Python - 为什么这个类变量没有在方法中定义?

时间:2012-10-08 22:03:01

标签: python variables scope

我有一个python应用程序,如下所示:

global_counter = 0
connections = {}

class SocketHandler():
    currentid = 0
    def open(self):
        global global_counter
        global connections
        currentid = global_counter
        global_counter += 1
        connections[currentid] = self
        print "WebSocket " + str(currentid) + " opened"

    def on_close(self):
        global connections
        print "WebSocket " + str(currentid) + " closed"
        del connections[currentid]

我收到了错误:

NameError: global name 'currentid' is not defined

在“打开”和“on_close”的行上,我打印我打开/关闭连接。我在课堂上定义了它,为什么不在范围内。另外,我已经读过使用全局变量很糟糕,但我没有看到解决方法。有人可以指出我应该做什么吗?感谢。

3 个答案:

答案 0 :(得分:9)

在Python中,您没有隐式访问方法内的属性。

行中的currentid这样的简称:

del connections[currentid]

在尝试全局模块范围之前,总是在本地函数范围中查找名称,然后在每个封闭的函数范围中查找(然后将内置函数作为最后的手段查看)。 currentid是一个类属性,在任何这些范围中都找不到。

要在Python中查找属性,始终需要指定要查看的对象。虽然查找协议意味着对象不一定必须具有属性本身;属性查找将回退到您指定的对象的类(以及基类,如果涉及继承)。

所以这会奏效:

del connections[self.currentid]

但是,我不认为你的其余代码正在做你认为的那样。 open方法中的这一行:

currentid = global_counter

未设置currentid对象的SocketHandler属性。分配给裸名称​​总是分配给局部变量,除非您明确声明它global(您似乎知道这一点,因为您已使用global关键字)。所以在open方法中,currentid是一个局部函数变量;它的值在open方法结束时丢失。

实际上,您的SocketHandler个对象根本没有currentid属性(除非您没有向我们展示更多代码)。将currentid = 0放在类块中并不会为所有SocketHandler个实例提供currentid属性。它为SocketHandler本身提供了属性currentid;这就像def open(self):块在类对象上创建open属性(存储函数),而不是在每个单独的实例上创建。

self.currentid方法中阅读on_close将无法在对象currentid中找到self属性,因此Python会查看self的类这是SocketHandler。该对象 的值为currentid,因此,无论您之前是否self.currentid,阅读0的结果都为openSocketHandler上。

如果您打算将currentid存储为每个SocketHandler中的实例变量,则open中的行必须为:

self.currentid = global_counter

这将分配给currentid引用的对象的self属性。然后,您还需要将方法中对currentid的所有其他引用更改为self.currentid

答案 1 :(得分:4)

currentid应为self.currentid,因为它是一个类变量。

答案 2 :(得分:0)

currentid是实例属性,因此请使用self.currentid代替currentid

def on_close(self):
        global connections
        print "WebSocket " + str(self.currentid) + " closed"
        del connections[self.currentid]