nested classes in Python
在python中处理类(嵌套等)并不容易,令人惊讶!我最近发现了以下问题,花了几个小时(尝试,搜索…)都没有成功。我阅读了大部分相关链接,但没有一个链接指出了这里提出的问题!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #------------------------------------ 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()似乎没有初始化。这个问题的解决方案是什么?注意,在b()的
更新:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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() |
结果是:
1 2 | Curvature 0.5 Curvature 0 |
我在找什么。
方法中执行的代码在该方法的本地范围内运行。如果您访问的对象不在此范围内,python将在全局/模块范围内查找它,而不在类范围或任何封闭类的范围内!
这意味着:
1 | A.a = 'a_b' |
在
1 | C.A.a = 'a_b' |
另外,如果您在子类中重写父方法,Python也不会调用它们。你得自己动手。
作用域规则意味着,如果要调用
1 | C.A.__init__(self) |
而不是这样:
1 | A.__init__(self) |
这可能是你尝试过的。
嵌套类看起来很不实用,即使被认为是工厂。但要回答你的问题:根本就没有C5.A(C.B的例子)。在C.B的init方法中,您向C.A类添加了一个属性A,但不添加到C.B!如果实例化,类A已经有了属性A!但是B类(甚至是B类)的对象没有!
您还必须记住,EDCOX1 0是不是像C++或Java那样的构造函数!python中的"真正的构造函数"是
1 2 3 4 | class A: c = 'class-attribute' def __init__(self): self.i = 'instance-attribute' |
所以在这个例子中,c是一个类属性,其中i是实例的一个属性。
更有趣的是,您试图在子类实例化时向基类添加一个属性。这样就不会得到"延迟"继承属性。您只需向类A添加一个额外的属性,这让我惊讶,甚至可以工作。我猜你用的是python 3.x?
这种行为的原因是什么?好吧,我想这和pythons的整洁特性有关,在python定义中执行(afaik)。
原因相同:
1 | def method(lst = []): |
几乎是个坏主意。deafult参数在定义时被绑定,每次调用该方法时都不会生成新的列表对象,而是重用同一个列表对象。