1

我对 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()

脚注:如果我将对全局变量selected2的第一个引用移动到类定义之前的行而不是之后的行,则 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'}

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

4

3 回答 3

2

global你认为的也不行。在这两种情况下chosenchosen2都是变量,而不是全局变量。

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

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

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

无论如何,将变量声明为 asglobal并不意味着超出我当前的范围。相反,它意味着在模块范围内,因此始终在您的函数、类和方法定义之外。

于 2012-09-11T16:39:11.003 回答
0

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

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

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

于 2012-09-11T16:38:50.247 回答
0

你不需要在global这里使用。在您的示例中,chosenchosen2是类属性。代替:

global chosen
chosen = self.choice

你只需写:

self.chosen = self.choice

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

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

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

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

于 2012-09-11T16:39:48.297 回答