简体   繁体   English

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

[英]What happens when you access a class-variable from inside an instance with a self-reference?

One of my colleagues wrote a code similar to this: 我的一位同事写了一个类似的代码:

class A(object):
    foo = "bar"


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

and against my personal belief, this worked! 并且违背我的个人信仰,这很有效! I come from a mainly Java background, and this hurts my eyes... Personally, I would have written it like this: 我来自一个主要的Java背景,这伤害了我的眼睛......就个人而言,我会这样写:

class A(object):
    foo = "bar"


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

I understand, that in Python variable names are often compared to "labels". 我理解,在Python中,变量名通常与“标签”进行比较。 But this still leaves a sour taste in my mouth. 但这仍然在我的嘴里留下酸味。 What are the implications of writing code like this? 编写这样的代码有什么意义? Is it really a bad idea? 这真是个坏主意吗? Can something go wrong? 可能会出错吗?

The only "bad" thing I can imagine is that deeper down the class hierarchy, an instance variable may shadow the class variable... so, you could says it's... okayish? 我可以想象的唯一“坏”的事情是,在类层次结构的更深处,一个实例变量可能会影响类变量......所以,你可以说它是......好吗?

You can basically do both. 你基本上可以做到这两点。

If your class has just one parent, you can reference the variable directly with the name. 如果您的类只有一个父级,则可以直接使用名称引用该变量。

class A(object):
    foo = "bar"


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

What you have done make sense if you use multi 如果你使用multi,你所做的就有意义了

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"  

EDIT: If we ignore that fact that Java doesn't have multiple inheritance, I think it behaves in the similar way. 编辑:如果我们忽略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"
}

The only difference is that in Java it is accessible with this.foo , super.foo but also foo , while in Python you can just use self.foo or <superclass>.foo , but not foo 唯一的区别是在Java中可以使用this.foosuper.foo以及foo访问它,而在Python中你可以使用self.foo<superclass>.foo ,但不是foo

Well, first of all, Python is not Java. 嗯,首先,Python不是Java。 Some things are just different. 有些事情只是不同。

According to the semantics of Python, name resolution in classes has to work that way. 根据Python的语义,类中的名称解析必须以这种方式工作。 Otherwise there'd be no way of calling methods from an instance, since methods are also class attributes. 否则,无法从实例调用方法,因为方法也是类属性。

You're right that an instance variable elsewhere could shadow the class variable. 你是对的,其他地方的实例变量可能会影响类变量。 But in my opinion, that's a feature, not a bug. 但在我看来,这是一个功能,而不是一个错误。 If you really wanted to be sure you were always accessing the class variable, you could do self.__class__.foo , but I don't think there's any need. 如果你真的想确定你总是访问类变量,你可以做self.__class__.foo ,但我认为没有任何需要。

This is kind of a complicated question. 这是一个复杂的问题。 Your two code examples have slightly different behavior. 您的两个代码示例的行为略有不同。

In your colleague's implementation, it is possible for an instance of B to have its own value of foo . 在您的同事的实现中, B的实例可能具有其自己的foo值。 Nothing in the above code would establish one, but you could easily do so: 上面的代码中没有任何内容可以建立一个,但您可以轻松地这样做:

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

Then example_B.baz() would return 'foobar' . 然后example_B.baz()将返回'foobar'

If implemented with your version, example_B.baz() would not check the instance's value. 如果使用您的版本实现, example_B.baz()将不检查实例的值。 Instead, it would return 'bar' , regardless of what had been set on example_B . 相反,它会返回'bar' ,无论在example_B设置了什么。

In practice, you should usually be able to tell when designing your class whether a name should refer to instance-specific information or to class-specific information. 在实践中,您通常应该在设计类时告诉您名称是应该引用特定于实例的信息还是引用特定于类的信息。 Only class-specific information should be declared at the class level. 只应在类级别声明特定于类的信息。

Some people use class-level declarations as a shortcut to ensure that a value is available on all instances of a class even if they don't set it, but I find that this usually leads to confusion as soon as they declare a mutable variable as a "default value": 有些人使用类级声明作为快捷方式来确保某个类的所有实例都有值,即使它们没有设置它,但我发现这通常会导致混淆,只要它们声明一个可变变量为一个“默认值”:

class BadExample(object):
    accidentally_shared_value = []

Instead, you should generally declare instance-specific values in __init__ : 相反,您通常应该在__init__声明特定于实例的值:

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

Accidentally sharing mutable values is the main situation that can go wrong when misunderstanding what's a class attribute versus what's an instance attribute. 意外地共享可变值是在误解什么是类属性与什么是实例属性时可能出错的主要情况。

The only "bad" thing I can imagine is that deeper down the class hierarchy, an instance variable may shadow the class variable 我可以想象的唯一“坏”的事情是,在类层次结构的深层,实例变量可能会影响类变量

It's actually possible without any deep hierarchy at all. 它实际上可能没有任何深层次结构。

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

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

But it's okay in Python. 但它在Python中没问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当您在继承的类中声明方法时不传递“自我”时会发生什么 - what happens when you don't pass 'self' while declaring a method inside a inherited class 将自引用传递给实例化的 class - Passing a self-reference down to an instantiated class 如何自引用Python中的类? - how to self-reference a class in Python? 在这种情况下,变量被自身覆盖时会发生什么? - What happens to the variable in this case when it is overwritten with self? 当我在 class 方法中初始化像 m1 这样的变量时不使用“self”键时到底发生了什么。 m1 是本地变量,object 还是 class 变量? - What exactly happens when i don't use "self" key while initialising a variable like m1 inside a class method. m1 is local,object or class variable? 当我从Python中继承实例而不是类时会发生什么? - What happens when I inherit from an instance instead of a class in Python? 当您固有于模块而不是Python中的类时,会发生什么? - What happens when you inherent from a module instead of a class in Python? 字典或替代品中的自我参考 - Self-reference in dictionary or alternative 如何防止子级采用父级变量更改 - How to prevent Parent class-variable changes to be adopted by Child class 是否可以在Python attr中自引用类型 - Is it possible to self-reference type in Python attr
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM