函数
动态参数
-
*args
def sum(*args): ''' 任何参数都会被args以元组的方式接收 ''' print(type(args)) # result:<class 'tuple'> sum = 0 for i in args: sum += i return sum print(sum(1, 2, 3)) # result:6 print(sum(*[1, 2, 3])) # result:6 # 12,13行等价 # * 表示将这个列表按照顺序打乱传入
-
**kwargs
def info(**kwargs): ''' 参数都会被kwargs以字典的方式接收 :param kwargs: :return: ''' print(type(kwargs)) # result:<class 'dict'> for key in kwargs: print(key, kwargs[key], end=' ') print() info(name='张三', age=12, gender='男') info(**{'name': '李四', 'age': 14, 'gender': '女'}) # ** 将字典按顺序打乱传入 # result: name 张三 age 12 gender 男 # name 李四 age 14 gender 女
默认参数
-
通过默认参数输出
def name_sex_print(name, sex='男'): print('姓名:{},性别:{}'.format(name, sex)) name_sex_print('小强') name_sex_print('小兵') name_sex_print('小红', '女') # result: # 姓名:小强,性别:男 # 姓名:小兵,性别:男 # 姓名:小红,性别:女
-
默认参数陷阱
def num_print(num_list=[]): num_list.append(1) print(num_list) num_print() num_print([]) num_print() num_print() # result: # [1] # [1] # [1, 1] # [1, 1, 1]
结论:如果默认参数的值是一个可变数据类型,那么每一次调用函数的时候,如果不传值就公用这个数据的资源
函数的引用
函数名实际上可以看做指向函数在内存中的引用(和C#中委托很相像)
-
赋值
def func1(): print('print in func1') func2 = func1; func2() #result: # print in func1
-
函数的传递
def func1(): print('print in func1') def func2(func): print('print in func2') func() func2(func1) # result: # print in func2 # print in func1
命名空间
命名空间的概述
-
内置命名空间
1.python解释器一启动就可以使用的变量及函数存放在内置命名空间内
2.内置的变量及函数在启动解释器的时候被加载进内存里
3.不能使用局部和全局命名空间的函数及变量
-
全局命名空间(自己写的非函数内部的代码)
1.是在程序从上到下被执行的过程中依次加载进内存的
2.放置了我们设置的所有变量名和函数名
3.可以使用内置命名空间但不能使用局部命名空间中定义的变量及函数
-
局部命名空间
1.定义在函数内部
2.当调用函数的时候,才会产生这个名称空间,随着函数执行的结束,这个命名空间就又消失了
3.可以使用全局及内置命名空间中的定义的变量及函数
三种命名空间的加载与取值顺序
-
加载顺序
内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:函数调用时才加载)
-
取值顺序
局部命名空间->全局命名空间->内置命名空间
作用域
作用域概述
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域
-
全局作用域
包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效
-
局部作用域
局部名称空间,只能在局部范围(函数内部)生效
查看局部变量和全局变量
使用locals()和globals()函数可查看局部和全局变量
-
locals()
def locals_func(): b = 2 c = 3 print(locals()) locals_func() # result: # {'b': 2, 'c': 3}
-
globals()
a=1 b=2 print(globals()) #result: # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000000001D67208>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/learning/python/test/0828/locals.py', '__cached__': None, 'a': 1, 'b': 2}
作用域链
-
就近原则
在函数内部使用一个变量时,会由近到远(由内而外)查找同名变量
str = 'in globals' def fun1(): str = 'in locals func1' def func2(): str = 'in locals func2' print(str) func2() fun1() # result: # in locals func2
str = 'in globals' def fun1(): str = 'in locals func1' def func2(): # str = 'in locals func2' print(str) func2() fun1() # result: # in locals func1
str = 'in globals' def fun1(): # str = 'in locals func1' def func2(): # str = 'in locals func2' print(str) func2() fun1() # result: # in globals
-
nonlocal关键字
使用要求:
1.外部(非全局)必须有这个变量
2.在内部函数声明nonlocal变量之前不能再出现同名变量
def func1(): a = 1 def func2(): nonlocal a a = 2 func2() print(a) func1() # result:
闭包
闭包函数的定义
内部函数包含对外部作用域而非全局作用域名字的引用,该内部函数称为闭包函数
def outer(): a = 1 def inner(): print(a) return inner func = outer() func()
闭包函数的判断
可通过函数的__closure__属性判断该函数是否是一个闭包函数,若返回不是None,则就是闭包函数
def outer(): a = 1 def inner(): b = a print(inner.__closure__) inner() outer() print(outer.__closure__) #result: # (<cell at 0x0000000000410108: int object at 0x000007FED797D420>, <cell at 0x0000000001DC82E8: function object at 0x00000000021CA730>) # None
闭包的优缺点
-
优点
1.能够读取函数内部的变量
2.让这些变量一直存在于内存中,不会在调用结束后,被垃圾回收机制回收
-
缺点
1.由于闭包会使函数中的变量保存在内存中,内存消耗很大,所以不能滥用闭包,解决办法是,退出函数之前,将不使用的局部变量删除