这篇文章主要介绍了Python变量作用域LEGB用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

闭包就是, 函数内部嵌套函数. 而 装饰器只是闭包的特殊场景而已, 特殊在如果外函数的参数是指向一个, 用来被装饰的函数地址时(不一定是地址哈, 随意就好) , 就有了 "@xxx" 这样的写法, 还是蛮有意思的. 装饰器的作用是 在不改变原函数的代码前提下, 额外给原函数填写新功能. 写法上来看, 还是比较简洁优雅的.

装饰器的通俗写法

# 装饰器的通用写法

def out(func):

def inner(*args, **kwargs):

print("we are checking...", args[0])

return func(*args, **kwargs)

return inner

@out

def check_2019_nCov(name):

return f"now, {name} is very healthy..."

tmp = check_2019_nCov('youge')

print(tmp)

# output

we are checking... youge

now, youge is very healthy...

给装饰器传参

虽然这种 "@" 的写法, 是要求 外函数的参数是一个 func 地址 , 但要达到可以传参, 只要 再在外面包一层函数 (作用是接受参数) , 这样不就相当于扩大作用空间, 拿到参数了呀 .

# 最外层的函数作用是, 给装饰器传递参数

def get_param(*args, **kwargs):

def out(func):

def inner(*args, **kwargs):

print("get params", args, kwargs)

return func(*args, **kwargs)

return inner

return out

@get_param("youge")

def check_2019_nCov(name):

return f"now, {name} is very healthy..."

tmp = check_2019_nCov("youge")

print(tmp)

# output

get params ('youge',) {}

now, youge is very healthy...

这种个装饰器传递参数的应用场景, 在 Web应用中, 以 Flask 为例, 就是所有的 路由 url 的概念呀, 如 route("/login") 这样的写法, 其原理就是用各种装饰器来实现 路由 -> 视图 的映射关系的.

仔细一看, 整个过程忽略了一个重要的话题, 即命名空间, 及 变量的作用域, 或者说命名空间如怎样的.

LEGB 法则

命名空间

前篇已经详细阐述过了, Python 变量的本质是指针, 是对象的引用, 而 Python中 万物皆对象. 这个对象是真正存储数据的内存地址, 是各种类(数据类型, 数据结构) 的实例. (变量就是用来引用对象的) 差不多这个意思吧.

最为直观的解释:

" A namespace is a mapping from names to objects". (变量名和对象的映射)

"Most namespaces are currently implemented as Python dictionaries." (大部分命名空间通过字典来实现)

即命名空间是用来 避免变量命名冲突 的约束. 各个命名空间是彼此独立的, 一个空间中不能重名, 不同空间中是不没有关系的. 就跟 计算机系统, 存储文件是样的逻辑.

for i in range(10):

print(i)

# 这两句话都用到了 i 但其各自的空间是不一样的.

[i for i in range(100)]

内置空间: (built-in names): Python 内置名称, 如内置函数,异常类...

全局空间: (global names): 常量, 模块中定义的名称(类, 导入模块)...

Enclosed: 可能嵌套在函数内的函数等...

局部名称: (local names): 函数中定义的名称(函数内的变量) ...

Python 查找变量顺序为:Local -> Enclosed -> Global -> Built-in。

其实, 从我个人经验而言, 能区分 局部和全局 的 相对性. 就好了, 基本上. 直观上, 以一个写代码的 py文件为例. 最外层有, 变量, 类定义, 函数定义, 从from .. import .. 的变量或函数名, 这些就是 全局变量, 最外面的类或者函数, 里面是各自的名字空间呀.

# var1 是 global

var1 = 666

def foo():

# var2 是局部

var2 = 666

def foo2():

# 内嵌的局部

var3 = 666

# print(var2)

print(var3) # G->L 是找不到的哦

# 在 foo2 中 寻找 var2 是 L->E 是ok的

# 在 foo 中 寻找 var2 是 E->L 是不行的

其实很好理解的. 就上段code来说,根据 L-E-G-B 法则, 其实理解一个 相对 就可以了.

全局 vs 局部

total = 0 # 全局

def sum(a, b):

"""重写内置sum"""

total = a + b

print("局部total:", total)

sum(1, 1)

print("全局total:", total)

# output

局部total: 2

全局total: 0

可以看到, 局部是不会改变全局的哦, 而在局部内是可以拿到全局变量的. 不然闭包, 外函数接收的参数, 内函数怎么可以拿到呢? 就是外函数, "扩充了" 内函数的作用域呀, 根据 L->E->G->B 法则去搜索到.

global 和 nonlocal

name = "youge"

def change_name():

name = "youyou"

# 希望将 "youge" 改为 "youyou"

change_name()

print(name)

# output

youge

发现没有能改掉, 这是自然的. 因为, 在调用函数时, 里面的 name 是一个 Local 变量, 是不会影响到全局的 name的, 如果想实现在 在函数内部来改变 全局变量, 则将 该变量用 global 关键字声明即可.

name = "youge"

def change_name():

global name

name = "youyou"

# 希望将 "youge" 改为 "youyou"

change_name()

print(name)

# output

youyou

很简单, 在函数内部, 用 global 将其声明为全局变量即可. 同样, 针对于** 函数嵌套, 即向闭包, 装饰器等, 通过 关键字 nonlocal 实现将 函数内的变量, 声明为 函数外的 Enclose 层**

name = "jack"

def outer():

name = "youge"

# 函数内有一个local函数空间

def inner():

name = "youyou"

print("local:", name)

inner() # 尝试改掉 嵌套层的 name

print("encolse:", name)

print("global:", name)

outer()

# output

global: jack

local: youyou

encolse: youge

现在想在, inner函数 (L层) 中来修改 E 层的 name, 即在inner中将 name 声明为 nonlocal 即可.

name = "jack"

def outer():

name = "youge"

# 函数内有一个local函数空间

def inner():

nonlocal name

name = "youyou"

print("local:", name)

inner() # 尝试改掉 嵌套层的 name

print("encolse:", name)

print("global:", name)

outer()

# output

global: jack

local: youyou

encolse: youyou

函数嵌套场景中, 通过 在 local 层, 声明 name 为 nonlocal 则将 enclosed 层的name改掉了. 但如果在 local 层 声明 global 则是没有其效果的, 为啥, 嗯... 暂时还不清楚, 也是实验的, 暂时.

哦, 突然想贴一个, 我还是菜鸟时常, 犯的小错误:

name = 'youge'

def change_name():

name = name + "youyou"

change_name()

print(name)

# output

UnboundLocalError: local variable 'name' referenced before assignment

原因就在于, 在函数内部的空间中, 对 name 是没有定义的. 在 Python中, 对于函数过程的存储, 是通过 递归栈 实现的. 利用栈的 FILO, (先进后出) 的特点, 当遇到一个函数, 就用栈将其参与的成员, 依次入栈, 如有 return 则将置为栈元素.

变量要先定义, 后使用嘛, Python中的定义是指, 该变量指向某个实例对象即可, 而非 其它语言中的 类型声明 哦, 这里最容易混淆.

修改 name 为全局变量,通过函数参数传递即可:

# 方式1: 定义个单独的函数来处理

name = 'youge'

def change_name(s):

name = s + "youyou"

print(name)

# 全局变量来传递给 函数空间, 即"先定义, 后执行")

change_name(name)

# output

yougeyouyou

# 方式2: 声明为全局即可, 不推荐

name = 'youge'

def change_name():

global name

name = name + "youyou"

change_name()

print(name)

# output

yougeyouyou

小结

闭包, 装饰器的本质是函数的嵌套, 参数及函数能被传递的原因是, Pyhton变量的本质是之指针

Python中用 命名空间 来 解决 变量名冲突, 原理跟 计算机系统(如 Linux) 存储文件是一样的逻辑

变量名寻找的规则为 Local -> Enclosed -> Global -> Built-in

个人觉得能理解,全局与局部的"相对性" 即可, 另外, 可用 global 与 nonlocal (E层) 改变变量作用等级.

变量作用域, 一直在用, 但却经常忽略它, 这里做个总结, 没事常翻翻, 作用域, 就到这吧.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

python legb_Python变量作用域LEGB用法解析相关推荐

  1. python进阶15变量作用域LEGB

    原创博客链接:python进阶15变量作用域LEGB 作用域 "作用域"定义了Python在哪一个层次上查找某个"变量名"对应的对象.接下来的问题就是:&quo ...

  2. python函数变量的作用域_学不会的Python函数——变量作用域

    1. LEGB函数 Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的.我们先来看一段代码. 上述代码有两个变量a,当在test函数中输出变量a的值是,为什么 ...

  3. python中变量作用域

    python中变量作用域采取以下规则: 1.python能够改变变量作用域的代码段是def.class.lamda. 2.if/elif/else.try/except/finally.for/whi ...

  4. Python基本语法_变量作用域LEGB

    目录 目录 软件系统 变量的作用域 高级语言对数据类型的使用过程 作用域的产生 作用域的类型 Llocal局部作用域 Eenclosing嵌套作用域 Gglobal全局作用域 Bbuilt-in内置作 ...

  5. Python 的变量作用域和 LEGB 原则

    在 Python 程序中创建.改变或查找变量名时,都是在一个保存变量名的地方进行中,那个地方我们称之为命名空间.作用域这个术语也称之为命名空间. 具体地说,在代码中变量名被赋值(Python 中变量声 ...

  6. python local global_Python 变量作用域 LEGB (上)—— Local,Global,Builtin

    Python 变量作用域的规则是 LEGB LEGB含义解释: L -- Local(function):函数内的名字空间 E -- Enclosing function locals:外部嵌套函数的 ...

  7. Python中变量作用域问题

    我们经常听说Python函数访问局部变量.全局变量:在定义装饰器的时候,还会使用自由变量.这些不同的变量是如何赋值.初始化.查找及修改的呢?各自的作用细则又是什么样的呢?本篇尝试解答这个问题. Pyt ...

  8. python的变量作用域

    1. 不在函数体内的变量或者在 if __name__=='__main__'中的变量,都是全局变量,注意访问这些全局变量的速度是比较慢的,因为这些全局变量放在一个全局的表中,需要查找 2. 在函数体 ...

  9. Python基础-变量作用域

    1.函数作用域介绍 函数作用域 Python中函数作用域分为4种情况: L:local,局部作用域,即函数中定义的变量: E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局 ...

最新文章

  1. python2的默认数字类型_伪·从零开始学Python - 2.2.1 基本数据类型 - 整型与浮点型...
  2. 剑指offer——面试题7:重建二叉树
  3. Numpy-随机生成以及矩阵的运算
  4. jmeter(三)参数化
  5. Castle 开发系统文章
  6. JVM专题之分代模型:年轻代、老年代、永久代
  7. python-day11 Mysql 数据类型
  8. android 接口报错409,android 在调用微信刷脸获取用户信息时,在还未完成识别时点击退出,WxPayFace 停止应用...
  9. tar 打包、压缩和备份
  10. Interesting Finds: 2008.01.04
  11. 【HDU-5963】朋友【树上博弈】
  12. 理解“正反馈”和“负反馈”,学会系统性思考
  13. 利用BS爬取单词音标
  14. 硬核 | 用Python给女朋友送一颗彩蛋
  15. 信道以及信道容量小结
  16. xp oracle10g安装图解,虚拟机xp系统中Oracle 10g的安装
  17. 如何安装适用于win11的安卓子系统(WSA)的谷歌框架安卓13版本
  18. 你喜欢的搞笑内容都在这里-----笑口常开
  19. HTML标签基础知识
  20. el表达式ne什么意思_EL表达式的基本语法及运算符

热门文章

  1. Python中可变类型和不可变类型的数据?
  2. 后悔!我早该把这1W字详解的 InnoDB 原理给你!
  3. Redis从入门到精通,至少要看看这篇!
  4. 感谢有你 | LiveVideoStackCon 2020 北京站优秀出品人、讲师与志愿者
  5. 《长安十二时辰》背后的文娱大脑:如何提升爆款的确定性?
  6. 视频云服务平台架构设计难点与趋势
  7. ​SoundCloud的web播放库Maestro演进之路
  8. 周思进:自知“能力不足“让我专注十几年音视频
  9. 谷沉沉:专注视频技术十几年
  10. 机器学习实战教程(四):朴素贝叶斯基础篇之言论过滤器