学习目标:
Python学习九、
学习内容:
1、返回函数
2、匿名函数
3、装饰器
4、偏函数
1、返回函数
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回,当我们调用某一返回函数时,调用的不是结果而是函数
实现一个可变参数的求和
def lazy_sum(*args):
def sum():
ax = 0
for n in args:
ax = ax + n
return ax
return sum
f = lazy_sum(1, 3, 5, 7, 9)
print(f)
输出:
<function lazy_sum.<locals>.sum at 0x000001FEDE00A040>
调用函数f时,才真正计算求和的结果
print(f())
输出:
25
调用返回函数时,每次调用都会返回一个新的函数,即使传入相同的参数,调用结果也可能不同
- 闭包
返回的函数在其定义内部引用了局部变量,一个函数返回了一个函数后,其内部的局部变量仍被新函数引用锁定在内部函数中,这就叫闭包 - 一个函数在for循环里面,当它只是定义而没有调用时,是不会被运行的
def f()函数在for运行的过程中并未使用,而是到程序的print(f1()、print(f2()、print(f3()处时才调用f()函数,此时i已经是3了
def count():
fs = []
for i in range(1, 4):
def f():
return i*i
fs.append(f)
return fs
f1, f2, f3 = count()
print(f1()
print(f2()
print(f3()
输出:
9
9
9
闭包的作用:实现数据锁定,提高程序的稳定性,一般与装饰器一起使用
def count():
fs = []
for i in range(1, 4):
def f(i):
def a():
return i*i
return a
fs.append(f(i))
return fs
f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
输出:
1
4
9
- 实例:利用闭包返回一个计数器函数,每次调用它返回递增整数
def a():
f = []
def b():
f.append(1)
return len(f)
return b
i = a()
print(i())
print(i())
print(i())
print(i())
print(i())
输出:
1
2
3
4
5
2、匿名函数
关键字lambda表示匿名函数,冒号前面的x表示函数参数
匿名函数有个限制,就是只能有一个表达式
不用写return,返回值就是该表达式的结果
匿名函数没有名字,不必担心函数名冲突 传入
- 以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数
其中lamdba匿名函数就是 :
def f(x):
return x*x
for i in list(map(lambda x:x*x, [1, 2, 3, 4, 5])):
print(i)
输出:
1
4
9
16
25
- 匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数
def a(i,j,n):
print('i=',i)
print('j=',j)
print('i-j=',n(i,j))
a(10,9,lambda i,j: i - j)
输出:
i= 10
j= 9
i-j= 1
- 实例:用匿名函数输出20以内的奇数
一般方法:
def jishu(n):
return n%2==1
L = list(filter(jishu, range(1, 20)))
print(L)
输出:
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
匿名函数
L = list(filter(lambda x:x%2==1, range(1, 20)))
print(L)
输出:
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
3、装饰器
函数是一个对象,它也具有一些属性可以被改变,而且函数对象可以被赋值给变量,通过变量也能调用该函数
- 一个简单的求平方
def f(x):
return x * x
d = f
print(d(9))
输出:
81
__name__属性可以拿到函数的名字
def f(x):
return x * x
d = f
print(d.__name__)
输出:
f
- 在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator),本质上decorator就是一个返回函数的高阶函数
Python的@语法把函数放在需要运用的地方
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用
- 输出一万个hello world!!!,并显示运行时间个和个数
import time
def help(func):
def wrapeer(*args):
t1 = time.time()
rseult = func(*args)
t2 = time.time()
print('运行时间为:', t2-t1)
return rseult
return wrapeer
@help
def prinre(num):
count = 0
for i in range(1, num):
print('hwllo world!!!')
count = count +1
return count
count = prinre(10001)
print(count)
输出:
...(无数个hello world!!!)
hello world!!!
hello world!!!
hello world!!!
运行时间为: 0.05481886863708496
10000
- 函数的__name__等属性需要与开始的设定保持一致,所以要把调用函数f的属性复制到返回的函数wrapper中去
@functools.wraps(func):当没有这句代码时,print(f.name)返回的函数将是wrapper
import functools
def a(text):
def d(func):
@functools.wraps(func)
def wrapper(*args,**kw):
print('call %s %s():' % (text, func.__name__))
return func(*args,**kw)
return wrapper
return d
@a('excute')
def f():
print('2020-11-30')
print(f.__name__)
f()
输出:
f
call excute f():
2020-11-30
- 实例:求100以内的每个数的平方并且输出个数和运行所用的是时间
import time
import functools
def metric(fn):
@functools.wraps(fn)
def wrapper(*args):
t1 = time.time()
result = fn(*args)
t2 = time.time()
print('%s executed in %s ms' % (fn.__name__, t2-t1))
print('总个数是:%s 个' %result)
return wrapper
@metric
def fn(num):
count = 0
for i in range(1, num):
print('%s 的平方是:%s '% (i,i*i))
count = count +1
return count
fn(10001)
输出:
1 的平方是:1
2 的平方是:4
3 的平方是:9
4 的平方是:16
5 的平方是:25
6 的平方是:36
7 的平方是:49
8 的平方是:64
9 的平方是:81
10 的平方是:100
11 的平方是:121
...
9997 的平方是:99940009
9998 的平方是:99960004
9999 的平方是:99980001
10000 的平方是:100000000
fn executed in 0.05081439018249512 ms
总个数是:10000 个
4、偏函数
Python的functools提供偏函数(Partial function)这个功能,当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单
- 偏函数通过设定参数的默认值,可以降低函数调用的难度
int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换
print(int('12345'))
输出:
12345
int函数还可以提供base参数
print(int('12345',base=16))
或者
print(int('12345',16))
输出:
74565
为这种转换进制编写一个函数int2
def int2(x, base=2):
return int(x,base)
print(int2('1010110101'))
- functools.partial可以帮助我们创建一个偏函数,不需要我们自己定义int2(),可以利用functools创建函数int2
import functools
int2 = functools.partial(int,base=2)
print(int2('1010110101'))
输出:
693
- 在创建偏函数时参数可以接受函数对象、*args和**kw,并且偏函数在调用时可以传入自己需要的关键字参数
**kw:
kw = { ‘base’: 2 }
int(‘10010’, **kw) `
import functools
int2 = functools.partial(int,base=2)
print(int2('1010110101',base=10))
输出:
1010110101
- 偏函数实例:设计一个函数求a+b+c+d的值
def num(a, b, c, d=1):
return a+b+c+d
import functools
int2 = functools.partial(num,c=5)
print(int2(1,2))
输出:
9