浅谈python函数之作用域(python3.5)


Posted in Python onOctober 27, 2017

1 基本概念

1.1 命名空间 (namespace)

命名空间是变量名到对象的映射(name -> obj)。目前大多数的命名空间以类似于python字典的形式实现,实现形式在未来可能发生变化。命名空间举例:内置变量(内置函数abs, 内置的异常等),模块中的全局变量,函数调用时的局部变量。在某种意义上讲,对象的属性也形成一个命名空间。重要的是,不同的命名空间中的变量没有任何关联,两个不同的命名空间中可以包含相同的变量名。

命名空间有不同的创建时间和生命周期:

•内置变量命名空间在python解释器启动时创建,并且在解释器运行期间永远不会被删除;

•一个模块的命名空间在模块被导入时创建,并且到解释器退出会一直存在;

•函数的本地(局部)命名空间在函数调用时创建,函数退出时删除;

•解释器顶层执行的语句都是 __main__ 模块的组成部分,它们有自己的命名空间。

注:内置变量实际上同样是以模块的形式存在,模块名为 builtins 。

1.2 作用域 (scope)

作用域是Python程序中可以直接访问一个命名空间内变量的文本区域,可直接访问即命名空间内的变量在该文本区域内可见、可引用。

•本地(局部)作用域:函数或者类的内部

•全局作用域:整个程序的运行环境。

全局作用域中无法直接访问本地作用域中定义的变量:

def func1():
 name = 1

print(func1) # <function func1 at 0x101a03d08>
print(name)
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# NameError: name 'name' is not defined

本地作用域中的变量定义:

•在python中,变量赋值即定义。在局部作用域内被赋值的变量,除非由 global 或者 nonlocal 声明,否则全部为局部变量,函数调用时存在于函数命名空间。

•global var : 声明变量 var 为全局变量,它所有的引用和赋值都在模块的命名空间进行。

•nonlocal var : 将外层函数命名空间中的变量 var 绑定到本地作用域,使其在本地作用域可重新赋值。如果变量没有被声明为 nonlocal,这些变量在本地作用域仅可读,尝试给变量赋值则会在本地命名空间创建一个同名变量。

nonlocal声明的变量在上层函数中必须存在,否则报错:

test = 'global variable'

def scope_test():
 def inner():
  nonlocal test
  print(test)

scope_test() # SyntaxError: no binding for nonlocal 'test' found

2 示例

2.1 本地作用域中变量的搜索遵守LEGB规则

1.L-Local(function):函数或类的命名空间,其中的变量称为本地变量

2.E-Enclosing function locals:外层函数的命名空间(例如closure),包含被声明为non-local的变量

3.G-Global(module):函数定义所在模块的命名空间,其中的变量称为全局变量

4.B-Builtin(Python):Python内置模块的名字空间

def scope_test():
 def do_local():
  spam = "local spam"

 def do_nonlocal(): 
  nonlocal spam# 递归向上寻找上层函数命名空间中的spam变量
  spam = "nonlocal spam"

 def do_global():
  global spam # 在全局变量中寻找spam变量,没有则创建
  spam = "global spam"

 spam = "test spam"
 do_local()
 print("After local assignment:", spam) # 输出本地变量 spam
 do_nonlocal()
 print("After nonlocal assignment:", spam)
 do_global()
 print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)

结果

<SPAN style="FONT-SIZE: 14px">1 After local assignment: test spam 
After nonlocal assignment: nonlocal spam 
After global assignment: nonlocal spam 
In global scope: global spam 
</SPAN>

2.2 闭包

闭包:在嵌套函数中,如果内层函数引用了外层函数的变量,就形成了一个闭包。

自由变量:被引用的外层函数变量,称为内层函数的自由变量。

def fn():
  a = 1
  def closure():
    nonlocal a
    a += 1
    print(a)
  return closure

inner = fn() 
print(inner.__closure__)  # (<cell at 0x10240b408: int object at 0x100277bc0>,)
inner() # 2
inner() # 3

外层函数执行完,其命名空间删除。但是因为 a 是内层函数的自由变量,所以变量 a 被保留,可以看作是 closure 函数对象的一个附加属性。

3 静态检测

3.1 本地变量

python是在编译def语句时静态检测其本地变量的。

a = 1
def local_test():
  a += 1
  print(a)
local_test()  # UnboundLocalError: local variable 'a' referenced before assignment

print(b)  # NameError: name 'b' is not defined

在编译local_test函数时,python就确定了变量 a 为函数的本地变量。所以在执行 a += 1 是会直接在本地命名空间寻找变量a。

3.2 命名空间搜索链

name = "lzl"
 
def f1():
  print(name)
 
def f2():
  name = "eric"
  f1()
 
f2() # lzl

一个函数的变量搜索路径是在它定义的时候决定的,不受它调用位置的影响。

f1定义在全局作用域中,其变量的搜索路径为:本地命名空间 --> 模块命名空间。所以最后的输出结果为‘lzl'。

4 匿名函数

Python借助lambda关键字定义匿名函数,格式如下:

lambda 参数列表: 表达式

lambda x: x + 1
# 函数功能类型于下面的函数
def _(x):
  return x + 1

示例

下面一段代码的输出结果是什么:

li = [lambda :x for x in range(10)]
print(li[0]())

其等价形式:

def fn():
  return x 

li = []
for x in range(10):
  li.append(fn)
li[0]() # fn() -> 9,根据变量搜索规则,x在函数中没有定义,在全局变量中查找

以上这篇浅谈python函数之作用域(python3.5)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python与shell的3种交互方式介绍
Apr 11 Python
python中函数总结之装饰器闭包详解
Jun 12 Python
Django 浅谈根据配置生成SQL语句的问题
May 29 Python
10 行 Python 代码教你自动发送短信(不想回复工作邮件妙招)
Oct 11 Python
Python 窗体(tkinter)按钮 位置实例
Jun 13 Python
Python split() 函数拆分字符串将字符串转化为列的方法
Jul 16 Python
python实现ip地址查询经纬度定位详解
Aug 30 Python
opencv3/Python 稠密光流calcOpticalFlowFarneback详解
Dec 11 Python
利用Python如何制作贪吃蛇及AI版贪吃蛇详解
Aug 24 Python
python各种excel写入方式的速度对比
Nov 10 Python
Python爬虫之Selenium鼠标事件的实现
Dec 04 Python
详解Python中openpyxl模块基本用法
Feb 23 Python
python+pyqt实现右下角弹出框
Oct 26 #Python
python中模块的__all__属性详解
Oct 26 #Python
Python内建函数之raw_input()与input()代码解析
Oct 26 #Python
python分布式环境下的限流器的示例
Oct 26 #Python
Python Nose框架编写测试用例方法
Oct 26 #Python
Python面向对象编程基础解析(二)
Oct 26 #Python
Python面向对象编程基础解析(一)
Oct 26 #Python
You might like
详细介绍PHP应用提速面面观
2006/10/09 PHP
php数组比较实现查找连续数的方法
2015/07/29 PHP
用js计算页面执行时间的函数
2006/12/07 Javascript
ExtJS 简介 让你知道extjs是什么
2008/12/29 Javascript
Span元素的width属性无效果原因及解决方案
2010/01/15 Javascript
jquery cookie的用法总结
2013/11/18 Javascript
JS 排序输出实现table行号自增前端动态生成的tr
2014/08/13 Javascript
JavaScript实现删除,移动和复制文件的方法
2015/08/05 Javascript
js实现具有高亮显示效果的多级菜单代码
2015/09/01 Javascript
浅析上传头像示例及其注意事项
2016/12/14 Javascript
jQuery实现搜索页面关键字的功能
2017/02/16 Javascript
完美实现js选项卡切换效果(二)
2017/03/08 Javascript
详解从Vue.js源码看异步更新DOM策略及nextTick
2017/10/11 Javascript
用p5.js制作烟花特效的示例代码
2018/03/21 Javascript
详解angular分页插件tm.pagination二次触发问题解决方案
2018/07/20 Javascript
JS集合set类的实现与使用方法示例
2019/02/01 Javascript
简述ES6新增关键字let与var的区别
2019/08/23 Javascript
JavaScript中ES6规范中let和const的用法和区别
2020/08/06 Javascript
vue 如何使用递归组件
2020/10/23 Javascript
[54:05]DOTA2-DPC中国联赛定级赛 SAG vs iG BO3第一场 1月9日
2021/03/11 DOTA
python集合类型用法分析
2015/04/08 Python
Python实现程序判断季节的代码示例
2019/01/28 Python
pyqt5之将textBrowser的内容写入txt文档的方法
2019/06/21 Python
Django使用模板后无法找到静态资源文件问题解决
2019/07/19 Python
python 字典有序并写入json文件过程解析
2019/09/30 Python
python 爬取小说并下载的示例
2020/12/07 Python
精油和天然健康美容产品:Art Naturals
2018/01/27 全球购物
娇韵诗法国官网:Clarins法国
2019/01/29 全球购物
介绍一下SQL注入攻击的种类和防范手段
2012/02/18 面试题
群众路线教育实践活动方案
2014/02/02 职场文书
危爆物品安全大检查大整治工作方案
2014/05/03 职场文书
交通运输局四风问题对照检查材料思想汇报
2014/10/09 职场文书
党员干部作风建设思想汇报范文
2014/10/25 职场文书
2014年办公室工作总结范文
2014/11/12 职场文书
2015年全国科普日活动总结
2015/03/23 职场文书
浏览器常用基本操作之python3+selenium4自动化测试(基础篇3)
2021/05/21 Python