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

作者:Wadirum 时间:2021-09-22 05:49:42 

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在函数中没有定义,在全局变量中查找

来源:http://www.cnblogs.com/wadirum/archive/2017/10/26/7674740.html

标签:python,函数,作用域
0
投稿

猜你喜欢

  • Python读取YUV文件,并显示的方法

    2023-03-19 11:44:13
  • ASP 生成静态新闻列表

    2009-03-03 12:25:00
  • MySQL数据库备份和还原的常用命令

    2012-01-05 18:50:06
  • asp如何调用DLL来加快服务器的执行速度?

    2009-11-15 20:07:00
  • python实现逢七拍腿小游戏的思路详解

    2021-02-28 23:44:29
  • Python中PyQt5/PySide2的按钮控件使用实例

    2023-03-04 16:27:44
  • tensorflow查看ckpt各节点名称实例

    2021-03-26 14:04:49
  • django的auth认证,authenticate和装饰器功能详解

    2021-10-06 00:34:51
  • mysql split函数用逗号分隔的实现

    2024-01-19 12:46:40
  • 如何利用Tensorflow2进行猫狗分类识别

    2021-06-29 18:58:12
  • python中将正则过滤的内容输出写入到文件中的实例

    2023-12-15 06:56:09
  • Python按行读取文件的实现方法【小文件和大文件读取】

    2021-12-11 01:31:08
  • MySQL的性能调优工具:比mysqlreport更方便的tuning-primer.sh

    2008-12-08 08:37:00
  • django 扩展user用户字段inlines方式

    2022-02-28 00:50:14
  • python不到50行代码完成了多张excel合并的实现示例

    2023-04-11 10:41:39
  • CentOS6.5设置Django开发环境

    2022-09-29 22:55:30
  • 客户端数据存储–超越cookies

    2008-01-15 13:01:00
  • 详解pytorch 0.4.0迁移指南

    2023-04-10 08:02:14
  • Jsp+Servlet实现文件上传下载 删除上传文件(三)

    2023-06-27 16:29:29
  • asp.net cookie清除的代码

    2023-07-19 15:24:37
  • asp之家 网络编程 m.aspxhome.com