Python基础学习08
ppt看完了10,
还剩11
本节内容较难,返回函数及闭包需要细细理解学习
返回函数
高阶函数将函数作为结果值返回
E.g 普通求和函数(返回值是一个数)
def calnum(*args):
ax=0
for n in args:
ax=ax+n
return ax
E.g举例
def laznum(*args):
def sum():
ax=0
for n in args:
ax=ax+n
return ax
return sum
>>>f=laznum(1,2,3,4)
>>>f
得到函数的名字
同样调用
>>>f1=laznum(1,2,3,4)
>>>f==f1
False 返回值的函数不同,每一次调用得到的函数的名字实际上是不一样的
其中的内容包含了 闭包
是一种程序结构
也就是 函数内部再定义一个函数,而内部的函数又引用外部函数的参数和局部变量
当 外部函数返回内部函数时,相关的参数和变量都保存在返回的函数中
闭包注意事项
E.g
>>>def count():
fs=[]
for i in range(1,4):
def f():
return i*i
fs.append(f)
return fs
>>>f1,f2,f3=count() 只能三个变量等于
>>>f1()
>>>f2()
>>>f3()
会发现f1(),f2(),f3()的值都是9
问题是以下需要注意的(闭包)
这个函数的返回值,是三个函数的名字,所以要用三个变量依次得到其名字。
返回闭包时
返回函数不要引用任何循环变量,或者后续会发生变化的变量
如果一定要引用循环变量,
需要再创建一个函数,用该函数的参数绑定循环变量当前的值,
无论该循环变量后续如何更改,已绑定到函数参数的值不变:
E.g
>>>def count():
def f(j):
def g():
return j*j
return g
fs=[]
for i in range(1,4):
fs.append(f(i))
return fs
>>>f1,f2,f3=count()
>>>f1() 1
>>>f2() 4
>>>f3() 9
上上个例子,返回函数包含在for循环内,该例子,返回函数和for循环分开来了。
匿名函数
无需显示定义函数
只能有一个表达式,不用写return,返回值就是表达式的结果
E.g
>>>list(map(lambda x:x*x,[1,2,3,4]))
[1,4,9,16]
匿名函数 具有函数的功能
可以赋给一个变量,再由变量调用,
可以当做返回值返回
装饰器(Decorator)
函数对象有一个__name__属性可以拿到函数的名字
E.g
>>>def now():
print('2019-2-2')
>>>f=now
>>>now.__name__
'now'
>>>f.__name__ 同理
如果要增强now()函数的功能,
比如,在函数调用前后自动打印日期,
但是又不希望更改now()函数的定义,
在代码运行期间动态增加功能的方式,称之为 装饰器
>>>def log(func): 括号内是被修饰的函数
def wrapper(*args,**kw): 普通的函数定义声明(可变参数,关键字参数)
print('call %s():'%func.__name__) 添加的功能(打印)
return func(*args,**kw) 正常的返回函数(调用被修饰的函数)
return wrapper 调用修饰后的函数
>>>@log
def now():
print('2019-2-2)
>>>now()
call now
2019-2-2
顾名思义,装饰器可以对函数进行修饰加工(添加功能)
接收一个函数作为参数,并返回一个函数,需要使用 @ 将decorator置于函数的定义处
之后,相当于执行语句now=log(now)
now()=log(now)()
如果decorator本身需要传入参数,那就需要写一个 返回 decorator 的高阶函数
因为,之前decorator参数默认为 需要被修饰 的函数
E.g
def log(text):
def decoraror(func):
def wrapper(*args,**kw):
print('%s %s():'%(text,func.__name__))
return func(*args,**kw)
return wrapper
return decorator
>>>@log('execute')
def now():
print('2019-2-2')
>>>now()
execute now():
2019-2-2
这个例子的修改到不难,就是原本的装饰器再外套一个函数用来接收参数而已
等价于
>>>now=log('execute')(now)
注意
经过decorator修饰后的函数,他们的名字发生了变化(第一个装饰器)
E.g
>>>now.__name__
'wrapper'
返回值就是wrapper函数名,
(变化的名字可能和装饰器的返回值函数名有关)
(添加的代码,也是写在作为返回值函数名的函数定义下)
所以,需要把原始函数的
__name__
属性复制到wrapper()函数中,
否则,有些以来函数签名的代码就会出错
(未知实例)
就是说 函数使用decorator装饰后,获取名字的那个属性会发生变化,可能会对一些依赖函数名字的函数/功能产生影响,因此,需要使用一些手段来避免这些事情
举例
不需要编写
wrapper.__name__=func.__name__
可以使用Python内置的functools.wraps来实现
E.g 一个完整的decorator
>>>import functools
>>>def log(func):
@functools.wraps(func) 增加的语句
def wrapper(*args,**kw):
print('call %s():'%func.__name__)
return func(*args,**kw)
return wrapper
加入参数,对应的decorator
E.g
>>>import functools
>>>def log(text)
def decorator(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print('%s %s():'%(text,func.__name__))
return func(*args,**kw)
return wrapper
return decorator
之后,按照前面的内容,正常使用即可。
一个完整的decorator,
除了需要增加的功能,还需要对函数名进行修改
偏函数
不同于数学上的偏函数,(我还没学到)
这个是functools模块中提供的 偏函数(partial function)
在设置函数参数的时候,偏函数可以帮助设置默认值,来降低使用难度
>>>int('123')
123
>>>int('123',base=8) base一般默认为10(进制)
83
当需要大量转换某进制的数字时,
functools.partial可以帮助我们创建一个偏函数,
就是把一个函数的某些参数给固定住(设置默认值),
返回一个新的函数,调用这个新函数会更简单。
E.g 不使用模块的
>>>def int2(x,base=2):
return int(x,base)
>>>int2('1000000')
64
>>>import functools
>>>int2 =functools.partial(int,base=2)
>>>int2('1000000')
64
>>>int2('1000000',base=10) 也可以传入新的参数
1000000
实际上,创建偏函数,可以接受
函数对象 *args **kw 三个参数
E.g.1
int2=functools.partial(int,base=2)
int2('10010')相当于
kw={'base':2} int('10010',**kw)
E.g.2
max2=functools.partial(max,10)
max2(5,6,7)相当于
args(10,5,6,7) max(*args)
暂时就到这里了