嵌套的Python类需要访问外部类的变量

12 投票
6 回答
13824 浏览
提问于 2025-04-16 19:48

我看到了一些“解决方案”,但每次的答案似乎都是“不要使用嵌套类,应该把类定义在外面,然后正常使用”。我不喜欢这个答案,因为它忽略了我选择嵌套类的主要原因,那就是为了有一个常量池(和基类相关),可以让所有创建的子类实例访问。

这里有个示例代码:

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

尽管我之前的评论有点让人觉得高高在上(可以这么说!),但其实有一些方法可以实现你想要的:一种不同的继承方式。这里有几个方法:

  1. 写一个装饰器,在类声明后立即检查这个类,找到内部类,并把外部类的属性复制到它们里面。

  2. 用元类做同样的事情。

这里介绍装饰器的方法,因为它是最简单直接的:

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

不过,我觉得其他答案中提到的一些想法可能对你更有帮助。

撰写回答