从具有自引用的实例内部访问类变量时会发生什么?

时间:2013-11-30 09:58:37

标签: python inheritance

我的一位同事写了类似的代码:

class A(object):
    foo = "bar"


class B(A):
    def baz(self):
        print self.foo

反对我个人的信念,这有效!我来自一个主要的Java背景,这伤害了我的眼睛......就个人而言,我会这样写:

class A(object):
    foo = "bar"


class B(A):
    def baz(self):
        print A.foo  # or dynamically determine the superclass.

据我所知,在Python中,变量名通常与“标签”进行比较。但这仍然在我的嘴里留下酸味。编写这样的代码有什么意义?这真是个坏主意吗?可能出现问题吗?

我能想象的唯一的“坏”事情是,在类层次结构的深层,实例变量可能会影响类变量......所以,你可以说它是......好吗?< / p>

4 个答案:

答案 0 :(得分:5)

你基本上可以做到这两点。

如果您的班级只有一个家长,您可以直接使用名称引用该变量。

class A(object):
    foo = "bar"


class B(A):
    def baz(self):
        print self.foo  

如果您使用多

,您所做的事情是有意义的
class A(object):
    foo = "bar"

class A2(object):
    foo = "bar 2"

class B(A, A2):
    def baz(self):
        #print foo # would throw NameError: global name 'foo' is not defined
        #print self.foo # prints "bar"
        print A.foo # prints "bar"
        print A2.foo # prints "bar 2"  

编辑: 如果我们忽略Java没有多重继承的事实,我认为它的行为方式类似。

public class A {
    String foo = "bar";
}

public class B extends A {

    public void baz() {
        System.out.println(this.foo);
    }

}
public static void main(String[] args) {
    B b = new B();
    b.baz(); // prints "bar"
}

唯一的区别是,在Java中,this.foosuper.foofoo都可以访问,而在Python中,您可以使用self.foo或{{1} },但不是<superclass>.foo

答案 1 :(得分:3)

嗯,首先,Python不是Java。有些事情是不同的。

根据Python的语义,类中的名称解析必须以这种方式工作。否则就无法从实例调用方法,因为方法也是类属性。

你是对的,其他地方的实例变量可能会影响类变量。但在我看来,这是一个功能,而不是一个错误。如果你真的想确定你总是访问类变量,你可以self.__class__.foo,但我不认为有任何需要。

答案 2 :(得分:0)

这是一个复杂的问题。您的两个代码示例的行为略有不同。

在您的同事的实施中,B的实例可能拥有自己的foo值。上面代码中没有任何内容可以建立一个,但您可以轻松地执行此操作:

example_B = B()
example_B.foo = 'foobar'

然后example_B.baz()会返回'foobar'

如果使用您的版本实现,example_B.baz()将不会检查实例的值。相反,它会返回'bar',无论example_B上设置了什么。

在实践中,您通常应该在设计类时告诉您名称是应该引用特定于实例的信息还是引用特定于类的信息。只应在类级别声明特定于类的信息。

有些人使用类级声明作为快捷方式,以确保某个类的所有实例都可以使用某个值,即使它们没有设置它,但我发现这通常会导致混淆,因为它们声明了可变变量作为“默认值”:

class BadExample(object):
    accidentally_shared_value = []

相反,您通常应在__init__中声明特定于实例的值:

class BetterExample(object):
    def __init__(self):
        self.unshared_value = []

当误解什么是类属性而不是实例属性时,意外共享可变值是可能出错的主要情况。

答案 3 :(得分:0)

  
    

我能想象的唯一“坏”的事情是,在类层次结构的深层,实例变量可能会影响类变量

  

实际上可能没有任何深层次结构。

class TestClass(object):
    var = 'foo'
    def __init__(self):
        self.var = 'bar'

x = TestClass()
print x.var
>>> 'bar'
del x.var
print x.var
>>>> 'foo'

但它在Python中没问题。