一等函数

在 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))

猜你喜欢

转载自www.cnblogs.com/forwardfeilds/p/10457317.html