Python-为什么在方法中未定义此类变量?


问题内容

我有一个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

在“ open”和“
on_close”行上打印打开/关闭连接的行。我在类中定义了它,为什么不在范围内。另外,我已经读到使用全局变量是不好的,但是我没有找到解决这个问题的方法。有人可以指出我该怎么做吗?谢谢。


问题答案:

在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将查看类selfSocketHandler。这个对象
确实
有一个currentid值,所以阅读的结果self.currentid将是0,不管是不是你以前运行openSocketHandler

如果要currentid在每个实例中将as作为实例变量存储SocketHandler,则其中的行open必须为:

self.currentid = global_counter

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