这一次主要是学习了一下Python3函数式编程思想,介绍了3个代表性高阶函数:map(), reduce(), filter()。像 sorted() 其实也是高阶函数,可以接受函数作为参数。这篇学习笔记中编写了大量高阶函数,同时介绍了Python中的闭包,装饰器。这些思想和方法很美妙,我受益匪浅。当然这些都需要进一步运用和学习。
运行环境:Python3.6 + Jupyter notebook
函数式编程¶
函数作为参数¶
def add(x, y, f):
return f(x) + f(y)
add(-1, 1, abs)
map¶
map()作为高阶函数,它将运算规则抽象了。
r = map(lambda x: x*x, [1, 2, 3, 4])
list(r)
reduce¶
from functools import reduce
def prod(List,f):
return reduce(f, List)
def f(x, y):
return x * y
prod([1,2,3], f)
str2int¶
from functools import reduce
num = {}
for i in range(10):
num[str(i)] = i
def str2int(string:str) -> int:
return reduce(lambda x, y: x*10 + y, map(char2num, string))
def char2num(s):
return num[s]
str2int(‘123‘)
type(str2int(‘123‘))
str2float¶
from functools import reduce
num = {}
for i in range(10):
num[str(i)] = i
def char2num(s):
return num[s]
def str2float(string):
s = string.split(‘.‘)
f1 = lambda x, y: x * 10 + y
f2 = lambda x, y: x * 0.1 + y
return reduce(f1, map(char2num, s[0])) + 0.1 * reduce(f2, map(char2num, s[-1][::-1]))
str2float(‘1.234‘)
type(str2float(‘1.234‘))
filter¶
利用filter() 求素数(埃氏筛法)
def odd_iter():
n = 1
while True:
n += 2
yield n
def prime():
yield 2
it = odd_iter()
while True:
n = next(it)
yield n
it = filter(lambda x: x % n > 0, it)
for i in prime():
if i < 20:
print(i, end=‘ ‘)
else:
break
返回函数¶
def lazy_sum(*args):
def sum():
ax = 0
for arg in args:
ax += arg
return ax
return sum
f = lazy_sum(1, 2, 3)
f
f()
我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
闭包¶
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()
注:闭包返回的函数并没有立刻执行,而是直到调用了f()才执行。
<font color = red>返回函数不要包含任何循环变量,或者后续会发生变化的变量。</font>
如果一定要引入循环变量呢?方法是在 count() 中调用 f(),从而绑定循环变量当前值。
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(), f2(), f3()
example¶
def creat_counter():
def g():
n = 1
while True:
yield n
n += 1
it = g()
def counter():
return next(it)
return counter
counterA = creat_counter()
counterA()
counterA()
注:creat_counter() 作为一个计数器函数。
转换简单的类为闭包¶
class sample:
def __init__(self,value):
self.value = value
def func(self):
print(‘n = ‘, self.value)
def get_value(self):
return self.value
def set_value(self,new_value):
self.value = new_value
test = sample(1)
test.func()
def sample(n):
value = n
def func():
print(‘n = ‘, value)
def get_value():
return value
def set_value(new_value):
nonlocal value
value = new_value
func.get_value = get_value
func.set_value = set_value
return func
test = sample(1)
test()
test.get_value()
test.set_value(5)
test()
注:将 get_value() 和 set_value() 作为函数 func()的属性,然后利用闭包返回 func() 函数
参考:访问闭包中定义的变量,里面有进一步内容。
装饰器¶
def now():
print(‘2018/2/20‘)
now.__name__
现在希望增加 now() 函数的功能,但不改变他的定义,这种在代码运行期间动态增加功能的方式,称之为装饰器(Decorator)。
本质上,decorator 就是一个返回函数的高阶函数。下面,我们定义一个打印日志的 decorator。
def log(func):
print(‘call {}‘.format(func.__name__))
log(now)
但是这样就显式调用了 log(),说白了是两个函数
def log(func):
def wrapper(*args, **kw):
print(‘call {}‘.format(func.__name__))
return func(*args, **kw)
return wrapper
now = log(now)
now()
以上就实现了打印日志的 now() 函数,同时会调用 now() 函数实现功能。
@log
def now():
print(‘2018/2/20‘)
now()
注:@log 相当于执行语句:
now = log(now)
log()就是一个 decorator,它返回 wrapper() 函数,执行 @log 后,wrapper 赋值给 now,再次执行 now() 后,我们会执行 wrapper() 函数,打印日志,然后执行原来的 now() 函数。
下面进一步。自定义日志内容
大致思想是下面两条语句:
now = log(‘text‘)(now)
now()
写一个3层嵌套的 decorator:log(‘text‘) 返回一个函数,返回相当于上一个例子的 log() 函数。
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print(‘{0}{1}():‘.format(text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
def now():
print(‘2018/2/20‘)
now = log(‘execute‘)(now)
now()
用法如下:
@log(‘execute‘)
def now():
print(‘2018/2/20‘)
now()
但是有一个问题:
now.__name__
由于最后返回的是 wrapper 函数,因此 now 的 __name__ 属性就是 ‘wrapper‘。
完整代码:
例一:
import functools
def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print(‘call {}‘.format(func.__name__))
return func(*args, **kw)
return wrapper
@log
def now():
print(‘2018/2/20‘)
now()
now.__name__
例二:
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print(‘{0}{1}():‘.format(text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
@log(‘execute‘)
def now():
print(‘2018/2/20‘)
now()
now.__name__
最后,写一个打印函数执行时间的decorator
import time, functools
def meric(func):
@functools.wraps(func)
def wrapper(*args, **kw):
start = time.time()
result = func(*args, **kw)
end = time.time()
print(‘{} executed in {} ms‘.format(func.__name__, end - start))
return result
return wrapper
@meric
def test(x, y):
time.sleep(0.1)
return x + y
test(1,2)