我一直试图理解为什么python会以这种方式运行,在下面的代码块中.我做了我的研究,但找不到一个好的答案所以我来到这里看看是否有人可以指出我正确的方向或提供一个很好的澄清.我知道它与一些旧的ALGOL原理有关,但我不完全理解它.
var = 5
def func1():
print(var)
func1()
def func2():
var = 8
print(var)
func2()
def func3():
print(var)
var = 8
func3()
Run Code Online (Sandbox Code Playgroud)
此代码的输出如下:
5
8
UnboundLocalError:赋值前引用的局部变量'var'
我理解为什么我们得到输出'5'和'8'.但是使用'func3()',我期待输出'5'.看起来,解释器认为我想在函数中打印局部'var'而不是全局'var'.所以它抛出了这个错误.
或者,如果在函数内部的某处定义了变量,则该函数将默认为局部变量,而不是具有相同名称的全局变量.
但是为什么python会这样表现呢?我不抱怨,我只是想了解一些事情......
我如何在函数中使用预定义的全局变量,然后在同一函数内定义一个具有相同名称的局部变量,而不更改全局变量的值?(当然是在python中)
在此先感谢大家.你是个很棒的人!:)
Edit_1:感谢每一个人给出了很好的答案.我完全理解在函数中使用预定义的全局变量是一个坏的和不切实际的想法,然后在同一个函数内定义一个具有相同名称的局部变量.我只是从理论的角度思考它,因为我在大学讲座中看到过它.XD我找不到一个用例,在这个用例中最好也是这样!
Edit_2:我已经阅读了PEP8,我知道明确比隐含更好.:) 这是真的.否则代码会混淆并导致错误.那个问题只是我试图理解的一些无用且不切实际的大学理论.
Edit_3:现在我完全理解为什么会发生这种情况以及这里发生了什么.感谢Randall Valenciano将这个链接提供给一个能够很好地解释它的博客.
会发生什么是该函数被解释为一个整体,而不是一行一行.因此,在解释函数时,任何已定义变量的变量声明都会移动到函数的顶部.因此,当我们打印'var'时,该函数正在使用本地声明的变量,该变量尚未分配任何值,然后解释器会抱怨它并抛出错误.
再次感谢大家!:)你对我有很大的帮助!现在我终于明白了幕后发生了什么.
我写了一个爬虫来从Q&A网站上获取信息.由于并非所有字段都始终显示在页面中,因此我使用了多个try-excepts来处理这种情况.
def answerContentExtractor( loginSession, questionLinkQueue , answerContentList) :
while True:
URL = questionLinkQueue.get()
try:
response = loginSession.get(URL,timeout = MAX_WAIT_TIME)
raw_data = response.text
#These fields must exist, or something went wrong...
questionId = re.findall(REGEX,raw_data)[0]
answerId = re.findall(REGEX,raw_data)[0]
title = re.findall(REGEX,raw_data)[0]
except requests.exceptions.Timeout ,IndexError:
print >> sys.stderr, URL + " extraction error..."
questionLinkQueue.task_done()
continue
try:
questionInfo = re.findall(REGEX,raw_data)[0]
except IndexError:
questionInfo = ""
try:
answerContent = re.findall(REGEX,raw_data)[0]
except IndexError:
answerContent = ""
result = {
'questionId' : questionId,
'answerId' : answerId,
'title' …Run Code Online (Sandbox Code Playgroud) 当我在python 2.7中重新导入已导入的模块时,我得到一个UnboundLocalError.一个最小的例子是
#!/usr/bin/python
import sys
def foo():
print sys
import sys
foo()
Traceback (most recent call last):
File "./ptest.py", line 9, in <module>
foo()
File "./ptest.py", line 6, in foo
print sys
UnboundLocalError: local variable 'sys' referenced before assignment
Run Code Online (Sandbox Code Playgroud)
但是,当嵌套导入作为函数定义中的第一个语句放置时,一切正常:
#!/usr/bin/python
import sys
def foo():
import sys
print sys
foo()
<module 'sys' (built-in)>
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么第一个脚本失败了吗?谢谢.
注意:有一个非常类似的问题在这里.但是,请耐心等待; 我的问题不是"为什么会发生错误",而是"为什么Python实现为在这种情况下抛出错误."
我只是偶然发现了这个:
a = 5
def x()
print a
a = 6
x()
Run Code Online (Sandbox Code Playgroud)
抛出一个UnboundLocalException.现在,我确实知道为什么会发生这种情况(后来在这个范围内,a受到限制,因此a在整个范围内都被认为是本地的).
在这种情况下:
a = 5
def x()
print b
b = 6
x()
Run Code Online (Sandbox Code Playgroud)
这非常有意义.但第一种情况有一个直观的逻辑,这意味着:
a = 5
def x()
print globals()["a"]
a = 6 # local assignment
x()
Run Code Online (Sandbox Code Playgroud)
我想有一个原因是为什么不允许"直觉"版本,但它是什么?虽然这可能是"明确比隐含更好"的情况,但摆弄着globals()总觉得我有点不洁净.
从这个角度来看,发生在我身上的实际情况是别人的剧本,我不得不改变一下.在我的(短暂的)更改中,我在脚本运行时进行了一些文件重命名,所以我插入了
import os
os.rename("foo", "bar")
Run Code Online (Sandbox Code Playgroud)
进入脚本.这个插入发生在一个函数内部.模块已经os在顶级导入(我没有检查过),有些os.somefunction调用在函数内部进行,但在插入之前.这些电话显然触发了一个UnboundLocalException.
那么,有人可以向我解释这个实现背后的原因吗?是为了防止用户犯错误?"直观"的方式会让字节码编译器的内容变得更复杂吗?或者是否有一种我没有想到的歧义?
Python 范围 我有同样的问题,但略有不同。
number = 0
def incrementNumber():
number += 1
Run Code Online (Sandbox Code Playgroud)
上面的这个不起作用,但下面的这个为什么?两者都在函数范围之外。
number = {'num':0}
def incrementNumber():
number['num'] += 1
Run Code Online (Sandbox Code Playgroud)
如果我将变量添加为全局变量,则第一个有效
number = 0
def incrementNumber():
global number
number += 1
Run Code Online (Sandbox Code Playgroud) 我一直在学习Ruby和Python,我注意到的一件事就是这两种语言似乎对待范围不同.这是我的意思的一个例子:
# Python
a = 5
def myfunc():
print a
myfunc() # => Successfully prints 5
# Ruby
a = 5
def myfunc
puts a
end
myfunc # => Throws a "NameError: undefined local variable or method `a' for main:Object"
Run Code Online (Sandbox Code Playgroud)
似乎def块可以在Python中访问在其直接范围之外声明的变量,但不能在Ruby中访问.有人可以确认我的理解是否正确吗?如果是这样,这些思考范围的方式之一是否在编程中更常见?
我已经阅读了其他一些SO(PythonScope和全局变量不需要全局),但似乎没有任何内容可以像我想的那样明确解释,而且我在精神上筛选PyDocs是否告诉我问题的答案时遇到了麻烦:
myList = [1]
def foo():
myList = myList + [2, 3]
def bar():
myList.extend([2, 3])
def baz():
myList += [2, 3]
Run Code Online (Sandbox Code Playgroud)
现在,可以理解,
>>> foo()
UnboundLocalError
Run Code Online (Sandbox Code Playgroud)
和
bar() # works
myList # shows [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
但是之后
>>> baz()
UnboundLocalError
Run Code Online (Sandbox Code Playgroud)
然而,我认为,+=在这种情况下extend(),隐含地称为方法运算符的东西,但错误意味着由于某种原因它实际上不会被+=视为extends().这与Python解析应该如何工作一致吗?
我本以为调用与方法运算符等效的函数,它们在所有情况下都是等价的.相反,它似乎将其视为+=实际的赋值运算符.除此之外,这并不完全正确,因为如果我做了某些事情(诚然做作):
myList = range(50000000) # wait a second or two on my laptop before returning
myList += [0] # returns instantly
myList = …Run Code Online (Sandbox Code Playgroud) def some_func(a):
def access_a():
print(a)
access_a()
Run Code Online (Sandbox Code Playgroud)
输出 的值a。但是,如果我想像这样更改a嵌套函数:
def some_func(a):
def change_a():
a += 1
print(a)
change_a()
Run Code Online (Sandbox Code Playgroud)
它引发UnboundLocalError异常。
我知道a是一个非局部变量,但为什么我可以在不声明的情况下访问它nonlocal a?
来自Google样式指南的词法范围:
嵌套的Python函数可以引用封闭函数中定义的变量,但不能赋值给它们.
这两个似乎最初都要检查:
# Reference
def toplevel():
a = 5
def nested():
print(a + 2)
nested()
return a
toplevel()
7
Out[]: 5
# Assignment
def toplevel():
a = 5
def nested():
a = 7 # a is still 5, can't modify enclosing scope variable
nested()
return a
toplevel()
Out[]: 5
Run Code Online (Sandbox Code Playgroud)
那么,为什么嵌套函数中的引用和赋值的组合会导致异常呢?
# Reference and assignment
def toplevel():
a = 5
def nested():
print(a + 2)
a = 7
nested()
return a
toplevel()
# UnboundLocalError: local variable 'a' referenced …Run Code Online (Sandbox Code Playgroud) 我使用yield来创建一个生成器,该生成器返回使用正则表达式和re.sub()提取的字符串块.虽然我发现了一种有效的方法,但我对它为什么单向工作而不是另一种工作有点困惑,如下所示:
这不起作用(processchunk()没有分配给splitmsg中声明的块):
def splitmsg(msg):
chunk = None
def processchunk(match):
chunk = match.group(1)
return ""
while True:
chunk = None
msg = re.sub(reCHUNK,processchunk,msg,1)
if chunk:
yield chunk
else:
break
Run Code Online (Sandbox Code Playgroud)
这确实有效(注意唯一的区别是块现在是一个列表块):
def splitmsg(msg):
chunks = [ None, ]
def processchunk(match):
chunks[0] = match.group(1)
return ""
while True:
chunks[0] = None
msg = re.sub(reCHUNK,processchunk,msg,1)
if chunks[0]:
yield chunks[0]
else:
break
Run Code Online (Sandbox Code Playgroud)
我的问题基本上是为什么看起来chunk/chunk变量的范围似乎取决于它是一个普通变量还是一个列表?
python ×10
python-3.x ×3
scope ×3
dictionary ×1
exception ×1
generator ×1
global ×1
methods ×1
nested ×1
python-3.5 ×1
python-3.6 ×1
regex ×1
ruby ×1
yield ×1