覆盖LGB范围规则?

时间:2016-05-13 13:56:12

标签: python-3.x scope

我是Python的新手,同时拥有丰富的C和C ++经验。经常让我兴奋的事情之一是希望能够在函数中引用全局变量,如下所示:

# first_time needs to be referenced within foo, but could also
# be modified by a different function, or from the global scope,
# so I try to define it globally

first_time = True

def foo():
    if (first_time):
        first_time = False

foo()

Python给出了错误,我明白了我是如何违反LGB Rule

if (first_time):

UnboundLocalError: local variable 'first_time' referenced before assignment

更新:我找到了部分解决方案,但我不喜欢它:

def foo():
    global first_time
    if (first_time):
        first_time = False

first_time = True     
foo()

我不喜欢这个解决方案,我想在声明它的同一行初始化它,但Python似乎不允许我这样做。

此外,它不允许我在另一个函数中执行相同的操作:

def bar():
    global first_time
    if (first_time):
        first_time = False

有没有办法在函数之外声明和初始化它,以便可以通过多个函数检查和更新它?

2 个答案:

答案 0 :(得分:3)

你误解了Python global关键字的作用。

它不声明全局变量。相反,它确保 - 在当前代码块中 - 在全局范围而不是在本地范围内搜索提供的标识符。 (documentation无法解释这种区别)

例如,如果global实际上在全局范围内声明了变量,则以下代码将起作用:

def bar():
    global foo
    foo = 1

print(foo)

但它产生了:

Traceback (most recent call last):
  File "./test.py", line 5, in <module>
    print(foo)
NameError: name 'foo' is not defined

由于global未声明变量,因此您需要注意两个问题:

  • 无法在声明时初始化变量,
  • 无法在多种方法中使用global foo

没有根据!如以下代码段所示:

foo = 5

def bar():
    global foo
    foo += 1

def baz():
    global foo
    foo += 10

bar()
baz()
bar()
print(foo)

正如预期的那样产生17

<强>更新

然而,总的来说,全球变量是不受欢迎的。根据具体情况,可能有更好的方法。

Python中一个鲜为人知的技巧是你可以在方法上放置属性(这是方法是对象的结果):

def bar():
    bar.foo += 1
bar.foo = 5

print(bar.foo)
bar()
print(bar.foo)

bar.foo = 1

哪个输出56

这样,foo不是全局的,它仅限于bar的命名空间,但仍可通过bar.foo全局访问!如果foo固有属于bar但需要全局访问,这是一个非常好的解决方案。

一个简单但更具体的例子,说明如何使用它:假设你有一个方法print(),如下所示:

def print(document, printer=None):
    printer = printer or print.printer
    printer.send(document)
    print.jobcount += 1 
print.printer = get_default_printer()
print.jobcount = 0

然后你可以:

  • 使用print(doc)
  • 将文档打印到默认打印机
  • 使用print(doc, printer=some_printer)
  • 打印到特定打印机
  • 使用print.printer = some_printer
  • 设置默认打印机
  • 使用print.jobcount
  • 查询打印文档的数量

实际上并没有为您的方法print()命名,因为这已经是一种内置方法; - )

这种方法可能最适合小事。如果它失控了,我更喜欢用类来封装这些东西,即使我只是使用静态方法:

class Print:
    printer = get_default_printer()
    jobcount = 0

    def print(document, printer=None):
        printer = printer or Print.printer
        printer.send(document)
        Print.jobcount += 1

所以你可以做Print.print(doc)Print.jobcount等等......

答案 1 :(得分:1)

可以从本地范围创建一个全局变量,虽然它被认为有点不合理:

def foo():
    if not 'first_time' in globals():
        globals()['first_time'] = True
    else:
        global first_time
    if (first_time):
        first_time = False

globals()是一个包含所有全局名称的字典(在shell中输入globals()是有用的)。你可以写信给它。如果是foo

>>> first_time
Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    first_time
NameError: name 'first_time' is not defined
>>> foo()
>>> first_time
False