前言

执行以下代码

def my_test():
x = 1
y = x+1 print(x) 》》
Traceback (most recent call last):
File "C:/Users/jingjing/PycharmProjects/py3Project/路飞/第二模块/函数练习/斐波那契.py", line 36, in <module>
print(x)
NameError: name 'x' is not defined

x在函数里面定义了,为什么会报错?

python解释器如何执行

"""
从python解释器开始执行之后,就在内存中开辟了一个空间 每当遇到一个变量的时候,就把变量名和值之间的对应关系记录下来。 但是当遇到函数定义的时候解释器只是象征性的将函数名读入内存,表示知道这个函数的存在了,至于函数内部的变量和逻辑解释器根本不关心。 等执行到函数调用的时候,python解释器会再开辟一块内存来存储这个函数里的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量会存储在新开辟出来的内存中。函数中的变量只能在函数的内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
"""

结论:“存放变量与值的关系”的空间——叫做命名空间

代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间,在函数的运行中开辟的临时的空间叫做局部命名空间

命名空间与作用域

命名空间的本质:存放变量与值的绑定关系

  •    全局命名空间:创建的存储“变量名与值的关系”的空间叫做全局命名空间
  •    局部命名空间:在函数的运行中开辟的临时的空间叫做局部命名空间
  •  内置命名空间:内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法。

三种命名空间之间的加载与取值顺序:

加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

使用:全局不能使用局部的,局部的可以使用全局的。
  

作用域

作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。

全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

局部作用域:局部名称空间,只能在局部范围生效

globals方法:查看全局作用域的名字【print(globals())】

locals方法:查看局部作用域的名字【print(locals())】

def func():
a = 12
b = 20
print(locals())
print(globals()) func()

global关键字,在函数内部修改全局变量的值(在多人协作开发时慎用)

a = 10
print('原始值',a)
def func():
global a
a = 20
print('函数修改值', a) func()
print('最终值',a) """
原始值 10
函数修改值 20
最终值 20 全局变量被修改
""" a = 10
print('原始值',a)
def func():
a = 20
print('函数修改值', a) func()
print('最终值',a) """
原始值 10
函数修改值 20
最终值 10 全局变量没有修改
"""

nonlocal关键字:在嵌套函数中,让内部函数中的变量在上一层函数中生效,外部必须有变量定义

a = 1
print('原始值',a)
def f1():
a = 2
print('进入f1内的打印', a)
def f2():
a = 5
def f3():
nonlocal a # 修改局部的(当用nonlocal时),global a 修改全局的
a = 100
print('f3内的打印',a)
f3()
print('离开f2内的打印', a) # nonlocal修改的值只对上一层函数(存在变量a被修改)的范围内有影响 ,此处只对f2有效
f2()
print('离开f1内的打印', a)
f1()
print('最终值', a) # nonlocal修改的值不影响全局的值 """
原始值 1
进入f1内的打印 2
f3内的打印 100
离开f2内的打印 100
离开f1内的打印 2
最终值 1
""" a = 1
print('原始值',a)
def f1():
a = 2
print('进入f1内的打印', a)
def f2():
# a = 5 取消修改,nonlocal会对f1有影响
def f3():
nonlocal a # 修改局部的(当用nonlocal时),global a 修改全局的
a = 100
print('f3内的打印',a)
f3()
print('离开f2内的打印', a) # nonlocal修改的值只对上一层函数(存在变量a被修改)的范围内有影响,此处对f2和f1有效,因为a在f1中被修改,在f2中没有变化
f2()
print('离开f1内的打印', a)
f1()
print('最终值', a) # nonlocal修改的值不影响全局的值 """
原始值 1
进入f1内的打印 2
f3内的打印 100
离开f2内的打印 100
离开f1内的打印 100
最终值 1 """

函数作用域查找顺序

LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__

  • locals 是函数内的名字空间,包括局部变量和形参
  • enclosing 外部嵌套函数的名字空间
  • globals 全局变量,函数定义所在模块的名字空间
  • builtins 内置模块的名字空间
level = 'L0'
n = 22
def func():
level = 'L1'
n = 33
print(locals()) def outer():
n = 44
level = 'L2'
print(locals(), n) def inner():
level = 'L3'
print(locals(),n) # 此外打印的n是多少?
inner()
outer() """
问题:在inner()里的打印的n的值是多少?44 取邻近函数outer中n=44
{'n': 33, 'level': 'L1'}
{'level': 'L2', 'n': 44} 44
{'level': 'L3', 'n': 44} 44
"""
func()

闭包

函数名的本质:就是函数的内存地址

def func():
print('func')
a = func
print(a)
"""
<function func at 0x0000000002357B70> # a指向了函数的内存地址
"""

函数名可以作为函数的返回值

def func():
print("func")
def func2():
print('func2')
return '返回func2'
return func2 # 函数名作为返回值 func2 = func() # 返回func2地址
print(func2)
print(func2())
"""
func
<function func.<locals>.func2 at 0x0000000002567840>
func2
返回func2
"""

闭包的定义:内部函数包含对外部作用域而非全局作用域变量的引用,该内部函数称为闭包函数

# 闭包的常用形式:
def func():
name = 'eva'
def inner():
"""闭包函数"""
print(name)
print(inner.__closure__) # 输出的__closure__有cell元素 :是闭包函数
return inner f = func()
f()
"""
(<cell at 0x0000000000510C48: str object at 0x0000000002558B90>,)
eva
"""

判断闭包函数的方法:__closure__

#输出的__closure__有cell元素 :是闭包函数
def func():
name = 'eva'
def inner():
print(name)
print(inner.__closure__)
return inner f = func()
f() #输出的__closure__为None :不是闭包函数,因为name为全局变量
name = 'egon'
def func2():
def inner():
print(name)
print(inner.__closure__)
return inner f2 = func2()
f2()

闭包获取网络应用

from urllib.request import urlopen

def outer():
url = "http://www.xiaohua100.cn/index.html"
def inner():
return urlopen(url).read()
return inner a = outer()
content = a()
print(content)

总结

作用域:小范围的可以用大范围的,但是大范围的不能用小范围的
范围从大到小(图)

如果在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有的,就用上上级的,以此类推
如果都没有,报错

函数作用域查找顺序:

LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> builtins

函数名的本质:

  就是一个变量,保存了函数所在的内存地址

闭包:

  内部函数包含对外部作用域而非全局作用域名字的引用,该内部函数称为闭包函数

 

   

Python函数——命名空间与闭包的更多相关文章

  1. python 函数名 、闭包 装饰器 day13

    1,函数名的使用. 函数名是函数的名字,本质就是变量,特殊的变量.函数名()加括号就是执行此函数. 1,单独打印函数名就是此函数的内存地址. def func1(): print(555) print ...

  2. python函数作用域,闭包,装饰器

    第一:函数作用域: L:local 函数内部作用域 E:enclosing       函数内部与内嵌函数之间(闭包) G:global            全局作用域 B:build_in    ...

  3. python函数对象和闭包

    关于函数对象和闭包 闭包(closure)是函数式编程的重要的语法结构.不同的语言实现闭包的方式不同.Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看 ...

  4. Python函数进阶:闭包、装饰器、生成器、协程

    返回目录 本篇索引 (1)闭包 (2)装饰器 (3)生成器 (4)协程 (1)闭包 闭包(closure)是很多现代编程语言都有的特点,像C++.Java.JavaScript等都实现或部分实现了闭包 ...

  5. python基础(7)-函数&命名空间&作用域&闭包

    函数 动态参数 *args def sum(*args): ''' 任何参数都会被args以元组的方式接收 ''' print(type(args)) # result:<class 'tupl ...

  6. Python之命名空间、闭包、装饰器

    一.命名空间 1. 命名空间 命名空间是一个字典,key是变量名(包括函数.模块.变量等),value是变量的值. 2. 命名空间的种类和查找顺序 - 局部命名空间:当前函数 - 全局命名空间:当前模 ...

  7. python 函数进阶与闭包

    函数的命名空间和作用域 引言 现在有个问题,函数里面的变量,在函数外面能直接引用么? def func1(): m = 1 print(m) print(m) #这行报的错 报错了: NameErro ...

  8. python 函数名,闭包

    1.函数名字的应用 函数名是什么? 函数名是函数的名字,本质:变量,特殊变量 函数名+() ———>执行此函数: 2.函数名的赋值: def func2(): print(44) f = fun ...

  9. python函数知识七 闭包、装饰器一(入门)、装饰器二(进阶)

    21.闭包 闭包:在嵌套函数内,使用非全局变量(且不使用本层变量) 闭包的作用:1.保证数据的安全性(纯洁度).2.装饰器使用 .__closure__判断是否是闭包 def func(): a = ...

随机推荐

  1. oracle可重复执行脚本(添加字段)

    --添加债券期限字段 declare cn integer; begin cn := 0; select count(*) into cn from user_tab_cols t where t.t ...

  2. Python: 下载底层由Python2转Python3环境更新手记

    谨记录运行环境改变过程中所碰到的坑. 下载底层运行环境由Python2移至Python3所遇到的问题及处理方法: 1.所引的第三方组件,基本都有替代支持:msvcr90.dll不再需要,有则报错2.引 ...

  3. java各历史版本官网下载

    java各历史版本官网下载: http://www.oracle.com/technetwork/java/javase/archive-139210.html

  4. 用<pre>预格式化的文本

    被包围在 <pre> 标签 元素中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. 提示: <pre> 标签的一个常见应用就是用来表示计算机的源代码.

  5. swift 设置阴影和圆角

    1.正常view设置阴影 func setShadow(view:UIView,sColor:UIColor,offset:CGSize, opacity:Float,radius:CGFloat) ...

  6. RobotFramework 模拟http接口登录自动化脚本

    RobotFramework 模拟自动化登录脚本思路: 先获取页面cookie值,然后根据cookie值加上请求体提交登录: 一.获取cookie: 以下脚本获取cookie值,并把改脚本封装为关键字 ...

  7. AUTEL MaxiSys MS908S Pro MS908SP Diagnostic Platform

    AUTEL MaxiSys MS908S Pro Description : One of the MaxiSys series devices, the MS908S Pro Diagnostic ...

  8. Calendar类常用需求方法

    经常处理一些日期相关的信息,Calendar类是处理日期的常用类,写下几个方法,不用重复造轮子了. 1.求上一天,下一天的日期 Date now = new Date();Calendar c = C ...

  9. 【Selenium】【BugList4】执行pip报错:Fatal error in launcher: Unable to create process using '""D:\Program Files\Python36\python.exe"" "D:\Program Files\Python36\Scripts\pip.exe" '

    环境信息: python版本:V3.6.4 安装路径:D:\Program Files\python36 环境变量PATH:D:\Program Files\Python36;D:\Program F ...

  10. 20175316盛茂淞 迭代和JDB

    迭代和JDB 题目 1 使用C(n,m)=C(n-1,m-1)+C(n-1,m)公式进行递归编程实现求组合数C(m,n)的功能 2 m,n 要通过命令行传入 3 提交测试运行截图(至少三张:正常如c( ...