Python中的嵌套类

12
处理类(嵌套等)在Python中看起来并不容易,令人惊讶!最近出现了以下问题,尝试了几个小时(尝试、搜索...),但都没有成功。我阅读了大多数相关链接,但没有一个指出了这里提出的问题!
#------------------------------------
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()的__init__() 内调用A.__init__()不起作用! 更新:

class Geometry:
    class Curve:
        def __init__(self,c = 1):
            self.c = c              #曲率参数
            print'Curvature%g'%self.c
            pass                    #一些代码
class Line(Curve): def __init__(self): Geometry.Curve.__init__(self,0)#关键点 pass #一些代码
g = Geometry()
C = g.Curve(0.5) L = g.Line()

这将结果输出:

曲率 0.5
曲率 0

这正是我要寻找的内容。


3
"A.init()"在"B()的__init__()"内部被调用是无效的!有图为证。" - Ignacio Vazquez-Abrams
同上,你在B.__init__()中调用A.__init__()是什么样子的? - soulcheck
@IgnacioVazquez-Abrams,现在问题的解决方案已经找到了。仅仅几个小时就解决了,太好了。您可以在问题的更新部分找到您的观点。 - Developer
@soulcheck,请看我上面对Ignacio Vazquez-Abrams的评论。 - Developer
2
@Supporter,如果您创建一个名为“geometry”的模块,而不是外部Geometry类,那将会简单得多。这样可以确保完全相同的分组,但不会出现嵌套类的复杂性:import geometry as g``c = g.Curve(0.5) l = g.Line() - Duncan
2个回答

10

在方法中执行的代码会在该方法的本地作用域中运行。如果您访问不在此作用域中的对象,则Python将在全局/模块作用域中查找该对象,而不是在类作用域或任何封闭类的作用域中查找!

这意味着:

A.a = 'a_b'

C.B.__init__ 中,将设置全局类 A 的类属性,而不是您可能想要的 C.A。为此,您需要执行以下操作:

C.A.a = 'a_b'

此外,如果在子类中覆盖了父类的方法,Python不会调用父类方法。您需要自己去实现调用。
作用域规则意味着如果您想要在C.B.__init__中调用父类的__init__方法,它应该像这样:
C.A.__init__(self)

而不是这样:
A.__init__(self)

这可能是你已经尝试过的。


谢谢。我通过你提供的“作用域规则”的关键点解决了问题。完整的解决方案已经添加为更新。 - Developer

1

嵌套类似乎不太符合Python的风格,即使考虑到它们作为工厂的角色。但是回答你的问题:C.B的实例中根本没有c5.a。在C.B的init方法中,你向类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 = []):

几乎总是不好的想法。默认参数在定义时绑定,每次调用方法时都不会生成新的列表对象,而是重用相同的列表对象。


1
感谢您的回答。正如问题的更新部分所示,有时嵌套类可以使编程更加结构化和易于处理。 - Developer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接