疫情环境下的网络学习笔记 python 3.19

3.19

回顾

  1. python中所有传递的值,都不是值本身,而是值的引用,即内存地址,所以也称作引用传递

  2. 函数两大类:内置函数,自定义函数

  3. 什么是形参,什么是实参:

    实参:变量值,形参:变量名

  4. 位置形参:从左到右依次写下来,必须被传值

  5. 默认形参:定义阶段已经为其赋值,调用的时候可以不用被其赋值。默认形参赋值的内容应该是不可变的

    函数的运行不应该受外界代码的干扰

    需求默认形参是可变值的时候可以默认赋值为none,再在函数体内判断

  6. 位置实参:从左到右顺序,一一对应传给对应的位置形参或默认形参

  7. 关键字实参:可以打乱顺序,指名道姓地对一个形参赋值

    必须在位置实参后面,不能重复对形参赋值

  8. * 在形参中,可以接收溢出的位置实参和溢出的关键字实参

    溢出的位置实参保存成元组赋值给 *args,溢出的关键字实参保存成字典赋值给 **kwargs

  9. *,**在实参中用于打散,*打散一个个元素,分别跟位置形参对应

    **打散字典成关键字实参

  10. # 很重要
    def index(x,y,z):
    	print(x,y,z)
    	
    def wrapper(*args,**kwargs):
    	index(*args,**kwargs)
    	
    wrapper(1,y=2,z=3)
    # x:溢出的位置实参,转成元组传入args。y,z:溢出的关键字实参,转成字典传入kwargs
    # index中 *将args打散,元组转回成x,**打散kwargs,字典转回成关键字
    # 最终wrapper的格式会转嫁给index
    

    将本来传给wrapper的格式原封不动地传给其中调用的函数index

    给wrapper传的参数格式要遵循 index的参数格式

今日内容

  1. 函数参数补充

    命名关键字参数

    组合使用

  2. 名称空间与作用域

    三种名称空间的用途与生命周期

    三种名称空间的加载顺序

    三种名称空间查找名字的优先级

  3. 作用域

    global

    local

    嵌套使用的情况下,作用域与名字的查找关系

  4. 函数对象

  5. 闭包函数

正课

命名关键字参数

在定义函数时,* 后面的参数,如下所示,称之为命名关键字形参

def func(x,y,*,a,b): # a,b为命名关键字参数
	print(x,y)
	print(a,b)
    
func(1,2,a=1,b=2)
  1. 命名关键字实参必须按照 key = value的形式为其传值

    强制让函数的使用者用key = value格式传值

  2. 在定义的时候给命名关键字参数赋默认值,可以在调用的时候不传

组合使用

形参中定义的顺序:

  • 位置形参,默认形参,*args(溢出的位置形参),命名关键字形参,**kwargs(溢出的关键字形参)

    def func(x,y=111,*args,z,**kwargs)
    

实参中调用的顺序:

  • 位置实参,*(),关键字实参,**{}

    def func(x,y,z,a,b,c):
        print(x)
        print(y)
        print(z)
        print(a)
        print(b)
        print(c)
    
    func(111,*(3333,4444),b=555,**{'c':666,'a':222})
    

名称空间

名称空间是内存中的一个空间,用来存放名字,是对栈区的划分

原来讲的概念里,变量名存放在内存中的栈区。现在将栈区再细分,把同类的变量名分为一片,就是名称空间

划分名称空间后,给所有的名字分门别类存放,且避免了相同的名字被覆盖的情况,可以在不同的名称空间内使用同样的名字不互相冲突

当查找名字的时候,有优先级

全局范围:内置名称空间,全局名称空间

局部范围:局部名称空间

内置名称空间

  • 存放的名字:

    存放python解释器内置的名字,内置的函数名,如print,int

  • 存活周期:

    python解释器启动则产生,python解释器关闭则销毁

全局名称空间

  • 存放的名字:

    只要不是函数内定义,也不是内置的,剩下的都是全局名称空间

    x = 10  # 如定义顶级代码中的变量名
    import os  #引入的模块名
    def func():  # 定义的函数名
    class foo:  # 定义的类名
    
  • 存活周期:

    python程序运行的时候产生,运行完成后销毁

    运行python程序刚刚开始运行的时候就产生,在执行到需要存名字的地方,如果名字不是局部或内置,则都丢到全局空间里

局部名称空间

  • 存放的名字:
    在调用函数时,运行函数体代码过程中产生的函数内的名字

  • 存活周期:

    调用函数时产生,函数调用结束则销毁。可能有多个函数同时运行,所以有多个名称空间同时存在,调用开始创建,调用结束就销毁

    调用同一个函数多次,也会产生多个不同的局部名称空间

加载顺序,销毁顺序

加载顺序:

  • 内置名称空间 > 全局名称空间 > 局部名称空间
  • 内置和全局一定有,局部不一定有

销毁顺序:

  • 局部 > 全局 > 内置
  • 先退出函数,再关闭文件,最后关闭解释器

名称空间不是真实存在的东西,像国家,只是用来将名字进行分类。真正用于存放的东西是栈区

名字的查找顺序

从当前所在的位置向上一层一层找

内置         👆
全局         👆
局部2        👆
	局部1    👆
# 名称空间是没有包含关系的,为了便于理解,可以看作包含关系,内置<全局<内置

如果当前在局部名称空间,则先在局部名称空间找,找不到则去全局名称空间找,还找不到最后去内置名称空间找

如果当前在全局名称空间,则先在全局名称空间找,找不到最后去内置名称空间找

最后都找不到,则报错

# 例子
def func():
	input = 111
	print(input)
input = 222	
func()

名称空间的”嵌套“ 关系是以函数定义阶段为准,与调用位置的嵌套关系无关,不是从头顶上找

  • 例1

    x = 1
    def func():    
        print(x)  # 局部找不到,去全局找,找到x = 1
    def foo():    
        x = 222    
        func()  # 与调用无关,只与定义有关,所以这里x =222 不影响    foo()# 输出 1
    
  • 例2 函数套用定义的情况

    input=111
    def f1():
        def f2():
            # input=333
            print(input)  # 在局部找不到 input,则去上一层局部找,在f1这一层局部中找到 input=222
        input=222  #假如这里也被注释,那么会再去上一层全局名称空间中找,找到 input=111
    
        f2()
    
    f1()
    
  • 例3

    x = 111
    def func():
    	print(x)
    	x = 222  # 报错:变量x在定义前被使用
    	
    func()
    

作用域

全局作用域

全局作用域:内置名称空间,全局名称空间

  1. 全局存活
  2. 全局有效:被所有函数共享,在无论哪里都可以被访问到

局部作用域

局部名称空间中的名字

  1. 临时存活
  2. 局部有效:函数内有效

顺序也可以记为LEGB:

  • local,enclosing,global,built in

global与nonlocal关键字

global

如果在局部想要修改全局的名字对应的值(不可变类型),用 global + 全局变量名

x = 111
def func():
	global x  # 声明 x 是全局的名字,不用再在局部造新的名字
	x = 222
	
func()
print(x)

如果不用关键字,则会在局部产生新的值,与上一层的全局变量没有关系

对于可变类型,不需要用这些关键字操作,直接改就行

nonlocal (了解)

当存在局部名称空间”嵌套“的情况

x = 0
def f1():
	x = 11
	def f2():
		nonlocal x
		x = 22
	f2()
	print('f1内的x:',x)
	
f1()

从当层空间的外层开始找关键字之后的变量名,找到最外层的局部名称空间,找到了就操作这个值,找到全局作用域还没找到就报错

posted @ 2020-03-19 18:46  黑猫警长紧张  阅读(176)  评论(0)    收藏  举报