声明:本文中大部分内容均在参考网址中,本人进行精简后,略加修改并加上一点自己的理解。

一、python中作用域

1.局部作用域,在函数内部或lambda、类中的全局局部变量中,调用函数时才会创建。每次调用都会创建一个新的本地作用域。调用结束后会销毁。(函数的参数也位于此作用域,这也解释了为什么不同函数,内部变量或参数名相同,并不引发冲突)。不可修改闭包作用域定义的变量,除非使用nonlocal语句。

2.闭包作用域(nonlocal),存在嵌套函数中,为其外层作用域。调用函数之后创建的变量不在此作用域。

3.全局作用域,顶层模块中所有函数外创建的全局变量。在函数内不可被修改,除非使用global语句,使用这些语句,也能在局部作用域创建全局变量。不过最好避免这种做法

4.内置作用域,builtins包,由python自动导入,一般为内置函数。如果担心其中命名被全局作用域覆盖,可显式写出。

与global不同,不能在嵌套或封闭函数之外使用nonlocal,也不能用nonlocal来创建变量。

二、搜索顺序问题(LEGB)

这里有两类情况需要区分:
2.1 在变量引用时,python的搜索顺序是按照从上向下的顺序搜索(如果有的话),这也就是为什么如果你命名变量和python内置变量冲突时,会导致覆盖,从而引发错误。
2.2 而在变量赋值时,则只考虑本地局部作用域,这是因为在python中赋值即定义

abs = 20
abs(-15)    # 由于内置函数名被覆盖,此时会出错# 1.第一种办法
import builtins
builtins.abs(-15)# 2.第二种办法
del abs     # 从全局作用域删除其定义,因此可以访问内置作用域
abs(-15)    # 15 正常执行

注意:闭包会从最内层搜索到最外层(多层嵌套情况)

前两个作用域保证你的变量不会在很远的地方被修改,方便调试和维护。

def scope_test():spam2 = "outer2 spam"def do_test():def do_local():spam = "local spam"                         # 局部变量print("outer two:", spam2)                  # 最外层闭包作用域print( do_local.__code__.co_varnames )        # 输出局部作用域变量# print("after call:", spam3)               # 调用函数之后创建的变量不在闭包作用域中def do_nonlocal():nonlocal spamspam = "nonlocal spam"def do_global():global spamspam = "global spam"spam = "test spam"do_local()spam3 = "after call create"print("After local assignment:", spam)do_nonlocal()print("After nonlocal assignment:", spam)do_global()print("After global assignment:", spam)do_test()scope_test()
print("In global scope:", spam)

上述输出为:

outer two: outer2 spam
('spam',)
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

三、闭包(Closures)和闭包作用域(Enclosing)

Closures会返回一个函数,其作用相当于冻结一些参数,已供后续使用(类似存款)。经常用于一些需要延后执行的场景。partial()函数及装饰器就是使用这个技术实现的。

def scope_test1():spam2 = "spam"def do_test():                # 其调用时机被延后,因此定义在外层的变量都可使用print(spam2)print("After:", spam3)spam3 = "after spam"     # 在定义之后的变量也可使用return do_testmfun = scope_test1()
mfun()

其实据此可以分析出,Enclosing的变量必然是存储在do_test()函数中的,这些变量存储在func_name._ _ code _ _.co_freevars中

def scope_test1():spam2 = "spam2"def do_test():print(spam2)print("After:", spam3)spam3 = "after spam3"do_test()spam4 = "spam4"print( do_test.__code__.co_freevars )   # 属于闭包的自由变量print( do_test.__closure__ )            # 这些元素是cell对象print( do_test.__closure__[0].cell_contents )   # 这些元素具体的值return do_test
mfun = scope_test1()

上述输出为:

spam2
After: after spam3
('spam2', 'spam3')
(<cell at 0x000001FADFAB1888: str object at 0x000001FADF997CA8>, <cell at 0x000001FADFAB1798: str object at 0x000001FADFC21030>)
spam2

从这再次验证了调用函数之后创建的变量不属于函数自由变量,因此在闭包中也就找不到该变量。

四、不符合LEGB的特例

4.1.列表生成式

[item for item in range(5)]     # 类似局部作用域,一旦完成,内部变量销毁
# print( item )                 # 会出错
# 与之对比
for item in range(5):pass
print(item)                     # 输出4

4.2.exception variable

如下述代码,err变量只能在except代码块中使用,类似局部变量。而在except块中定义的其他变量是作为全局变量。要想在全局作用域使用err保存的信息,只能在except块中定义一个辅助变量ex,然后在外部引用ex变量。

mylist = [1, 2, 3]
try:mylist[4]
except IndexError as err:print(err)          # list index out of rangeex = err         # 这样就可以在外面使用此信息了err = "change"print(err)          # changenew_var = 5print(new_var)          # 正常输出 5
print(err)              # NameError: name 'err' is not defined
# -------------------------------
# 与之对比,with as语句并不会出现此问题
with open("score.txt", 'r') as f:f.read()
print(f)    # <_io.TextIOWrapper name='score.txt' mode='r' encoding='cp936'>

4.3.类和实例属性

class Myclass:attr = 50a = Myclass()
b = Myclass()
a.attr = 100        # 仅改变自身
print( b.attr )     # 50
Myclass.attr = 100  # 会改变所有实例的该属性
print( b.attr )     # 100# 例2
class Myclass:attr = 50                # class local scopedef __init__(self, var):self.var = var      # 其为实例属性  instance local scope
a = Myclass(40)
b = Myclass(60)
print(a.var)            # 40
print(Myclass.var)      # __init__根本没执行,AttributeError: type object 'Myclass' has no attribute 'var'# 以下为两者区别
print(a.__init__)       # <bound method Myclass.__init__ of <__main__.Myclass object at 0x000002B5D24F2BE0>>
print(Myclass.__init__) # <function Myclass.__init__ at 0x000002835EA687B8>

self是表示当前实例,也可从另一方面解释,即python中类的方法是与实例进行绑定的,因此没有实例就无法执行,除非是静态方法。

搜索顺序

1.搜索instance local scope,因此实例属性可覆盖类属性
2.class local scope
尽管类中也为局部作用域,但不适用闭包作用域,必须使用点。
实例属性覆盖类属性后,仍能通过类名.属性访问类属性。此时实例.属性返回的是实例属性。

class Myclass:attr = 50def __init__(self, var):# print("attr ", attr )       # 类似闭包作用域做法,NameErrorprint("attr ", self.attr )    # 正确执行 或 使用Myclass.attra = Myclass(40)

参考

https://realpython.com/python-scope-legb-rule/#understanding-scope
https://docs.python.org/zh-cn/3/tutorial/classes.html
《流畅的python》

python中的各种作用域相关推荐

  1. python中函数的作用域_Python中的函数作用域

    在python中,一个函数就是一个作用域 name = 'xiaoyafei' def change_name(): name = '肖亚飞' print('在change_name里的name:', ...

  2. python中变量的作用域有几种_Python中变量的作用域(variable scope)

    http://www.crifan.com/summary_python_variable_effective_scope/ 解释python中变量的作用域 示例: 1.代码版 #!/usr/bin/ ...

  3. 【Python】Python中令人头疼的变量作用域问题,终于弄清楚了

    [Python]Python中令人头疼的变量作用域问题,终于弄清楚了_fengdu78的博客-CSDN博客 [Python]Python中令人头疼的变量作用域问题,终于弄清楚了_fengdu78的博客 ...

  4. Python中的变量作用域

    1.变量的作用域:即变量的有效范围.变量并不是在哪个位置都可以访问的,访问权限取决于这个变量是在哪里赋值的,也就是在哪个作用域内的. 2.在Python中,没有块级作用域,也就是说类似if语句块.fo ...

  5. Python中令人头疼的变量作用域问题,终于弄清楚了

    来源:Python数据之道 作者:大奎  整理:阳哥 学习Python变量过程中,曾经为变量混乱的作用域问题头疼不已,全局变量.局部变量.自由变量傻傻分不清,今天来跟大家分享 Python变量作用域 ...

  6. Python中变量的作用域?(变量查找顺序)

    函数作用域的LEGB顺序 1.什么是LEGB? L: local 函数内部作用域 E: enclosing 函数内部与内嵌函数之间 G: global 全局作用域 B: build-in 内置作用 p ...

  7. python中if for 作用域问题

    先看一段代码 class Car():def __init__(self,name):self.name = namedef __repr__(self):return self.nameif __n ...

  8. python中变量的作用域

    变量的作用域 变量的作用域就是指变量的有效范围. 变量按照作用范围分为两类,分别是 全局变量 和 局部变量. 全局变量:在函数外部声明的变量就是全局变量 有效范围:全局变量在函数外部可以正常使用.全局 ...

  9. python中函数作用域_Python中的函数作用域

    在python中,一个函数就是一个作用域 name = 'xiaoyafei' def change_name(): name = '肖亚飞' print('在change_name里的name:', ...

最新文章

  1. 【linux】串口编程(三)——错误处理
  2. 360浏览器登录_360浏览器登录统一操作系统UOS国产CPU首次实现高清视频在线播放...
  3. 原子变量、volatile、synchronized的可见性和原子性比较
  4. Day1-dns Extension
  5. easyui根据select下拉框内容更新表单内容_Ant Design 4.0 的一些杂事儿 - Select 篇
  6. 华为云优秀伙伴展示--2020-08-12
  7. copy 浅复制 与深复制
  8. 3个阶段 项目征名_中资企业新签的3个海外项目开工
  9. Voleon Group:一家『纯』用机器学习策略的对冲基金
  10. bbs的html代码,bbs论坛源代码
  11. Detached InstanceError:Instance is not bound to a Session 关闭session后使用SQLAlchemy对象
  12. 星际开图挂_别开|《星际争霸2》牛X强力高端职业玩家手把手教你识别开图挂_234游戏网...
  13. 斯坦福大学公开课机器学习课程(Andrew Ng)六朴素贝叶斯算法
  14. rds mysql 导出数据文件_rds数据库导出
  15. 悦保车牌识别相机优势
  16. iOS项目开发中的知识点与问题收集整理
  17. 蓝屏代码stop:0X000000EA(0X85E286B8,0X8635F210,0XF7A53CBC,0X00000001)NV4_DISP是什么意思?
  18. 诚之和:各业务不断爆出裁员,字节跳动如何“过冬”?
  19. 轻松获取Excel安装路径
  20. go语言实现网易云音乐爬虫

热门文章

  1. cf----2019-10-23( Posterized,Pair Of Lines,Greedy Arkady)
  2. samba 开通_开启Samba服务
  3. transformer与vit
  4. 关于卷积神经网络的案例以及ReLU函数
  5. python第三方库有哪些-Python常用第三方库大盘点
  6. poi操作表格table
  7. Directx9播放视频
  8. 【时事摘抄】“冷漠的哥”获罪是否可有法依?----坐视强奸的司机
  9. Android开发中EditText:一、属性详解
  10. C语言 extern的用法