python函数参数顺序_Python 中的参数深入、取值顺序、内置函数等

封面图片来源:沙沙野

内容概览动态参数

形参的顺序问题

名称空间与作用域

加载顺序

取值顺序

内置函数

高阶函数

关键字 global

关键字 nonlocal

动态参数前面文章提到,形参有三种:位置参数\默认参数\万能参数.其中万能参数又称动态参数,包括: args*kwargs

定义函数时,* 与 ** 表示函数的聚合

# 定义函数时,*/** 表示函数的聚合

def func(*args, **kwargs):

print(args) # (1, 2, 3)

print(kwargs) # {'name': 'Jane', 'age': 18}

func(1, 2, 3, name="Jane", age=18)

3. *的魔性用法

a, b, *args = [i for i in range(20)]

print(a) # 0

print(b) # 1

print(args) # [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

4. 调用函数时,* 与 ** 表示函数的打散

def func(*args):

print(args)

func(*[1, 2, 3], *(4, 5, 6), *"abc")

# 运行结果:

(1, 2, 3, 4, 5, 6, 'a', 'b', 'c')

def func(**kwargs):

print(kwargs)

func(**{"name": "Jane", "age": 16}, **{"sex": "female"})

# 运行结果:

{'name': 'Jane', 'age': 16, 'sex': 'female'}

def func(*args, **kwargs):

print(args)

print(kwargs)

func(*[1, 2, 3], *(4, 5, 6), *"abc", **{"name": "Jane", "age": 16}, **{"sex": "female"})

# 运行结果:

(1, 2, 3, 4, 5, 6, 'a', 'b', 'c')

{'name': 'Jane', 'age': 16, 'sex': 'female'}

5. 一个小细节

# 字典里的 key 不能是数字,必须是字符串

def func(*args, **kwargs):

print(args)

print(kwargs)

func(*[1, 2, 3], *(4, 5, 6), *"abc", **{1: "Jane", "age": 16})

# 运行结果:

Traceback (most recent call last):

File "test01.py", line 5, in

func(*[1, 2, 3], *(4, 5, 6), *"abc", **{1: "Jane", "age": 16})

TypeError: func() keywords must be strings

形参的顺序问题思考:假设有以下形参,该怎么排序才正确?a, b, c, sex="female", args,*kwargs

2. 位置参数一定要在默认参数的前面

def func(a, b, sex="female"):

print(a)

print(b)

print(sex)

func(1, 2, sex="male")

# 运行结果:

1

2

male

# 其实函数调用的时候,这里不用写明 sex="male",结果一样

def func(a, b, sex="female"):

print(a)

print(b)

print(sex)

func(1, 2, "male")

3. *args 要在位置参数和默认参数的中间

def func(a, b, *args, sex="female"):

print(a)

print(b)

print(args)

print(sex)

func(1, 2, "a", "b", sex="male")

# 运行结果:

1

2

('a', 'b')

male

4. **kwargs 要放在最后面

def func(a, b, *args, sex="male", **kwargs):

print(a)

print(b)

print(args)

print(sex)

print(kwargs)

func(1, 2, "a", "b", sex="female", name="Jane")

# 运行结果:

1

2

('a', 'b')

female

{'name': 'Jane'}

5. 总结形参的排序:

位置参数 > args > 默认参数 >*kwargs

名称空间与作用域名称空间① 程序开始运行时是逐行解释的,即从上往下执行代码

② 当遇到了初始化对象命令时,在内存中存放一个变量与值的对应关系的空间,这个空间称为『全局名称空间』

③ 如果程序走到一个函数时,看到函数的定义,会把函数名与函数体的对应关系在内存中存放一个命名空间,但是,里面没有任何东西

④ 当遇到函数调用时,会在内存中再开辟一个临时的名称空间,存放的是函数体里面的变量与值.注意,该名称空间会随着函数的结束而消失

⑤ 全局名称空间:存放的是 py 文件中变量与值的对应关系

⑥ 局部名称空间:临时存放比如函数体里面的变量与值的对应关系

⑦ 内置名称空间:内置函数及关键字等等

2. 作用域① 作用域,分为全局作用域和局部作用域

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

③ 局部作用域:局部名称空间

加载顺序① 所谓加载顺序,即加载到内存的顺序

② 内置名称空间 > 全局名称空间 > 局部名称空间

③ 解释器加载到内存中才能写代码,这个时候内置函数已经一起加进内存里,所以它是最先加载的

④ 接下来运行程序时,肯定是先加载全局名称空间

⑤ 遇到函数之类的代码块时才加载局部名称空间

取值顺序就近原则

def func():

name = "aaa"

print(name)

func() # aaa

name = "bbb"

def func():

name = "aaa"

print(name)

func() # aaa

# 上面的 print(name),其结果就是采用就近原则获取的

name = "bbb"

def func():

print(name)

func() # bbb

# 这个时候在函数内部找不到变量 name,于是在函数外部找到该变量及对应的值

2. LEGB 原则,也是就近原则

name = "bbb"

def func():

name = "aaa"

# print(name)

def inner():

name = "ccc"

print(name)

inner()

# print(name)

func()

# 这里根据就近原则得知,运行结果应该是 ccc

# 如果把 print(name) 放在 name = "aaa" 下面,则结果是:aaa

# 如果把 print(name) 放在函数外下面,则结果是:bbb

3. 总结取值顺序:

局部名称空间 > 全局名称空间 > 内置名称空间

内置函数 globals()、locals()① globals():返回一个字典,包含全局作用域的所有内容

② locals():也返回一个字典,包含当前作用域的内容

③ 注意:无论是加载顺序还是取值顺序,都是单向不可逆的!

name = "Jane"

age = 16

def func():

name = "John"

age = 18

print(globals())

print(locals())

# 运行结果:

{'__name__': '__main__',...

'__file__': 'test01.py', ...

'name': 'Jane', 'age': 16,

'func': }

{'__name__': '__main__', ...

'__file__': 'test01.py',...

'name': 'Jane', 'age': 16,

'func': }

name = "Jane"

age = 16

def func():

name = "John"

age = 18

print(globals())

print(locals())

func()

# 运行结果:

{'__name__': '__main__',...

'__file__': 'test01.py', ...

'name': 'Jane', 'age': 16,

'func': }

{'name': 'John', 'age': 18}

# 原因解析:这两个 print 函数都放在 func() 函数内了

# 所以 locals() 能把当前具体的局部作用域全部打印出来

name = "Jane"

age = 16

def func():

name = "John"

age = 18

def inner():

print(globals())

print(locals())

inner()

func()

# 运行结果:

{'__name__': '__main__',...

'__file__': 'test01.py', ...

'name': 'Jane', 'age': 16,

'func': }

{}

# 原因解析:locals() 返回的是当前作用域的内容

# 注意,所谓的『当前』,在这里就是指 inner() 函数内部

# 显然该函数内容啥也没有,因此返回的结果是一个空字典

高阶函数永远记住一点:代码是从上往下开始执行的!

def func1():

print(111)

def func2():

print(222)

func1()

def func3():

print(333)

func(2)

print(555)

func3()

print(666)

# 运行结果:

555

333

222

111

666

# 原因解析:先执行 print(555)

# 然后执行 fun3(),先执行 print(333),再执行 func2()

# 注意:此时 func3() 并没有结束运行,而是要等 func2() 执行完后才结束

# 此时执行 func2(), 先执行 print(222), 再执行 func1(),逻辑和上面的一样

# 当执行到 print(111) 之后,func1() 执行完毕,然后 func2() 跟着执行完毕

# 再是一开始执行的函数 func3() 执行完毕

# 最后才执行 print(666)

def wrapper():

print(111)

def inner():

print(222)

def func():

print(333)

print(444)

inner()

print(555)

wrapper()

# 运行结果:

111

444

222

555

# 原因解析:还是那句话!程序是从上往下开始执行的

# 首先执行 print(111),这个无争议

# 接下来,为什么是先执行 print(444) 不是先执行 inner() 呢?

# 原因很简单,因为它没有被调用!

# 等执行完 print(444) 后,inner() 被调用,然后开始执行该函数

# 发现该函数内部还有一个函数 func(),为什么它没被执行呢?

# 还是同样的原因,它始终没有被调用!

# 最后执行 print(555)

关键字 global当某个变量只存在局部名称空间时

def func():

name = "aaa"

func()

print(name)

# 运行结果

Traceback (most recent call last):

File "test01.py", line 5, in

print(name)

NameError: name 'name' is not defined

# 原因解析:name 在局部名称空间内

# 因此 print(name) 时找不到 name

# 这里一定要注意与上面的就近原则的一个示例的区别:

name = "bbb"

def func():

print(name)

func()

2. 使用 global 可以在局部声明一个变量

def func():

global name

name = "aaa"

func()

print(name) # aaa

# 原因解析:这里的 global name 表示这个局部名称空间的变量 name 对应的在全局名称空间也会同步

# 即相当于 func() 外有 name = "aaa" 这个变量与值的对应关系

3. 使用 global 后,局部变量的值改变了,全局的也跟着改变

def func():

global name

name = "aaa"

name = "bbb"

func()

print(name) # bbb

# 注意函数执行结束后,全局的变量指向的值在内存中还存在

# 所以 print(name) 才会有结果

4. 使用 global 后局部变量可以操控全局的同一个变量对应的值

name = "bbb"

def func():

global name

name = "aaa"

func()

print(name) # aaa

# 注意与这里的区别

name = "ccc"

def func():

global name

name = "aaa"

func()

print(name) # aaa

name = "bbb"

print(name) # bbb

5. 局部作用域不能对全局作用域的变量进行修改,只能引用

count = 1

def func():

count += 1

func()

# 运行结果:

Traceback (most recent call last):

File "test01.py", line 5, in

func()

File "test01.py", line 3, in func

count += 1

UnboundLocalError: local variable 'count' referenced before assignment

# 报错提示局部变量 count 还没声明就使用

6. 使用 global 之后,局部作用域就可以对全局作用域的变量进行修改

count = 1

def func():

global count

count += 1

print(count)

func() # 2

关键字 nonlocal该关键字只存在于 Python3 版本中,是子级对父级的操控。不能操控全局变量

name = "aaa"

def func():

nonlocal name

print(name)

func()

# 运行结果:

File "test01.py", line 3

nonlocal name

^

SyntaxError: no binding for nonlocal 'name' found

2. 内层函数可以引用外层函数的变量

def wrapper():

name = "aaa"

def inner():

print(name)

inner()

wrapper() # aaa

3. 内层函数只能引用外层函数的变量,不能对其改变

def wrapper():

name = "aaa"

def inner():

name += "bbb"

inner()

wrapper()

# 运行结果:

Traceback (most recent call last):

File "test01.py", line 7, in

wrapper()

File "test01.py", line 5, in wrapper

inner()

File "test01.py", line 4, in inner

name += "bbb"

UnboundLocalError: local variable 'name' referenced before assignment

4. 使用 nonlocal 之后内层函数能对外层函数的变量进行修改

def wrapper():

name = "aaa"

def inner():

nonlocal name

name += "bbb"

print(name)

inner()

wrapper() # aaabbb

5. 再次复习一遍 nonlocal 的用法,先目测下面代码执行后的结果再看解析

def wrapper():

name = "aaa"

def inner():

nonlocal name

name += "bbb"

print(name)

print("111", name)

inner()

print("222", name)

wrapper()

# 运行结果:

111 aaa

aaabbb

222 aaabbb

# 原因解析:首先 wrapper() 调用 wrapper 函数后

# 先执行 print("111", name). 此时 name 就是 name = "aaa" 对应的值,即打印结果是 111 aaa

# 然后 inner() 调用 inner 函数,内存函数的变量改变了外层函数的变量对应的值

# 此时 print(name) 时 name = "aaabbb", 即打印结果是 aaabbb

# 注意:外层函数的变量对应的值已经被内存函数的改变了

# 因此 print("222", name) 时,name = "aaabbb",故打印结果是 222 aaabbb

PS: 为了方便大家相互交流、解决学习过程中遇到的问题,我新建了一个 QQ 群,感兴趣的小伙伴加进来一起学习吧!~ (群号码:697678250,加群请备注:笔记)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值