【问题标题】:Python Jython global variable usagePython Jython 全局变量的使用
【发布时间】:2012-09-11 16:34:02
【问题描述】:

我对 python 全局变量及其正确用法的理解存在问题。代码的第一位工作正常,第二位抛出异常“NameError:未定义全局名称'选择'”。我确定我在这里遗漏了一些简单的东西,但我看不到它是什么。

我想将一个侦听器与许多事件生成器中的每一个相关联,然后使用 getChoices 方法获取每个生成器所做选择的字典。

#Working code
class Listener1():
  chosen = "0"
  def __init__(self, choice):
    self.choice = choice

  def actionPerformed(self, event):            
    global chosen
    chosen = self.choice

  @staticmethod
  def getChoices():
    return chosen

e1 = Listener1('evt1')
e1.actionPerformed('abc')
print Listener1.getChoices()

失败代码

class Listener2():  
  chosen2 = {'a':-1}
  def __init__(self, choice):
    self.choice = choice
    global chosen2
    chosen2[self.choice] = 'unset'

  def actionPerformed(self, event):
    val = event
    global chosen2
    chosen2[self.choice] = val

  @staticmethod
  def getChoices():
    return chosen2

e2 = Listener2('evt2')
e2.actionPerformed('def')
e3 = Listener2('evt3')
e3.actionPerformed('ghi')
print Listener2.getChoices()

脚注: 如果我将对全局变量 chosen2 的第一个引用移动到类定义之前的行而不是之后的行,Listener2 类可以正常工作。

感谢下面的回答,代码改写为:

class Listener3():
  chosen3 = {}
  def __init__(self, choice):
    self.choice = choice
    if choice is not None:
        self.chosen3[self.choice] = 'unset'

  def actionPerformed(self, event):
    val = event
    self.chosen3[self.choice] = val

  def getChoices(self):
    return self.chosen3

e1 = Listener3('evt1')
e1.actionPerformed('abc')
e2 = Listener3('evt2')
e2.actionPerformed('def')
e3 = Listener3('evt3')

print Listener3(None).getChoices()
{'evt1': 'abc', 'evt2': 'def', 'evt3':'unset'}

除了更简单之外,现在可以完美运行。

【问题讨论】:

  • 问题已回答。感谢 Martijn、Matthew 和 heyden 没有对我粗鲁地忽略这个最明显的问题。

标签: python scope jython global


【解决方案1】:

global 都没有你认为的那样。在这两种情况下,chosen 和 chosen2 都是 类 变量,而不是全局变量。

但是当您将 chosen 声明为全局变量并分配给它时,python 很高兴地创建了一个全局变量(与 Listener1.chosen 分开)并存储了您的值。

但是对于chosen2,你没有分配任何东西给它;您试图将其视为 dict,但您没有通过赋值创建变量,因此失败。

您想改用self.chosen2;作为一个类变量,它将可用于Listener2 的所有实例。您也可以使用Listener2.chosen2。对于chosen,您可以使用Listener1.chosen 来引用它。 global 关键字可以完全删除。

无论如何,将变量声明为global 并不意味着在我当前的范围之外。它意味着在模块范围内,所以总是在你的函数、类和方法定义之外。

【讨论】:

    【解决方案2】:

    您可以重新创建相同的错误:

    global chosen2 #you're not creating chosen2, just saying you're about to create it, and when you do - it should be a global variable
    chosen2[2]=2 #chosen2 has yet to be defined so how can you set anything?
    

    您正在尝试设置尚未定义的对象two 的属性,首先您必须说明您希望它是列表还是字典(或其他)。

    global chosen2
    chosen2={}
    chosen2[2]=2
    

    如前所述,我认为您不希望这是全局的(因为您希望能够创建具有不同值的类实例 selected2!

    【讨论】:

      【解决方案3】:

      您无需在此处使用global。在您的示例中,chosen 和 chosen2 是类属性。而不是:

      global chosen
      chosen = self.choice
      

      你只需要写:

      self.chosen = self.choice
      

      当您在类之前定义chosen2 时,您实际上是在global 所指的范围内定义它。当您在类范围内定义它时,它是一个由所有实例共享的类属性。

      更新: 正如所指出的,直接分配给类属性不是您想要的,因为它会在实例上创建一个新属性,从而在类上屏蔽它。但是在您的 Listener2 示例中,这会很好:

      def actionPerformed(self, event):
          self.chosen[self.choice] = event
      

      在这里,您并没有覆盖.chosen,而是将一个项目添加到它所引用的字典中,因此该类将记录每个侦听器的最新事件。

      【讨论】:

      • self.chosen = self.choice 将创建一个实例变量,而不是 OP 想要的。每个实例都有自己的副本,而不是共享状态。
      • 我不完全相信他在这里想要一个类属性,但无论如何。
      • 这可能不是最好的主意,但我相当肯定这就是 OP 试图实现的目标。 :-)
      • 我希望指出正确的方向就足够了,但为了清楚起见,我现在已经更新了 :)
      猜你喜欢
      • 2019-07-24
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      • 1970-01-01
      • 2016-10-07
      • 2012-01-31
      • 1970-01-01
      相关资源
      最近更新 更多