在另一个对象中传递对象的属性和方法

Passing attributes and methods of object inside another object

我正在 Python 3.9 中写一个 API。我将首先提供一个简化的示例,说明我正在处理的内容,下面的代码将从设计的角度对我试图实现的内容进行一些扩展。我刚刚开始涉足更复杂的设计和对象组合的事情,所以我尝试做的一些事情完全有可能是不可能的或不是最佳实践——我很想知道我可以改进什么。

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

secondary_module.py中:

class SecondaryClass:
    def secondary_method(pri_cls):
        print(pri_cls.attr1)
        print(pri_cls._attr2)

如您所见,我在 secondary_module.py 中定义了一个 class SecondaryClass 并使用它在 primary_module.py。从 API 的角度来看,我希望最终用户只能直接访问 PrimaryClass,永远不要让他们看到 SecondaryClass,即使它是在幕后使用的。唯一需要实例化 SecondaryClass 的时间是 运行ning PrimaryClass.primary_method() 和相关对象,因此没有 SecondaryClass 会 运行 作为独立对象的情况.但是,当运行使用此方法时,SecondaryClass 需要访问PrimaryClass 中包含的一些用户指定的数据。请记住 SecondaryClass(理论上)永远不会被最终用户直接访问,允许 SecondaryClass 查看 PrimaryClass 的某些属性的最佳方法是什么?在 SecondaryClass.secondary_method() 的定义中使用 duck typing 来授予它访问 PrimaryClass 的某些属性(public 和隐藏)的权限是否可以接受?或者有没有我没有想到的更好的解决方案?

不是很清楚,但我想这就是你想要的:

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)

要对 primary_module 的用户隐藏 SecondaryClass,请使用:

from secondary_module import SecondaryClass as _SecondaryClass

Hide external modules when importing a module (e.g. regarding code-completion)

如果不了解 classes 实际在做什么,就很难讨论这个问题。

就是说,让两个 class 相互依赖通常不是一个好主意,因为这往往会生成脆弱的代码: class 中的任何一个的变化都可能破坏 classes 以及任何依赖它们的人。

最好明确地传递 secondary_method 它需要的东西(即 secondary_method(self._attr2)),可能作为函数指针(例如 lambda: __private_method()lambda: self.attr1),通过 class 构造函数(即 __init__)或作为 secondary_method 的方法参数。这样,SecondaryClass 就不会具体依赖于 PrimaryClass,并且 secondary_methodSecondaryClass 的依赖性是明确的。

class PrimaryClass:
    def __init__(self, param1, param2):
        self.attr1 = param1
        self._attr2 = do_something(param2)

    def primary_method(self):
        # E.g. 1: Pass _attr2 via constructor
        sec_cls = SecondaryClass(self._attr2)
        # E.g. 2+3: Pass attr1 and _attr2 as method parameters
        sec_cls.secondary_method(
            lambda: self.attr1,
            lambda: __private_method(),
        )

    def __private_method(self):
        do_something_else()

class SecondaryClass:
    def __init__(self, attr2):
        self.attr2 = attr2

    def secondary_method(get_attr1, private_callback):
        print(self.attr2)    # <- _attr2, received from constructor
        print(get_attr1())  # <- Getting attr1 at execution time from lambda
        private_callback()    # <- Calling __private_method