Python中的嵌套类
在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 个回答
嵌套类看起来不太像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 = []):
这几乎总是个坏主意。默认参数在定义的时候就被绑定了,每次调用这个方法时不会生成一个新的列表对象,而是重用同一个列表对象。
在一个方法里执行的代码只在这个方法的局部范围内运行。如果你想访问一个不在这个范围内的对象,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)
这可能就是你之前尝试的方式。