在 Python ,令人惊讶的中处理类(嵌套等)并不容易!最近我出现了以下问题并花了几个小时(尝试,搜索......)但没有成功。我阅读了大部分SO相关链接,但没有一个指出这里提出的问题!
#------------------------------------ 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()的A.__init__()
内调用的术语__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
我在寻找什么。
答案 0 :(得分:7)
方法中执行的代码在该方法的本地范围内运行。如果您访问的对象不在此范围内,Python将在全局/模块范围内查找,在类范围中 NOT 或任何封闭类的范围!
这意味着:
A.a = 'a_b'
在C.B.__init__
内将设置全局A
类的class属性,而不是您想要的C.A
。为此你必须这样做:
C.A.a = 'a_b'
此外,如果在子类中覆盖它们,Python将不会调用父方法。你必须自己做。
范围规则意味着如果要在__init__
内调用父类的C.B.__init__
方法,则必须如下所示:
C.A.__init__(self)
而不是这样:
A.__init__(self)
这可能是你尝试过的。
答案 1 :(得分:1)
嵌套类看起来非常简单,即使被视为工厂。但回答你的问题:根本就没有c5.a(C.B的例子)。在C.B的init方法中,您将属性a添加到CLASS C.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定义为executed(AFAIK)的pythons整洁功能有关。
同样的原因:
def method(lst = []):
几乎是一个坏主意。 deafult参数在定义时被绑定,并且每次调用方法时都不会生成新的列表对象,而是重用相同的列表对象。