【问题标题】:Python - Why is this class variable not defined in the method?Python - 为什么这个类变量没有在方法中定义?
【发布时间】:2012-10-08 22:03:01
【问题描述】:

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


    【解决方案1】:

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

    一行中的currentid 之类的裸名:

    del connections[currentid]
    

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

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

    这样就可以了:

    del connections[self.currentid]
    

    但是,我认为您的其余代码也没有按照您的想法进行。 open 方法中的这一行:

    currentid = global_counter
    

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

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

    on_close 方法中读取self.currentid 将无法在对象self 中找到currentid 属性,因此Python 将查看self 的类,即SocketHandler。该对象确实具有currentid 值,因此读取self.currentid 的结果将是0,无论您之前是否在该SocketHandler 上运行open。 p>

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

    self.currentid = global_counter
    

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 为什么这么多人赞成? -- 上面示例中的代码将不再因 NameError 而中断,但如果仅进行此替换,则会因严重的逻辑错误而中断。
      • @jsbueno:你什么意思?唯一被修改的其他变量是全局变量。
      • @Blender 您认为 OP 打算在 open 方法中使用与类属性同名的局部变量的可能性有多大?并始终使用on_close 方法del connections[0]
      • @Ben:对不起,我看了jsbueno的评论说脚本会出现解析错误,而不是运行时错误。
      • 是的,我想办法把 self.currentid 放在这两种方法中,一切都按计划运行。
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-31
        • 2012-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-05
        相关资源
        最近更新 更多