嵌套的Python类需要访问外部类的变量
我看到了一些“解决方案”,但每次的答案似乎都是“不要使用嵌套类,应该把类定义在外面,然后正常使用”。我不喜欢这个答案,因为它忽略了我选择嵌套类的主要原因,那就是为了有一个常量池(和基类相关),可以让所有创建的子类实例访问。
这里有个示例代码:
class ParentClass:
constant_pool = []
children = []
def __init__(self, stream):
self.constant_pool = ConstantPool(stream)
child_count = stream.read_ui16()
for i in range(0, child_count):
children.append(ChildClass(stream))
class ChildClass:
name = None
def __init__(self, stream):
idx = stream.read_ui16()
self.name = constant_pool[idx]
所有类都传入一个参数,这个参数是一个自定义的比特流类。我的想法是找到一个解决方案,这样我就不需要在父类中读取子类的idx值。所有子类的流读取应该在子类中完成。
这个例子过于简单了。常量池并不是我需要让所有子类都能访问的唯一变量。idx变量也不是从流读取器中读取的唯一内容。
在Python中这可能吗?难道没有办法访问父类的信息吗?
6 个回答
2
你可以通过父类的名字来访问它:
class ChildClass:
name = None
def __init__(self, stream):
idx = stream.read_ui16()
self.name = ParentClass.constant_pool[idx]
不过,我不太明白你想要达到什么目的。
7
这里其实不需要两个类。下面是你代码的一个更简洁的写法。
class ChildClass:
def __init__(self, stream):
idx = stream.read_ui16()
self.name = self.constant_pool[idx]
def makeChildren(stream):
ChildClass.constant_pool = ConstantPool(stream)
return [ChildClass(stream) for i in range(stream.read_ui16())]
欢迎来到Python编程。类在运行时是可以改变的。好好享受吧。
12
尽管我之前的评论有点让人觉得高高在上(可以这么说!),但其实有一些方法可以实现你想要的:一种不同的继承方式。这里有几个方法:
写一个装饰器,在类声明后立即检查这个类,找到内部类,并把外部类的属性复制到它们里面。
用元类做同样的事情。
这里介绍装饰器的方法,因为它是最简单直接的:
def matryoshka(cls):
# get types of classes
class classtypes:
pass
classtypes = (type, type(classtypes))
# get names of all public names in outer class
directory = [n for n in dir(cls) if not n.startswith("_")]
# get names of all non-callable attributes of outer class
attributes = [n for n in directory if not callable(getattr(cls, n))]
# get names of all inner classes
innerclasses = [n for n in directory if isinstance(getattr(cls, n), classtypes)]
# copy attributes from outer to inner classes (don't overwrite)
for c in innerclasses:
c = getattr(cls, c)
for a in attributes:
if not hasattr(c, a):
setattr(c, a, getattr(cls, a))
return cls
下面是一个简单的使用示例:
@matryoshka
class outer(object):
answer = 42
class inner(object):
def __call__(self):
print self.answer
outer.inner()() # 42
不过,我觉得其他答案中提到的一些想法可能对你更有帮助。