14

我有一个 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”的行上,我打印我正在打开/关闭连接。我在课堂上定义的,为什么不在范围内。另外,我已经读过使用全局变量是不好的,但我没有看到解决这个问题的方法。有人可以指出我应该做什么吗?谢谢。

4

3 回答 3

17

在 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.currentidon_close方法将无法在对象中找到currentid属性self,因此 Python 将查看selfis的类SocketHandler。该对象确实有一个currentid值,因此读取的结果self.currentid将是0,无论您之前是否在该对象上运行openSocketHandler

如果您打算将 存储currentid为每个实例变量SocketHandler,那么 in 行open需要是:

self.currentid = global_counter

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

于 2012-10-08T22:21:44.177 回答
5

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

于 2012-10-08T22:04:07.803 回答
1

currentid是实例属性,所以使用self.currentid代替currentid

def on_close(self):
        global connections
        print "WebSocket " + str(self.currentid) + " closed"
        del connections[self.currentid]
于 2012-10-08T22:04:33.913 回答