Python基础学习08(返回、匿名函数,装饰器与偏函数)

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)

暂时就到这里了

猜你喜欢

转载自blog.csdn.net/weixin_43420243/article/details/86727041