4

我想知道从嵌套子类访问父变量的最佳方法是什么,目前我正在使用装饰器。

这是唯一/最好的方法???

我不想直接访问父变量(例如 ComponentModel.origin (见下文)),因为这需要“配置”文件中的更多代码,所以我想知道是否可以在有问题的子类继承自哪个类?

我当前解决方案的简单示例:

# defined in a big library somewhere:
class LibrarySerialiser(object):
    pass

# defined in my module:
class ModelBase:
    pass

class SerialiserBase(LibrarySerialiser):
    def __init__(self, *args, **kwargs):
        # could i some how get hold of origin here without the decorator?
        print self.origin
        super(SerialiserBase, self).__init__(*args, **kwargs)

def setsubclasses(cls):
    cls.Serialiser.origin = cls.origin
    return cls

# written by "the user" for the particular application as the
# configuration of the module above:

@setsubclasses
class ComponentModel(ModelBase):
    origin = 'supermarket'

    class Serialiser(SerialiserBase):
        pass


ser = ComponentModel.Serialiser()

这显然是一个简单的例子,它错过了所有真正的逻辑,因此许多类看起来是无效的,但确实是必要的。

4

1 回答 1

3

仅供参考,嵌套类时使用的公认术语是内部/外部,而不是父/子或超/子类。父/子或超级/子关系是指继承。这让你的装饰器的名字 ,setsubclasses令人困惑,因为没有涉及到子类!

您在这里所做的不同寻常的事情是将类用作名称空间而不实例化它。通常你会实例化你的ComponentModel并且在那个时候,给你的Serialiser内部类一个来自其外部类的属性的副本是微不足道的。例如:

class ModelBase(object):
    def __init__(self):
        self.Serialiser.origin = self.origin

# ... then

cm  = ComponentModel()
ser = cm.Serialiser()

更好的是,让外部类实例化内部类并将其传递给外部类;然后它可以在需要时获取它自己想要的任何属性:

class ModelBase(object):
    def __init__(self, *args, **kwargs):
        serialiser = self.Serialiser(self, *args, **kwargs)

class SerialiserBase(LibrarySerialiser):
    def __init__(self, outer, *args, **kwargs):
        self.outer = outer
        print self.outer.origin
        super(SerialiserBase, self).__init__(*args, **kwargs)

# ...

cm  = ComponentModel()
ser = cm.serialiser

但是,如果您坚持在不实例化外部类的情况下能够获取该属性,则可以使用元类来设置该属性:

class PropagateOuter(type):
    def __init__(cls, name, bases, dct):
        type.__init__(cls, name, bases, dct)
        if "Serialiser" in dct:
            cls.Serialiser.outer = cls

class ModelBase(object):
    __metaclass__ = PropagateOuter

# Python 3 version of the above
# class ModelBase(metaclass=PropagateOuter):
#     pass

class SerialiserBase(LibrarySerialiser):
    def __init__(self, *args, **kwargs):
        print self.outer.origin
        super(SerialiserBase, self).__init__(*args, **kwargs)

class ComponentModel(ModelBase):
    origin = 'supermarket'

    class Serialiser(SerialiserBase):
        pass

ser = ComponentModel.Serialiser()

这并没有做你的装饰器没有做的任何事情,但是用户通过继承自动获得它,而不必手动指定它。Python 的禅宗说“显式胜于隐式”,所以番茄,番茄。

您甚至可以编写元类,以便它内省外部类并将对该类的引用放入每个内部类中,而不管它们的名称如何。

顺便说一句,你这样做的一个陷阱是你所有的模型类都必须subclass SerialiserBase。如果您的类的用户只想要默认的序列化程序,他们不能只写Serialiser = SerialiserBase在他们的类定义中,他们必须class Serialiser(SerialiserBase): pass. 这是因为只有一个SerialiserBase,而且它显然不能包含对多个外部类的引用。当然,您可以编写您的元类来处理这个问题(例如,如果它已经有一个outer属性,则通过自动创建指定序列化程序的子类)。

于 2013-09-14T15:04:18.007 回答