我有一个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”行上。我在类中定义了它,为什么不在范围内。另外,我已经读到使用全局变量是不好的,但是我没有找到解决这个问题的方法。有人可以指出我该怎么做吗?谢谢。

最佳答案

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

该行中的裸名,如currentid:

del connections[currentid]

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

要在Python中查找属性,您始终需要指定要在其中查找的对象。尽管查找协议(protocol)意味着对象不一定必须具有属性本身,但是对象本身不一定具有属性。属性查找将回退到您指定的对象的类(如果涉及继承,则返回基类)。

因此,这将工作:
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,读取open的结果将为SocketHandler

如果您打算将currentid作为实例变量存储在每个SocketHandler中,则open中的行将需要为:
self.currentid = global_counter

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

关于Python-为什么在方法中未定义此类变量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12790114/

10-09 08:51