Python 3.x 在Python中,列表变量和字符串变量的作用域是否不同?
我正在学习Python 3中的作用域,这个例子让我感到困惑。在函数内调用时比较列表变量和字符串变量的行为:Python 3.x 在Python中,列表变量和字符串变量的作用域是否不同?,python-3.x,string,list,scope,Python 3.x,String,List,Scope,我正在学习Python 3中的作用域,这个例子让我感到困惑。在函数内调用时比较列表变量和字符串变量的行为: foo1 = [] foo2 = '' def f(): foo1.append(3) global foo2 foo2 += 'c' print('foo1-in-f:',foo1) print('foo2-in-f:',foo2) print('foo1-before:',foo1) print('foo2-before:',foo2) f()
foo1 = []
foo2 = ''
def f():
foo1.append(3)
global foo2
foo2 += 'c'
print('foo1-in-f:',foo1)
print('foo2-in-f:',foo2)
print('foo1-before:',foo1)
print('foo2-before:',foo2)
f()
print('foo1-after:',foo1)
print('foo2-after:',foo2)
正如预期的那样,输出为:
foo1-before: []
foo2-before:
foo1-in-f: [3]
foo2-in-f: c
foo1-after: [3]
foo2-after: c
我不明白为什么字符串必须是声明的全局的,如global foo2
行,但列表是未声明的全局的,如没有行global foo1
我运行代码时忽略了行global foo2
,毫不奇怪地得到了UnboundedLocalError:赋值前引用的局部变量'foo2'。但是,为什么我没有得到foo1
的这个错误呢
任何见解都值得赞赏。我想确保我了解这是如何工作的。您需要知道变量作用域在Python中是如何工作的。Python不要求您声明变量,但假定在函数体中分配的变量是局部变量。您可以看到编译器在生成的字节码中反映了这一点:
foo1=[]
foo2=''
def():
foo1.追加(3)
foo2+=“c”
从dis导入dis
dis(f)
foo1
是从全局上下文加载的,因为foo1.append(3)
是项分配操作-它修改实际引用。AFAIK Python字符串是不可变的,这意味着您需要在执行赋值之前复制该值,这是您在函数内部执行的操作,因为foo2+='c'
将实际创建一个新字符串。尝试运行foo1+=[3]
,您将得到与foo1
相同的UnboundLocalError
foo1.append(3)
是一种项目分配操作,相当于foo1[len(foo1):]=[3]
。由于上述原因,Python字符串无法执行此类操作-请尝试运行foo2[:]=“c”
,您将得到错误“str”对象不支持项分配
现在,global关键字基本上告诉解释器将foo2
视为一个全局变量,而不管函数中如何赋值。在Python函数中,所有变量引用都假定为全局变量,除非在本地命名。所有新对象都是在本地作用域中创建的,并且在将对象传输或修改到另一个作用域时有限制
你可以做:
a=1
def f(): return a+1 # unnamed integer object created and returned
>>> f()
2
您可以修改全局可变变量的内容,因为这不会将本地命名的对象分配给全局范围:
ls=['string']
def f():
ls.append('another') # unnamed string object created and added to ls
ls[0]+='_modified' # ls[0] read, new object created with +=,
# new object added to ls[0]
>>> f()
>>> ls
['string_modified', 'another']
ls=[]
def f():
ls+=['new entry'] # UnboundLocalError
但是使用ls+=[something]
将是一个错误,因为赋值+=
被视为ls
在作用域中是局部的,然后被重新分配到全局作用域:
ls=['string']
def f():
ls.append('another') # unnamed string object created and added to ls
ls[0]+='_modified' # ls[0] read, new object created with +=,
# new object added to ls[0]
>>> f()
>>> ls
['string_modified', 'another']
ls=[]
def f():
ls+=['new entry'] # UnboundLocalError
您看到的问题不一定是修改全局变量。将函数在本地使用的名称重新指定给全局作用域
Python网站上有一个
Eli Bendersky的博客上有一个链接。+=
是作为可变类型的变异实现的,但作为不可变类型的重新绑定。一个要点是a+=b
通常并不等同于a=a+b
。(对于字符串,正如您所观察到的那样)。感谢您提供的澄清示例和其他链接。我将深入研究+=运算符。乍一看,我假设a+=1
等同于a=a+1
。此外,您在列表中包装字符串的方法非常巧妙。例如,在退出函数后,我可以“连接”完整字符串,如:“”。join(['Zapdos','used','Thunder.])
谢谢,您对dis
读数的评论非常有用!我将在将来使用这个软件包,当遇到令人困惑的行为时,我会从引擎盖下面看看。