Folder Structure
We start from the structure, sqs_client
folder contains a utility class SqsClient
in __init__.py
which I have written in the past.

Originally all functions are written within a class defined in __init__.py
. It causes mental fatigue when there is a bunch of functions but to only one of them we want to focus.
It also violates the separation of concerns principle for each single .py
file (as a module) when all functionality are written in just a single file.
You may also notice I have an underscore in _listen.py
. As in other languages this notation has something to do with privateness. However:
Naming Convention --- Can we Make Class Methods Private?
In python
there is no concept of private methods, the best you can do is to use name mangling as in:
class A: def __some_method(self): pass
But users can still get access to it by a = A()
and a._A__some_method()
.
Worse still, functions named with double underscored as prefix cannot be imported by any other files. This makes our approach of decomposing a class impossible (as we shall see).
A single underscore _
is enough to indicate a function should just be used internally (you can inspect it form other built-in modules in python like os
). In IDEs, these methods will be sorted at the bottom in auto-completion.
Implementation of Code Separation
As usual our __init__.py
will be the entry point of our class and:
# __init__.py class SqsClient: def __init__(self,...): self.sqs_client = ... # we remove the following function and import it from send_message.py # def send_message(self, message="n/a"): # self.sqs_client.send_message(MessageBody=message) from ._listen import _listen from .send_message import send_message from .send_test_message import send_test_message from .start_listening_test_message import start_listening_test_message from .add_receive_message_handler import add_receive_message_handler from .start_listening import start_listening
And we take send_message.py
as an example:
# send_message.py def send_message(self, message="n/a"): self.sqs_client.send_message(MessageBody=message)
As we can see:
- We can copy and paste the methods written in
__init__.py
directly to another file without any modification of code (this make any refactoring rather simple!). - In separated file we can still get access to attributes assigned to
self
.
When we init an instance by sqs_client = SqsClient()
, we get access to all methods! We can run something like
sqs_client.send_message(message="123") sqs_client.start_listening() # ... etc
and our __init__.py
now just plays the role as an entry point.