前言

执行以下代码

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. day34 并发编程之生产者消费者模型 队列

    1.守护进程(了解) """ 守护进程 表示 一个进程b 守护另一个进程a 当被守护的进程a结束后 那么b也跟着结束了 就像 皇帝驾崩 妃子殉葬 应用场景 之所以开启子进 ...

  2. 167. Two Sum II - Input array is sorted (Array)

    Given an array of integers that is already sorted in ascending order, find two numbers such that the ...

  3. 微信小程序——微信卡券的领取和查看

    这里大致介绍下微信卡券的一些常见问题,不再介绍具体技术了,相关接口详见微信卡券. 1. 会员卡跟卡券一样么? 这个是一样的,至少在前端是一样处理的,最多也就是卡券设置展示不同.对于微信卡券领取和查看的 ...

  4. 华为NB-IOT报告

    转 https://blog.csdn.net/np4rHI455vg29y2/article/details/78958137 [NB-IoT]华为NB-IoT网络报告(完整版) 2018年01月0 ...

  5. 通过DOS界面查看电脑上端口使用情况

    如何查看查看端口是否被占用? 打开电脑上的运行,输入cmd,进入DOS界面. 然后输入       netstat -an     即可显示电脑上所用的端口使用情况! 状态显示 LISTENING就表 ...

  6. Spring事务管理的四种方式(以银行转账为例)

    Spring事务管理的四种方式(以银行转账为例) 一.事务的作用 将若干的数据库操作作为一个整体控制,一起成功或一起失败.   原子性:指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不 ...

  7. java_24 FileOutputStream类和FileInputStream类

    1.OutputStream 和InputStream 输入和输出:1.参照物都是java程序来惨遭 2.Input输入,持久化上的数据---->内存 3.Output输出,内存--->硬 ...

  8. PAT 甲级 1002 A+B for Polynomials (25 分)

    1002 A+B for Polynomials (25 分) This time, you are supposed to find A+B where A and B are two polyno ...

  9. Linux module 添加到bashrc 和临时ifort编译器 以及python2和3的配置

    第一步vim ~/.bashrc按键盘的i然后source /home/export/online1/bjpara/para/modules/scripts/cn-module.sh最后:x! bas ...

  10. python入门之两种方法修改文件内容

    1.占硬盘修改 import os file_name="兼职.txt" new_file_name="%s.new".% file_name old_str= ...