I am writing an API in Python 3.9. I'll first provide a simplified example of what I'm working on and below the code will expand a bit on what I'm trying to implement from a design perspective. I just started getting into more complex design and object composition things, so it's entirely possible that some of what I'm trying to do is either not possible or not best practice - I'd be interested to know what I can improve.
In primary_module.py
:
from some_module import do_something
from secondary_module import SecondaryClass
class PrimaryClass:
def __init__(self, param1, param2):
self.attr1 = param1
self._attr2 = do_something(param2)
def primary_method(self):
sec_cls = SecondaryClass(PrimaryClass)
sec_cls.secondary_method()
In secondary_module.py
:
class SecondaryClass:
def secondary_method(pri_cls):
print(pri_cls.attr1)
print(pri_cls._attr2)
As you can see, I have one class SecondaryClass
defined in secondary_module.py
and am using that to compose a class called PrimaryClass
in primary_module.py
. From an API standpoint, I would like end users to only directly access PrimaryClass
and never let them see SecondaryClass
even though it is being used under the hood. The only time SecondaryClass
needs to be instantiated is when running PrimaryClass.primary_method()
and related objects, so there's no situation in which SecondaryClass
would run as a standalone object. However, when running this method, SecondaryClass
needs access to some of the user-specified data contained in PrimaryClass
. Keeping in mind that SecondaryClass
is (theoretically) never directly accessed by end users, what's the best way to allow SecondaryClass
to see certain attributes of PrimaryClass
? Is it acceptable to use duck typing in the definition of SecondaryClass.secondary_method()
to grant it access to certain attributes (both public and hidden) of PrimaryClass
? Or is there some better solution that I'm not thinking of?
It's not totally clear, but I think this is what you want:
class PrimaryClass:
def __init__(self, param1, param2):
self.attr1 = param1
self._attr2 = do_something(param2)
def primary_method(self):
sec_cls = SecondaryClass(self)
sec_cls.secondary_method()
def __private_method(self):
do_something_else()
class SecondaryClass:
def __init__(self, primary):
self.primary = primary
def secondary_method():
print(self.primary.attr1)
print(self.primary._attr2)
To hide SecondaryClass
from users of primary_module
, use:
from secondary_module import SecondaryClass as _SecondaryClass
See Hide external modules when importing a module (e.g. regarding code-completion)