Python中的嵌套类

12 投票
2 回答
29003 浏览
提问于 2025-04-17 09:46

Python中处理类(包括嵌套类等)看起来并不简单,真让人惊讶!最近我遇到了一个问题,花了好几个小时(尝试、搜索……)都没有找到解决办法。我看了大部分相关的StackOverflow链接,但没有一个能指出我这里遇到的问题!

#------------------------------------
class A:
    def __init__(self):
        self.a = 'a'
        print self.a

class B(A):
    def __init__(self):
        self.b = 'b'
        A.a = 'a_b'
        print self.b, A.a
#------------------------------------
class C:
    class A:
        def __init__(self):
            self.a = 'a'
            print self.a

    class B(A):
        def __init__(self):
            self.b = 'b'
            A.a = 'a_b'
            print self.b, A.a
#------------------------------------
#------------------------------------
>>> c1 = A()
a
>>> c1.a
'a'
>>> c2 = B()
b 
>>> c2.a, c2.b
('a_b', 'b')
>>> c3 = C()
>>> c4 = c3.A()
a
>>> c4.a
'a'
>>> c5 = c3.B()
b a_b
>>> c5.b
'b'
>>> c5.a
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: B instance has no attribute 'a'

代码中问题出在哪里? 还有 在这两种情况下,似乎当B(A)被初始化时,A()并没有被初始化。这个问题的解决办法是什么呢?注意,A.__init__()在B()的__init__()中调用是无效的!

更新:

class Geometry:
    class Curve:
        def __init__(self,c=1):
            self.c = c                          #curvature parameter
            print 'Curvature %g'%self.c
            pass                                #some codes

    class Line(Curve):
        def __init__(self):
            Geometry.Curve.__init__(self,0)     #the key point
            pass                                #some codes

g = Geometry()
C = g.Curve(0.5)
L = g.Line()

这导致了:

Curvature 0.5
Curvature 0

这是我一直在寻找的结果。

2 个回答

1

嵌套类看起来不太像Python的风格,即使把它当作工厂来用也是如此。不过,来回答你的问题:其实并没有c5.a(C.B的实例)。在C.B的初始化方法里,你给类C.A添加了一个属性a,但并没有给C.B添加!类A在实例化时已经有了属性a,但类B的对象(甚至类本身)并没有这个属性!

你还要记住,__init__并不是像C++或Java那样的构造函数!在Python中,真正的构造函数是__new____init__只是用来初始化类的实例!

class A:
    c = 'class-attribute'
    def __init__(self):
        self.i = 'instance-attribute'

所以在这个例子中,c是一个类属性,而i是实例的属性。

更有趣的是,你试图在子类实例化的时候给基类添加一个属性。这样做并不会得到一个“延迟”的继承属性。你只是给类A添加了一个额外的属性,这让我很惊讶它居然能工作。我猜你是在用Python 3.x吧?

这种行为的原因?我想这和Python的一个特点有关,就是在Python中定义是会被执行的(据我所知)。

同样的原因也适用于:

def method(lst = []):

这几乎总是个坏主意。默认参数在定义的时候就被绑定了,每次调用这个方法时不会生成一个新的列表对象,而是重用同一个列表对象。

10

在一个方法里执行的代码只在这个方法的局部范围内运行。如果你想访问一个不在这个范围内的对象,Python会去全局或模块的范围里找,而不是在类的范围或任何封闭类的范围里找!

这意味着:

A.a = 'a_b'

C.B.__init__ 里面设置的类属性其实是全局的 A 类的属性,而不是你可能想要的 C.A。如果你想要设置 C.A,你需要这样做:

C.A.a = 'a_b'

另外,如果你在子类中重写了父类的方法,Python不会自动调用父类的方法,你得自己去调用。

根据作用域的规则,如果你想在 C.B.__init__ 里面调用父类的 __init__ 方法,它的写法应该是这样的:

C.A.__init__(self)

而不是这样的:

A.__init__(self)

这可能就是你之前尝试的方式。

撰写回答