从内部类访问外部类的方法

1 投票
2 回答
1763 浏览
提问于 2025-04-16 00:42

我想要一个Python类,这个类里面有一个嵌套的类,里面的类可以访问外面类的成员。我知道,普通的嵌套类其实不需要外面类有实例。我有一些代码,似乎能达到我想要的效果,我想听听大家对代码风格和可能出现的问题的看法。

代码:

class A():

    def __init__(self,x):
        self.x = x
        self.B = self.classBdef()

    def classBdef(self):
        parent = self

        class B():
            def out(self):
                print parent.x

        return B

输出:

>>> a = A(5)
>>> b = a.B()
>>> b.out()
5
>>> a.x = 7
>>> b.out()
7

所以,A类里面有一个B类,这个B类只能通过A类的实例来创建。然后,B类可以通过一个叫做parent的变量访问A类的所有成员。

2 个回答

0

我觉得你想做的事情不是个好主意。在Python中,“内部”类和它的“外部”类之间没有什么特别的关系,即使你把一个类定义在另一个类里面。你可以这样理解:

class A(object):
    class B(object):
        pass

和这样说是一样的:

class B(object): pass
class A(object): pass
A.B = B
del B

不过,确实可以通过把你的“内部”类变成一个描述符,并在它的元类上定义__get__(),来实现你所描述的功能。但我不推荐这样做——这太复杂了,而且收益不大。

class ParentBindingType(type):
    def __get__(cls, inst, instcls):
        return type(cls.__name__, (cls,), {'parent': inst})
    def __repr__(cls):
        return "<class '%s.%s' parent=%r>" % (cls.__module__, 
            cls.__name__, getattr(cls, 'parent', None))

class B(object):
    __metaclass__ = ParentBindingType
    def out(self):
        print self.parent.x

class A(object):
    _B = B
    def __init__(self,x):
        self.x = x
        self.B = self._B

a = A(5)
print a.B
b = a.B()
b.out()
a.x = 7
b.out()

打印结果:

<class '__main__.B' parent=<__main__.A object at 0x85c90>>
5
7
2

我觉得这个看起来不太好。classBdef 是一个类工厂方法。通常情况下(而且很少用到),你会用它来创建自定义类,比如说一个有自定义父类的类:

def class_factory(superclass):
    class CustomClass(superclass):
        def custom_method(self):
            pass
    return CustomClass

但是你的构造方式并没有利用到这种自定义。实际上,它把 A 的东西放到了 B 里,并且把它们紧密地耦合在一起。如果 B 需要知道某个 A 的变量,那就应该通过方法调用并传递参数,或者在创建 B 对象的时候传入 A 对象的引用。

除非你有特定的理由或者需要解决的问题,否则直接做一个普通的工厂方法,在 A 中返回一个 B 对象会更简单、更清晰,而不是像 b = a.B() 这样的写法。

class B(object):
    def __init__(self, a):
        self.a = a

    def out(self):
        print self.a.x

class A(object):
    def __init__(self,x):
        self.x = x

    def create_b(self):
        return B(self)

a = A()
b = a.create_b()
b.out()

撰写回答