–
变量f现在已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同 f = abs f(-10) 10 函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数 既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。 def add(x, y, f): return f(x) + f(y) 当我们调用add(-5, 6, abs)时,参数x,y和f分别接收-5,6和abs,根据函数定义,我们可以推导计算过程为: def add(x, y, f): return f(x) + f(y) x, y = -5, 6 sum = add(x, y, abs) print(sum) map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。 比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下 def f(x): return x*x r = map(f, list(range(10))) print(list(r)) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算, 如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场 from functools import reduce def fn(x, y): return x * 10 + y reduce(fn, [1, 3, 5, 7, 9]) 13579 str2int的函数就是: from functools import reduce DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9} def str2int(s): def fn(x, y): return x * 10 + y def char2num(s): return DIGITS[s] return reduce(fn, map(char2num, s)) Python内建的filter()函数用于过滤序列。 filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。 在一个list中,删掉偶数,只保留奇数 def is_odd(n): return n % 2 == 1 list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) # 结果: [1, 5, 9, 15] 生成器示例,这里生成器可以直接作为filter的参数,可以理解为就是list def _odd_iter(): n = 1 while n<100: n = n + 2 yield n def _not_divisible(n): return lambda x: x % n > 0 it = _odd_iter() n =2 a = filter(_not_divisible(n), [2,3,4,5,6,7,8,9]) # 构造新序列 print(list(a)) b = filter(_not_divisible(n), it) # 构造新序列 print(list(b)) 我们给sorted传入key函数,即可实现忽略大小写的排序: >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower) ['about', 'bob', 'Credit', 'Zoo'] 要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True: >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True) ['Zoo', 'Credit', 'bob', 'about'] 从上述例子可以看出,高阶函数的抽象能力是非常强大的,而且,核心代码可以保持得非常简洁。 闭包 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) f() 在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时, 相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure) @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2 返回的函数并没有立刻执行,而是直到调用了f()才执行 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!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。 匿名函数 关键字lambda表示匿名函数,冒号前面的x表示函数参数 匿名函数lambda x: x * x实际上就是: def f(x): return x * x 也可以起个名字 f = lambda x: x * x >>> f <function <lambda> at 0x101c6ef28> >>> f(5) 25 装饰器 函数对象有一个__name__属性,可以拿到函数的名字 如果要在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。 本质上,decorator就是一个返回函数的高阶函数。所以,我们要定义一个能打印日志的decorator,可以定义如下: def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper 观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处: @log def now(): print('2015-3-25') 调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志: >>> now() call now(): 2015-3-25 把@log放到now()函数的定义处,相当于执行了语句: now = log(now) 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂 def log(text): def decorator(func): def wrapper(*args, **kw): print('%s %s():' % (text, func.__name__)) return func(*args, **kw) return wrapper return decorator 这个3层嵌套的decorator用法如下: @log('execute') def now(): print('2015-3-25') 执行结果如下: >>> now() execute now(): 2015-3-25 上面的原理是这样的: >>> now = log('execute')(now) 设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间 import functools,time def metric(fn): @functools.wraps(fn) def wrapper(*args, **kw): t0 = time.time() result = fn(*args, **kw) print('%s executed in %.4f ms' % (fn.__name__, time.time() - t0)) return result return wrapper @metric def fast(x, y): time.sleep(0.0012) return x + y @metric def slow(x, y, z): time.sleep(0.1234) return x * y * z print(fast(11, 22)) print(slow(11, 22, 33)) #fast executed in 0.0020 ms #33 #slow executed in 0.1244 ms #7986 示例中 def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper 返回函数,而上面的例子返回了一个值,该怎么理解!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 偏函数 简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。 def int2(x, base=2): return int(x, base) 这样,我们转换二进制就非常方便了: >>> int2('1000000') 64 上面的方式可以简化 >>> import functools >>> int2 = functools.partial(int, base=2) >>> int2('1000000') 64 >>> int2('1010101') 85
–
评论前必须登录!
注册