我想知道从嵌套子类访问父变量的最佳方法是什么,目前我正在使用装饰器.
那是唯一/最好的方法吗?
我不想直接访问父变量(例如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,并且显然不能包含对多个外部类的引用.当然,您可以编写元类来处理此问题(例如,通过自动创建指定序列化器的子类(如果已经具有外部属性的话)).