在 Python 中,函数是一等对象。编程语言理论家把“一等对象”定义为满足下述条件的程
序实体:
• 在运行时创建
• 能赋值给变量或数据结构中的元素
• 能作为参数传给函数
• 能作为函数的返回结果
把函数视为对象
在python中一切皆对象,那么函数自然也是对象。
1 #定义一个求阶乘的函数 2 def fact(n): 3 """ 4 return n! 5 """ 6 return 1 if n <=1 else n*fact(n-1) 7 print(fact(10)) 8 print(fact) 9 print(fact.__doc__)#函数拥有__doc__属性 10 print(type(fact)) #函数是<class 'function'>, fact是function类的对象 11 12 f = fact #函数名可以被引用 13 print(f is fact) 14 15 #函数作为参数传递 16 def g(func): 17 print("function [%s] as argument" % func.__name__) 18 return None 19 20 #函数可以作为返回值被返回 21 def h(): 22 print("return a function") 23 return fact 24 25 g(fact) 26 print(h()(10))
明白了函数是对象后,就可以使用函数式风格编程。函数式编程的特点之一就是使用高阶函数。
高阶函数
什么是高阶函数?
接收函数作为参数或者把函数作为返回值返回的函数就是高阶函数。例如我们上面定义的函数g和函数h都是高阶函数。许多python内置的函数也是高阶函数,如sorted,map,filter等。
sorted、map、reduce、filter都接收一个函数作为参数。
1 fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana'] 2 #sorted的key参数接收一个函数作为参数,按照长度排序 3 f = sorted(fruits, key=len) 4 print(list(f)) 5 6 def reverse(s): 7 return s[::-1] 8 #按照单词逆序进行排序 9 f = sorted(fruits, key=reverse) 10 print(list(f)) 11 12 from operator import mul 13 from functools import reduce 14 s = reduce(mul, range(1, 11), 1) 15 print(s) 16 17 #定义一个函数判断是否字符串长度大于6 18 def len_gt6(s): 19 return len(s) > 6 20 f = filter(len_gt6, fruits) 21 print(list(f)) 22 23 #把fruits全部变成大写 24 f = map(str.upper, fruits) 25 print(list(f))
补充:reduce的思想是把某种操作连续的应用到序列的元素上,累计之前的结果,最后规约成一个值。
类似的还有all和any。
all(iterable)
如果iterable的每个值都为真,结果返回True;否则返回False
any(iterable)
只要iterable中有一个元素为真,返回True;否则返回False
1 all(range(10)) #False, 0被认为是False 2 all(range(1, 10))#True 3 4 any(range(10)) #True 5 any([0 for i in range(10)]) # False
lambda匿名函数
lambda关键字用于在python中创建匿名函数。
lambda函数的定义只能使用表达式,这就意味着匿名函数不能赋值、不能使用try、while等语句。
事实上,lambda函数除了作为高价函数的参数和返回值之外,python较少使用匿名函数。因为语法的限制导致了复杂的lambda表达式要么难以理解,要么无法实现。
1 #计算每个元素的立方 2 f = map(lambda x:x**3, (i for i in range(10))) 3 print(list(f)) 4 5 #奇数项计算元素的立方,偶数项计算元素的平方 6 f = map(lambda x:x**3 if x%2 else x**2, (i for i in range(10))) 7 print(list(f))
可调用对象
可调用对象就是可以使用()运算符的对象。可以通过内置的callable()函数判断对象是否是可调用的。
包含:
1、自定义函数
2、内置函数
3、内置方法
4、方法
5、类
6、类的实例(实现了__call__方法)
7、生成器函数
1 class Foo(object): 2 def __call__(self, *args, **kwargs):#args和kwargs是可选参数和关键字参数 3 print("i am a callable object") 4 pass 5 6 f = Foo() 7 print(callable(f)) 8 f()
实现了__call__方法的类是创建函数对象的简单方式。
支持函数式编程的包
python得益于operator和functools等包的支持,进行函数式编程也很方便。
operator模块
operator模块为多种算术运算符提供了对应的函数,如上面的add,mul等。
此外,operator模块中还有一类函数,能够从序列类型或者对象中读取元素或者属性的方法。
itemgetter和attrgetter的用法。
1 from operator import itemgetter, attrgetter 2 from collections import namedtuple 3 metro_data = [ 4 ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)), 5 ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)), 6 ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)), 7 ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)), 8 ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)), 9 ] 10 11 #按照人口对城市进行排序 itemgetter(i) 等价于obj[i] 12 for city in sorted(metro_data, key=itemgetter(2)): 13 print(city) 14 15 #itemgetter也可以接收多个参数,返回一个由取到的值构成的元组 16 tup = itemgetter(0,1,3) 17 for city in sorted(metro_data, key=itemgetter(2)): 18 print(tup(city)) 19 20 Card = namedtuple('Card', "rank suit") 21 Pocker = namedtuple('Pocker', "width height card") 22 23 print("-------------------------------------") 24 PockerCards = [ 25 Pocker(10, 20, Card('2', 'spades')), 26 Pocker(13, 19, Card('J', 'spades')), 27 Pocker(18, 18, Card('A', 'diamonds')), 28 Pocker(15, 22, Card('6', 'spades')), 29 Pocker(12, 17, Card('4', 'hearts')), 30 Pocker(19, 21, Card('K', 'clubs')), 31 ] 32 print(PockerCards) 33 34 #attrgetter与itemgetter类似也可以接收多个参数,返回一个元组 35 info = attrgetter('height', 'card.rank') 36 for card in PockerCards: 37 print(info(card))
使用functools.partial冻结参数
functools模块提供了一系列高阶函数,reduce就是其中之一,剩下比较常用的就是partical和particalmethod。
functools.partial这个高阶函数用于绑定一些参数,返回一个函数,返回的函数可以直接调用。
究其本质而言,partial是个闭包。闭包的概念会专门讲解。
partialmethod和partial是一样的,只是用于处理方法的。
1 from functools import partial, partialmethod 2 from operator import add 3 4 #把参数3绑定到add,返回一个函数对象 5 add3 = partial(add, 3) 6 print(add3) 7 #functools.partial(<built-in function add>, 3) 可以看出3已经被绑定了 8 #把每个元素的值加3 9 l = map(add3, range(10)) 10 print(list(l)) 11 12 class Foo(object): 13 def f(self, n1, n2, n3): 14 print("%s => n1: %s, n2: %s, n3: %s" %(self, n1,n2,n3)) 15 return n1+n2+n3 16 foo = Foo() 17 g = partial(foo.f, 1,2) 18 print(g(3))
1 class Foo(object): 2 def f(self, n1, n2, n3): 3 print("%s => n1: %s, n2: %s, n3: %s" %(self, n1,n2,n3)) 4 return n1+n2+n3 5 fn = partialmethod(f, n1=1, n2=2) 6 7 foo = Foo() 8 print(foo.fn) 9 print(foo.fn(n3=100))