令人费解的作用域行为

Posted

技术标签:

【中文标题】令人费解的作用域行为【英文标题】:Puzzling scope behaviour 【发布时间】:2012-02-22 12:07:26 【问题描述】:

我似乎无法理解这里发生了什么:

class testclass: 

    def __init__(self): 
        print "new instance" 
    myList=[] 

if __name__ == "__main__":  

    inst1=testclass() 
    inst1.myList.append("wrong") 

    inst2=testclass() 
    inst2.myList.append("behaviour") 

    print "I get the",inst2.myList

输出是:

new instance
new instance
I get the ['wrong', 'behaviour']

我原以为 inst1 中的列表对 inst2 中的列表一无所知,但不知何故它看起来像是 myList 的范围超越类的实例化。 我觉得这非常令人不安和令人费解,还是我在这里遗漏了什么?

谢谢!

【问题讨论】:

【参考方案1】:

你定义myList的方式是一个类属性。

您正在寻找的行为是对象属性之一:

class testclass:
    def __init__(self): 
        print "new instance"
        self.myList = []

让我们试试吧:

>>> t1 = testclass()
new instance
>>> t2 = testclass()
new instance
>>> t1.myList.append(1)
>>> t2.myList.append(2)
>>> t1.myList
[1]
>>> t2.myList
[2]

如果您对类属性感兴趣,请查看Class documentation。由于 Python 中的类也是对象,就像(几乎)Python 中的所有东西一样,它们可以有自己的属性。

【讨论】:

【参考方案2】:

您在类中声明myList 的方式使其成为class 属性。如果您打算拥有一个 instance 属性,请像这样声明它,它将具有预期的行为:

class testclass:
    def __init__(self): 
        print "new instance" 
        self.myList=[]

【讨论】:

【参考方案3】:

是的,因为这就是类属性的用途。如果你想要一个实例变量,你需要在实例本身上声明它——通常在方法中使用self

【讨论】:

【参考方案4】:

myListclass 实例化时初始化,因为它是在类的主体中声明的,而不是在 object 实例化时。

这些属性然后与实例共享,直到在实例上创建同名变量。

因此,在您的情况下,您使用每个对象来访问相同的 myList 对象(并向其附加一个值)。

【讨论】:

【参考方案5】:
class testclass:

    def __init__(self):
        self.myList=[]
        print "new instance"

【讨论】:

【参考方案6】:

如果你想让 myList 成为一个实例变量,你应该在 init 函数中定义 self.myList。然后你应该得到你期望的行为。正如你现在所拥有的,我认为 myList 是一个类变量,将由该类的所有实例共享。

【讨论】:

它只会在对象分配之前共享。 不确定我是否理解您的评论。类变量不是总是在所有实例之间共享吗?如果您将 myList 定义为类变量和实例变量,它们仍然是不同的,并且对一个变量的赋值不会影响另一个变量。我错过了什么吗? 这是我的观点。如果你给实例上的变量赋值,你就不能再使用那个实例来访问类变量(除非,也许你删除了实例变量)。 是的,但您始终可以使用类名获取类变量。它还在那里。它仍然是共享的。 我不确定您认为它在何种意义上与无法访问它的对象共享。

以上是关于令人费解的作用域行为的主要内容,如果未能解决你的问题,请参考以下文章

JS作用域面试题总结

执行环境 作用域 作用域链 闭包的理解

js作用域

AngularJS中的控制器和作用域

es6记录之一——块级作用域与函数声明

块内声明函数