当前位置:必发365电子游戏 > 编程 > 可以拿到函数的名字,纯粹的函数式编程语言编写的函数没有变量
可以拿到函数的名字,纯粹的函数式编程语言编写的函数没有变量
2019-12-19

一:装饰器

黄金年代:函数式编制程序概念

1 函数对象有三个__name__属性,能够获得函数的名字````

       函数是Python内建扶植的生龙活虎种包装,大家透过把大段代码拆成函数,通过意气风发层生机勃勃层的函数调用,就能够把复杂职分分解成简单的天职,这种解释能够称呼面向进度的次第设计。函数便是面向进程的程序设计的宗旨单元。

 1 >>> def now():
 2 ...     print('2015-3-25')
 3 ...
 4 >>> f = now
 5 >>> f()
 6 2015-3-25
 7 
 8 
 9 >>> now.__name__
10 'now'
11 >>> f.__name__
12 'now'

       而函数式编制程序(请留心多了三个“式”字)——Functional Programming,即便也可以归纳到面向进度的前后相继设计,但其思谋更肖似数学总计。

 

       函数式编制程序正是意气风发种浮泛程度相当的高的编制程序范式,纯粹的函数式编制程序语言编写的函数未有变量,由此,任性四个函数,只要输入是鲜明的,输出正是规定的,这种纯函数大家称为未有副功效。

2  要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。本质上,decorator就是一个返回函数的高阶函数。

1 def log(func):
2     def wrapper(*args, **kw):
3         print('call %s():' % func.__name__)
4         return func(*args, **kw)
5     return wrapper

       而允许利用变量的次第设计语言,由于函数内部的变量状态不分明,相像的输入,恐怕获取分歧的出口,由此,这种函数是有副成效的。

 

函数式编程的叁本性情正是,允许把函数本人作为参数字传送入另三个函数,还允许再次来到一个函数!

 

       Python对函数式编程提供部分扶助。由于Python允许选拔变量,因而,Python不是纯函数式编制程序语言。

上面的log,因为它是一个decorator,所以接纳贰个函数作为参数,并再次来到叁个函数。大家要依赖Python的@语法,把decorator置于函数的定义处:

 

1 @log
2 def now():
3     print('2015-3-25')

二:高阶函数概念

 

1  变量可以针对函数,内置函数abs是函数自己,abs(-10卡塔尔国才是函数的调用。f=abs   f(-10卡塔尔与abs(10)的意思相近

 

2  函数名也是变量

调用now()函数,不止会运营now()函数自己,还会在运作now()函数前打字与印刷生龙活虎行日志:

3  变量能够针对函数,函数的参数能选取变量,那么三个函数就足以接到另二个函数作为参数,这种函数就称为高阶函数。

1 >>> now()
2 call now():
3 2015-3-25

 

 

三:高阶函数

@log放到now()函数的定义处,也正是试行了语句:

1 filter函数

1 now = log(now)

    和map()类似,filter()也收到一个函数和叁个行列。和map()今是昨非的是,filter()把传播的函数依次效率于各类成分,然后依照重回值是True还是False调整封存还是丢掉该因素。

 

1 def is_odd(n):
2 
3     return n % 2 == 1
4 
5 list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))

由于log()是二个decorator,再次回到一个函数,所以,原本的now()函数还是存在,只是未来同名的now变量指向了新的函数,于是调用now()将实践新函数,即在log()函数中回到的wrapper()函数。

 

wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以承当任意参数的调用。在wrapper()函数内,首先打印日志,再接着调用原始函数。

把一个序列中的空字符串删掉:

1 def not_empty(s):
2     return s and s.strip()
3 
4 list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))

3  若decorator本身要求传入参数,那就要求编写制定叁个赶回decorator的高阶函数,写出来会更头昏眼花。

 

 1 def log(text):
 2     def decorator(func):
 3         def wrapper(*args, **kw):
 4             print('%s %s():' % (text, func.__name__))
 5             return func(*args, **kw)
 6         return wrapper
 7     return decorator
 8 @log('execute')
 9 def now():
10     print('2015-3-25')
filter()这个高阶函数,关键在于正确实现一个“筛选”函数。filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list。

 

 

   

实践结果如下:

2  map/reduce函数

1 >>> now()
2 execute now():
3 2015-3-25

  a       map()函数接受八个参数,四个是函数,四个是iterable,map将盛传的函数依次功效到行列的各种成分,并把结果作为新的Iterator重临。注意:Iterator是三个惰性种类,能够透过list,next,for  in来回到

 

1 def f(x):
2 
3 ...     return x * x
4 ...
5 >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
6 >>> list(r)

和两层嵌套的decorator相比较,3层嵌套的功效是那般的:

 

1 >>> now = log('execute')(now)

 

 

 

咱们来剖判下边包车型大巴语句,首先奉行log('execute'),重返的是decorator函数,再调用重返的函数,参数是now函数,再次来到值最后是wrapper函数。

map()传入的第一个参数是f(函数名),即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

4   以上两种decorator的定义都不曾难题,但还差最终一步。因为大家讲了函数也是目的,它有__name__等属性,但您去看经过decorator装饰之后的函数,它们的__name__业已从原来的'now'变成了'wrapper'

b  reduce把一个函数效率在三个队列[x1, x2, x3, ...]上,那么些函数必需接收四个参数,reduce把结果延续和连串的下一个要素做储存总括,其成效正是:

1 >>> now.__name__
2 'wrapper'
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)。但是用前必须先用 from functools import reduce导入

把字符串转化为整数的函数

1 from functools import reduce
2 
3 DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
4 
5 def char2num(s):
6     return DIGITS[s]
7 
8 def str2int(s):
9     return reduce(lambda x, y: x * 10 + y, map(char2num, s))

 

 

因为重回的非常wrapper()函数名字正是'wrapper',所以,要求把原始函数的__name__等特性复制到wrapper()函数中,不然,有个别信任函数具名的代码实行就能够出错。

3 sorted函数

 (1)Python内置的sorted()函数就可以对list进行排序:>>> sorted([36, 5, -12, 9, -21])  [-21, -12, 5, 9, 36]

  (2) sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序: >>> sorted([36, 5, -12, 9, -21], key=abs)  [5, 9, -12, -21, 36]

key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序。然后sorted()函数按照keys进行排序,并按照对应关系返回list相应的元素。
(3) 默认情况下,对字符串排序,是按照ASCII的大小比较的,由于'Z' < 'a',结果,大写字母Z会排在小写字母a的前面。

Python内置的functools.wraps可以解决这个问题。记住:

            忽视大小写来相比较五个字符串,实际上正是先把字符串都改成大写(可能都改成小写),再比较。

a  在概念函数前导入functools模块。import functools

           这样,我们给sorted传播key函数,就能够实现忽视大小写的排序:

b 在定义wrapper()的先头加上@functools.wraps(func)即可。

1  >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
2                                 ['about', 'bob', 'Credit', 'Zoo']

 

 

二:偏函数(functools模块中内部一个成效)

             要扩充反向排序,不必改动key函数,可以流传第三个参数reverse=True

可以拿到函数的名字,纯粹的函数式编程语言编写的函数没有变量。1 在介绍函数参数的时候,通过设定参数的默认值,可以降低函数调用的难度。而偏函数也可以做到这一点。

1  >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
2        ['Zoo', 'Credit', 'bob', 'about']

int()函数能够把字符串转变为整数,当仅传入字符串时,int()函数默许按十进制调换:

 

1 >>> int('12345')
2 12345

    

 

    

 

 

int()函数还提供额外的base参数,默许值为10。借使传入base参数,就足以做N进制的转移:

1 >>> int('12345', base=8)
2 5349   #把字符串当做8进制,返回相对应的十进制。
3 >>> int('12345', 16)
4 74565  #把字符串当做16进制,返回相对应的十进制。

 

1 >>> import functools
2 >>> int2 = functools.partial(int, base=2)
3 >>> int2('1000000')
4 64
5 >>> int2('1010101')
6 85

 

简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。