为什么 Python 中的函数可以在封闭范围内打印变量,但不能在赋值中使用它们? [英] Why can functions in Python print variables in enclosing scope but cannot use them in assignment?

查看:69
本文介绍了为什么 Python 中的函数可以在封闭范围内打印变量,但不能在赋值中使用它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我运行以下代码:

x = 1类增量:打印(x)x = x + 1打印(x)打印(x)

它打印:

121

好的,没问题,这正是我所期望的.如果我执行以下操作:

x = 1类增量:全球 x打印(x)x = x + 1打印(x)打印(x)

它打印:

122

也是我所期待的.没有问题.

现在,如果我开始创建一个增量函数,如下所示:

x = 1定义增量():打印(x)增量()

正如我所料,它打印了 1.我认为它这样做是因为它在其本地范围内找不到 x,所以它搜索其封闭范围并在那里找到 x.目前没有问题.

现在如果我这样做:

x = 1定义增量():打印(x)x = x + 1增量()

这在回溯中给了我以下错误:

<块引用>

UnboundLocalError:在赋值之前引用了局部变量x".

为什么 Python 在找不到 x 的值用于像我的 class Incr 那样的赋值时不只是搜索 x 的封闭空间代码>做了吗?请注意,我不是在问如何使此功能起作用.我知道如果我执行以下操作,该功能将起作用:

x = 1定义增量():全球 x打印(x)x = x + 1打印(x)增量()

这将正确打印:

12

正如我所料.我要问的是,当关键字 global 不存在时,为什么它不只是从封闭范围中拉出 x ,就像它在我上面的类中所做的那样.当解释器清楚地知道存在某些 x 时,为什么会觉得需要将其报告为 UnboundLocalError.由于该函数能够读取 x 处的值进行打印,我知道它具有 x 作为其封闭范围的一部分......那么为什么这不起作用喜欢课堂的例子吗?

为什么将 x 的值用于打印与将其值用于赋值如此不同?我就是不明白.

解决方案

类和函数不同,类内部的变量实际上是分配给类的命名空间作为属性,而函数内部的变量只是普通变量,不能可以在它之外访问.

函数内部的局部变量实际上是在函数第一次解析时决定的,python不会在全局范围内搜索它们,因为它知道你将它声明为局部变量.

因此,一旦 python 看到 x = x + 1(assignment) 并且没有为该变量声明 global ,那么 python 将不会在全局或其他范围.

<预><代码>>>>x = '外部'>>>定义函数():... x = 'inner' #x 现在是一个局部变量... 打印 x...>>>功能()内

常见问题:

<预><代码>>>>x = '外部'>>>定义函数():... print x #this 不会访问全局`x`... x = 'inner' #`x` 是一个局部变量... 打印 x...>>>功能()...UnboundLocalError:赋值前引用了局部变量x"

但是当您使用 global 语句时,python 会在 global 范围内查找该变量.

阅读:为什么当变量有值时我会收到 UnboundLocalError?

nonlocal:对于嵌套函数,您可以使用 py3.x 中的 nonlocal 语句来修改在封闭函数中声明的变量.

<小时>

但是类的工作方式不同,在类A中声明的变量x实际上变成了A.x:

<预><代码>>>>x = '外部'>>>A类:... x += 'inside' #使用全局`x`的值创建一个新的属性`A.x`... 打印 x #prints `A.x`...外面里面>>>打印 x外

您也可以直接从全局范围访问类属性:

<预><代码>>>>斧头'外在'

在课堂上使用global:

<预><代码>>>>x = '外部'>>>A类:... 全球 x... x += 'inner' #现在 x 不是类属性,你只是修改了全局 x... 打印 x...外在的>>>X'外层'>>>斧头属性错误:A 类没有属性x"

函数的陷阱不会在类中引发错误:

<预><代码>>>>x = '外部'>>>A类:... 从全局变量或内置变量打印 x #fetch... x = '我是一个类属性' #声明一个类属性... print x #print 类属性,即`A.x`...外我是一个类属性>>>X'外'>>>斧头'我是一个类属性'

<小时>

LEGB 规则:如果没有使用 globalnonlocal 则 python 按此顺序搜索.

<预><代码>>>>外 = '全球'>>>定义函数():封闭 = '封闭'定义内部():内部 = '内部'从(L)局部范围打印内部#fetch从(E)封闭范围打印封闭#fetch从(G)全局范围打印外部#fetch从 (B) uilt-ins 打印任何 #fetch内()...>>>功能()内封闭全球的<内置函数any>

If I run the following code:

x = 1

class Incr:
    print(x)
    x = x + 1
    print(x)

print(x)

It prints:

1
2
1

Okay no problems, that's exactly what I expected. And if I do the following:

x = 1

class Incr:
    global x
    print(x)
    x = x + 1
    print(x)

print(x)

It prints:

1
2
2

Also what I expected. No problems there.

Now if I start making an increment function as follows:

x = 1

def incr():
    print(x)

incr()

It prints 1 just as I expected. I assume it does this because it cannot find x in its local scope, so it searches its enclosing scope and finds x there. So far no problems.

Now if I do:

x = 1

def incr():
    print(x)
    x = x + 1

incr()

This gives me the following error in the traceback:

UnboundLocalError: local variable 'x' referenced before assignment.

Why does Python not just search the enclosing space for x when it cannot find a value of x to use for the assignment like my class Incr did? Note that I am not asking how to make this function work. I know the function will work if I do the following:

x = 1

def incr():
    global x
    print(x)
    x = x + 1
    print(x)

incr()

This will correctly print:

1
2

just as I expect. All I am asking is why it doesn't just pull x from the enclosing scope when the keyword global is not present just like it did for my class above. Why does the interpreter feel the need to report this as an UnboundLocalError when clearly it knows that some x exists. Since the function was able to read the value at x for printing, I know that it has x as part of its enclosing scope...so why does this not work just like the class example?

Why is using the value of x for print so different from using its value for assignment? I just don't get it.

解决方案

Classes and functions are different, variables inside a class are actually assigned to the class's namespace as its attributes, while inside a function the variables are just normal variables that cannot be accessed outside of it.

The local variables inside a function are actually decided when the function gets parsed for the first time, and python will not search for them in global scope because it knows that you declared it as a local variable.

So, as soon as python sees a x = x + 1(assignment) and there's no global declared for that variable then python will not look for that variable in global or other scopes.

>>> x = 'outer'
>>> def func():
...     x = 'inner'  #x is a local variable now
...     print x
...     
>>> func()
inner

Common gotcha:

>>> x = 'outer'
>>> def func():
...     print x       #this won't access the global `x`
...     x = 'inner'   #`x` is a local variable
...     print x
...     
>>> func()
...
UnboundLocalError: local variable 'x' referenced before assignment

But when you use a global statement then python for look for that variable in global scope.

Read: Why am I getting an UnboundLocalError when the variable has a value?

nonlocal: For nested functions you can use the nonlocal statement in py3.x to modify a variable declared in an enclosing function.


But classes work differently, a variable x declared inside a class A actually becomes A.x:

>>> x = 'outer'
>>> class A:
...    x += 'inside'  #use the value of global `x` to create a new attribute `A.x`
...    print x        #prints `A.x`
...     
outerinside
>>> print x
outer

You can also access the class attributes directly from global scope as well:

>>> A.x
'outerinside'

Using global in class:

>>> x = 'outer'
>>> class A:
...     global x
...     x += 'inner' #now x is not a class attribute, you just modified the global x
...     print x
...     
outerinner
>>> x
'outerinner'
>>> A.x
AttributeError: class A has no attribute 'x'

Function's gotcha will not raise an error in classes:

>>> x = 'outer'
>>> class A:
...     print x                      #fetch from globals or builitns
...     x = 'I am a class attribute' #declare a class attribute
...     print x                      #print class attribute, i.e `A.x`
...     
outer
I am a class attribute
>>> x
'outer'
>>> A.x
'I am a class attribute'


LEGB rule: if no global and nonlocal is used then python searches in this order.

>>> outer = 'global'
>>> def func():
        enclosing = 'enclosing'
        def inner():
                inner = 'inner'
                print inner           #fetch from (L)ocal scope
                print enclosing       #fetch from (E)nclosing scope
                print outer           #fetch from (G)lobal scope
                print any             #fetch from (B)uilt-ins
        inner()
...         
>>> func()
inner
enclosing
global
<built-in function any>

这篇关于为什么 Python 中的函数可以在封闭范围内打印变量,但不能在赋值中使用它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆