从Python中的嵌套子类访问父变量

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

那是唯一/最好的方法吗?

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

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

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

显然,这是一个琐碎的示例,它错过了所有真实的逻辑,因此许多类似乎是空的,但确实是必需的.

解决方法:

仅供参考,嵌套类时使用的公认术语是内部/外部,而不是父/子或父/子类.父/子或父/子关系是指继承.因为不涉及子类,所以这会使装饰器的名称,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的禅宗说“显性胜于隐式”,所以说西红柿,番茄.

您甚至可以编写元类,以便它对外部类进行内部检查,并将对该类的引用放入每个内部类中,而不管其名称如何.

顺便说一句,执行此操作的一个陷阱是所有模型类都必须继承SerialiserBase.如果您的班级用户只想要默认的序列化程序,则不能只在其类定义中编写Serialiser = SerialiserBase,而是必须编写类Serialiser(SerialiserBase):pass.这是因为只有一个SerialiserBase,并且显然不能包含对多个外部类的引用.当然,您可以编写元类来处理此问题(例如,通过自动创建指定序列化器的子类(如果已经具有外部属性的话)).

上一篇:Svelte 自定义组件属性统一设置与全部获取


下一篇:PHP嵌套菜单安全性问题