python返回函数+匿名函数+装饰器+偏函数
函数作为返回值
可变参数的求和
可以不返回求和的结果,而是返回求和的函数:
不需要立刻求和,而是在后面的代码中,根据需要再计算
def sum_nums(*args):
sum = 0
for i in args:
sum = sum + i
return sum
def lazy_sum(*args):
def sum_nums():
ax = 0
for i in args:
ax = ax + i
return ax
return sum_nums
if __name__ == '__main__':
print(sum_nums(1, 2, 3, 4, 5)) #15
print(lazy_sum(1,2,3,4,5)) #<function lazy_sum.<locals>.sum_nums at 0x000001D547F8B6A8> 返回的是函数 运行的时候需要调用函数
f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
print(f1==f2)
#False
闭包
注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。
def fun():
print("hello")
def fun1(): # 作用域 运行时存活 函数执行期间
print("world") #想让fun1 调用 需要用 return fun1() / fun1
https://www.bilibili.com/video/av18586448?from=search&seid=6307915518193049229
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count() #9 9 9 经过初步的检验得出 存到 fs 是 三个 f 的 地址 已经有进行运行 所以 f1 f2 f3 只是让里面的函数进行运行
#ValueError: too many values to unpack (expected 2) 需要有三个函数输入并同时返回三个函数,等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9
#闭包
def count():
def fun1(j):
def fun2():
return j*j
print(j,fun2())
return fun2
ls = []
for i in range(1,4):
ls.append(fun1(i))
return ls
if __name__ == '__main__':
a,b,c = count()
print(a())
print(b())
print(c())
'''
1 1
2 4
3 9
1
4
9
'''
#计数器
def createCounter():
i = 0
def counter():
nonlocal i
i += 1
return i
return counter
匿名函数
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
装饰器
增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。
函数对象有一个__name__属性,可以拿到函数的名字
https://www.bilibili.com/video/av25698102/
https://www.jianshu.com/p/98f7e34845b5
https://v.youku.com/v_show/id_XNDMwNjczNjExMg==.html
import time
# 时间未加装饰器
def is_prime(x):
if x < 2 :
return False
elif x == 2 :
return True
else :
for i in range(2 , x):
if x % i == 0:
return False
return True
def print_nums():
a = time.time()
for i in range(2 ,10000 ):
if is_prime(i):
print(i)
b = time.time()
print(b-a)
if __name__ == '__main__':
print_nums()
改成时间的装饰器
def display_time(func):
def wrapper(): #包装:wrapper 其实这里可以替代为其他的名字
a = time.time()
func() # 只是装饰器就是这样的结构
b = time.time()
print(b - a)
return wrapper # 对其wrapper 这里返回wrapper 如果下面 print_nums不加括号 wrapper要加 反之不加
@display_time
def print_nums():
for i in range(2 ,10000 ):
if is_prime(i):
print(i)
if __name__ == '__main__':
print_nums()
继续变形
def display_time(func):
def wrapper():
a = time.time()
result = func() # 星星
b = time.time()
print(b - a)
return result
return wrapper
@display_time
def print_nums():
count = 0
for i in range(2 ,10000 ):
if is_prime(i):
count = count+1
return count # 星星 返回除去给func 后给 result
if __name__ == '__main__':
print(print_nums()) #调用即运行 后输出result 给 wrapper 就不会输出none
加参数的操作
def display_time(func):
def wrapper(*args): # 星星
a = time.time()
result = func(*args) # 星星
b = time.time()
print(b - a)
return result
return wrapper
@display_time
def print_nums(nums): # 星星
count = 0
for i in range(2 ,nums ): # 星星
if is_prime(i):
count = count+1
return count
if __name__ == '__main__':
print(print_nums(10000)) #调用即运行 后输出result 给 wrapper
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用
三层嵌套
import functools
def log (func):
#@functools.wraps(func) 有得话 house 无则 wrapper 消除装饰器的副作用
def wrapper():
return func()
return wrapper
@log
def house():
print(house.__name__)
house()
小结
在面向对象(OOP)的设计模式中,decorator被称为装饰模式。OOP的装饰模式需要通过继承和组合来实现,而Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。
decorator可以增强函数的功能,定义起来虽然有点复杂,但使用起来非常灵活和方便。
@functools.wraps(func) 消除副作用
偏函数
Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)
- int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换 int('123456')
- 但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换 int('123456 ' , base = 8) / ,16
functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数:
import functools
int2 = functools.partial(int , base = 2)
print(int2('11101'))
当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。