Search code examples
pythonobjectcomposition

Passing attributes and methods of object inside another object


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?


Solution

  • 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)