发布时间:2018-03-29 20:53:58编辑:Run阅读(3790)
例子
def func(a,b,c,d,e,f,g):
pass
print(func(a, b , c, d, e, f, g))
如果再加30个参数呢?,在后面继续添加?有没有万能的参数,可以代表一切参数呢?
*args 动态参数,万能参数
args接收的就是实参对应的所有位置参数,并将其放在元组中,它不会接收关键字参数
例子
def func(*args): pass func(1,2,3,4,5,6,7,8,9)
执行没有报错
def func1(*args): print(args) func1(1,2,3,4,5,6,7,8,9)
执行结果是一个元组
(1, 2, 3, 4, 5, 6, 7, 8, 9)
形参对应顺序
错误的示例
def func(*args,a,b,c,d,e='sex'): print(args) print(a) print(b) print(c) print(d) func(1,2,3,4,5)
执行报错
TypeError: func() missing 4 required keyword-only arguments: 'a', 'b', 'c', and 'd'
因为*args接收了所有实参,所以缺少了a,b,c,d
形参对应顺序
#位置参数,*args,默认参数
正确的示例
def func(a,b,c,d,*args,e='男'): print(a) print(b) print(c) print(d) print(args) print(e) func(1,2,3,4,10,9,8,7,e='女')
执行结果
*args参数,可以不传,默认为空()
示例
def func(a,b,c,d,*args,e='男'): print(a) print(b) print(c) print(d) print(args) print(e) func(1,2,3,4,e='女')
执行结果
*args名字可以随便更改,args只是一个变量而已,但是约定默认使用的就是*args,建议不要更改
**kwargs
示例代码
def func(a,b,c,**kwargs): print(kwargs) func(1,2,3,r=4,s=5)
执行结果
**kwargs只接收关键字参数
**kwargs动态传参,他将所有的关键字参数放到一个字典中,返回的结果是一个字典,从前往后找
示例
def func(a,b,c,**kwargs): print(kwargs) func(1,2,3,r=4,b1=5,c1=6,d=7)
执行结果为
{'d': 7, 'c1': 6, 'r': 4, 'b1': 5}
**kwargs动态传参,他将所有的关键字参数(非位置对应的)放到一个字典中
示例
def func(a,b,c,**kwargs): print(kwargs) func(1,2,r=4,b1=5,c1=6,c=7)
执行结果
{'c1': 6, 'b1': 5, 'r': 4}
**kwargs动态传参,他将所有的关键字参数(无意义的)放到一个字典中
上面示例中的c参数,是有意义的
最终顺序:位置参数,*args,默认参数,**kwargs
例子:
def func(a,b,c,d,*args,e='男',**kwargs): print(a) print(b) print(c) print(d) print(args) print(e) print(kwargs) func(1,2,3,4,5,6,7,v=3,m=7,h=9,e='女')
执行结果
一般情况下,用这种方式就可以了
def func(*args,**kwargs): pass func()
查看python源码
*魔法运用
例子
def func(*args): print(args) l1 = [1,2,30] l2 = [1,2,33,21,45,66] func(*l1) func(*l1,*l2)
执行结果
在函数的调用时,*代表打散
例子2
def func(*args): print(args) l1 = [1,2,30] l2 = [1,2,33,21,45,66] tu = (1,2,3) func(*l1,*l2,*tu)
执行结果
(1, 2, 30, 1, 2, 33, 21, 45, 66, 1, 2, 3)
*就相当于迭代添加
在函数的调用时,*可迭代对象,代表打散(list,tuple,str,dict(键))
比如用到要传多个列表时,需要用到魔法运用
def func(*args): print(args) func(1,2,3,10,20,80)
执行结果
(1, 2, 3, 10, 20, 80)
在函数的调用执行时,*可迭代对象,代表打散
在函数定义时,*args代表的是聚合
将字典的键值对,添加到函数中
def func(**kwargs): print(kwargs) dic1 = {'name1':'sam','age1':16} dic2 = {'name2':'tom','age2':20} func(**dic1,**dic2)
执行结果
{'age1': 16, 'age2': 20, 'name1': 'sam', 'name2': 'tom'}
**kwargs只限于字典
在函数的调用执行时,
*可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args
**字典,代表打散,将所有键值对放到一个kwargs字典里
在函数定义时,*args,**kwargs代表的是聚合
def func(*args,**kwargs): print(args) print(kwargs) dic1 = {'name1':'sam','age1':18} dic2 = {'name2':'tom','age2':20} func(*[1,2,3,4],*'abcdef',**dic1,**dic2)
执行结果
(1, 2, 3, 4, 'a', 'b', 'c', 'd', 'e', 'f') #打散
{'name1': 'sam', 'age1': 18, 'name2': 'tom', 'age2': 20} #聚合
我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。
等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。
我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。
代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;
在函数的运行中开辟的临时的空间叫做局部命名空间。
命名空间和作用域
命名空间一共分为三种
全局命名空间
局部命名空间
内置命名空间
内置命名空间中存放了python解释器为我们提供的名字:input,print,str,list,tuple...它们都是我们熟悉的,拿过来就可以用的方法
三种命名空间之间的加载和取值顺序
加载顺序:内置命名空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载)
例子
def my_len(argv): return 666 print(len([12,3]))
执行结果,因为函数没有被调用,所以直接打印len里面列表的长度
2
取值顺序:
在局部调用:局部命名空间-->全局命名空间-->内置命名空间
在全局调用:全局命名空间-->内置命名空间
综上所述,在找寻变量时,从小范围,一层一层到大范围去寻找
例子
name = '张三' def func(): name = 'sam' print(name) func()
执行结果,程序运行中,从上到下加载,name的值被局部命名空间里的值覆盖了
sam
例子2
a = 2 print(a) def func(): age = 11 print(age) func()
执行结果
2
11
例子3
print(111) def func1(): print(333) def func2(): print(444) def func3(): print(555) func2() func1() print(222)
执行结果,从上往下执行,首先打印111,中间遇到了几个函数,只是暂存到内存中,并不执行,后面调用func1,从而打印333,下面的几个函数没有调用,所以不执行,最后打印222
111
333
222
例子4
print(111) def func1(): print(333) func2() print(666) def func2(): print(444) def func3(): print(555) func1() print(222)
执行结果,先手打印111,遇到func1-3函数暂存到内存中,遇到调用func1函数,打印出333,然后调用func2,打印444,这里注意,要等func2执行完成后,才会执行func1后面剩余的print(666),最后打印222
111
333
444
666
222
例子5
def f1(): def f2(): def f3(): print("in f3") print("in f2") f3() print("in f1") f2() f1()
执行结果,调用f1,先打印'in f1'在调用f2,打印'in f2'在调用f3,打印'in f3'
in f1
in f2
in f3
作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域
全局作用域:包含内置名称空间,全局名称空间,在整个文件的任意位置都能被引用,全局有效
局部作用域:局部名称空间,只能在局部范围内生效
globals和locals方法
globals:全局名称空间:所有变量
locals:局部名称空间:所有变量
例子
a = 2 b = 3 def func1(): c = 5 d = 6 print(globals()) #全局变量放在一个字典中 print(locals()) #局部变量(函数里的c,d)放在一个字典中 func1()
执行结果
例子2
a = 3 b = 5 def func1(): c = 6 d = 8 e = 10 print(globals()) #全局变量放在一个字典中 return locals() #局部变量(函数里的c,d,e)放在一个字典中 print(func1())
如果逻辑比较多,可以使用return locals() 查看函数所有局部变量,返回字典类型
global关键字,nonlocal关键字
global:
1 声明一个全局变量
2 在局部作用域想要对全局作用域的全局变量进行修改时,需要用到global(限字符串,数字)
例子1
def func1(): global name name = '你好' print(name) func1() print(name)
执行结果,在局部空间内,声明一个全局变量
你好
你好
例子2
name = '哈哈' def func1(): global name name = '你好' func1() print(name)
执行结果,因为函数func1里面声明使用全局变量name,对name的值进行了修改,所以最后打印的值是函数里面name的值
你好
例子3
def func1(): global a a = 5 func1() a = 4 print(a)
执行结果,代码从上至下执行,最后a=4把a的值覆盖了
4
对可变数据类型(list,dict,set)可以直接引用不用通过global
例子
li = [1,2,3] dic = {'a':'b'} def change(): li.append('a') dic['q'] = 'g' print(dic) print(li) change() print(li) print(dic)
执行结果,很明显,这里没有使用global声明,也可以直接添加
{'q': 'g', 'a': 'b'}
[1, 2, 3, 'a']
[1, 2, 3, 'a']
{'q': 'g', 'a': 'b'}
nonlocal
1 不能修改全局变量
2 在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用到哪层,从那层及父级或以下此变量全部发生改变。
错误例子
a = 4 def func1(): nonlocal a a = 5 func1() print(a)
执行报错
SyntaxError: no binding for nonlocal 'a' found
例子
def func1(): b = 6 def func2(): nonlocal b # b = 666 print(b) func2() func1()
执行输出
666
例子2
def add_b(): b = 42 def do_global(): b = 10 print(b) def dd_nonlocal(): nonlocal b b = b + 20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b()
执行结果
10
30
30
42
上一篇: python3--函数初识
47605
45985
36909
34469
29080
25713
24566
19714
19245
17756
5565°
6155°
5691°
5737°
6705°
5483°
5484°
5988°
5965°
7295°