ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

支持函数式编程的包

2022-01-04 22:04:51  阅读:160  来源: 互联网

标签:函数 metro 编程 支持 attrgetter operator import name


支持函数式编程的包

Python的目标不是变成函数式语言,但是得益于operator和functools等包的支持,函数式编程风格也可以信手拈来

operator模块

在函数式编程中,经常需要把算术运算符当作函数使用。例如,不适使用递归计算阶乘。求和可以使用sum函数,但是求积没有这样的函数。可以使用reduce函数,但是需要一个函数计算序列中两个元素之积

# 使用reduce函数和一个匿名函数计算阶乘
from functools import reduce


def fact(n):
    return reduce(lambda a, b: a * b, range(1, n + 1))

operator模块为多个算术运算符提供了对应的函数,从而避免编写lambda a, b:a*b这种平凡的匿名函数。使用算术运算符

from functools import reduce
from operator import mul


def fact(n):
    return reduce(mul, range(1, n + 1))

operator模块中还有一类函数,能替代从序列中取出元素或读取对象属性的lambda表达式:因此,itemgetter和attrgetter其实会自行构建函数

metro_data = [('Tokyo', 'JP', 36.933, (35.689722, 139.69167)),
              ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))]
from operator import itemgetter

for city in sorted(metro_data, key=itemgetter(1)):
    print(city)
# itemgetter(1)的作用与lambda fields:fields[1]一样,创建一个接受集合的函数,返回索引为1上的元素
('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
('Tokyo', 'JP', 36.933, (35.689722, 139.69167))
cc_name = itemgetter(1, 0)
for city in metro_data:
    print(cc_name(city))
# 如果把多个参数传给itemgetter,它构建的函数会返回提取的值构成的元组
('JP', 'Tokyo')
('IN', 'Delhi NCR')

itemgetter使用[]运算符,因此它不仅支持序列,还支持映射和任何实现__getitem__方法的类

attrgetter与itemgetter作用类似,它会创建函数根据名称提取对象的属性。如果把多个属性名传递给attrgetter,它也会返回提取的值构成的元组。此外,如果参数名中包含点号,attrgetter会深入嵌套对象,获取指定的属性。

# 定义一个namedtuple,名为metro_data,用attrgetter处理它
from collections import namedtuple

LatLong = namedtuple('LatLong', 'lat long')  # 使用namedtuple定义LatLong
Metropolis = namedtuple('Metropolis', 'name cc pop coord')  # 定义Metropolis
metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long)) for name, cc, pop, (lat, long) in
               metro_data]  # 使用Metropolis实例构建metro_areas列表。使用嵌套的元组拆包提取(lat, long),然后使用它们构建LatLong,作为Metropolis的coord属性
metro_areas[0]
Metropolis(name='Tokyo', cc='JP', pop=36.933, coord=LatLong(lat=35.689722, long=139.69167))
metro_areas[0].coord.lat  # 深入metro_areas[0]获取它的纬度
35.689722
from operator import attrgetter

name_lat = attrgetter('name', 'coord.lat')  # 定义一个attrgetter,获取name属性和嵌套的coord.lat属性
for city in sorted(metro_areas, key=attrgetter('coord.lat')):  # 再次使用attrgetter,按照纬度排序城市列表
    print(name_lat(city))  # 使用定义的attrgetter,只显示城市名和纬度
('Delhi NCR', 28.613889)
('Tokyo', 35.689722)
# 下面是operator模块中定义的部分函数(省略了以_开头的函数名称,因为它们基本上是实现细节)
import operator

[name for name in dir(operator) if not name.startswith('_')]
['abs',
 'add',
 'and_',
 'attrgetter',
 'concat',
 'contains',
 'countOf',
 'delitem',
 'eq',
 'floordiv',
 'ge',
 'getitem',
 'gt',
 'iadd',
 'iand',
 'iconcat',
 'ifloordiv',
 'ilshift',
 'imatmul',
 'imod',
 'imul',
 'index',
 'indexOf',
 'inv',
 'invert',
 'ior',
 'ipow',
 'irshift',
 'is_',
 'is_not',
 'isub',
 'itemgetter',
 'itruediv',
 'ixor',
 'le',
 'length_hint',
 'lshift',
 'lt',
 'matmul',
 'methodcaller',
 'mod',
 'mul',
 'ne',
 'neg',
 'not_',
 'or_',
 'pos',
 'pow',
 'rshift',
 'setitem',
 'sub',
 'truediv',
 'truth',
 'xor']

这些函数中的大部分作用不言而喻。以i开头,后面是另一个运算符的那些名称(如iadd、iand等),对应的是增量赋值运算符(如+=、&=等)。如果第一个参数是可变的,那么这些运算符会就地修改它;否则,作用与不带i的函数一样,直接返回运算结果

在operator模块中,methodcaller的作用与attrgetter和itemgetter类似,它会自行创建函数。methodcaller创建的函数会在对象上调用参数指定的方法

from operator import methodcaller

s = 'The time has come'
upcase = methodcaller('upper')
upcase(s)
'THE TIME HAS COME'
hiphenate = methodcaller('replace', ' ', '-')  # methodcaller可以冻结某些参数
hiphenate(s)
'The-time-has-come'

使用functools.partial冻结参数

functools模块提供了一系列高阶函数,其中最为人熟知的是reduce函数

functools.partial这个高阶函数用于部分应用一个函数。部分应用是指,基于一个函数创建一个新的可调用对象,把原函数的某些参数固定。使用这个函数可以把接受一个或多个参数的函数改编成需要回调的API,这样参数更少

# 使用partial把两个参数函数改编成需要单参数的可调用对象
from operator import mul
from functools import partial

triple = partial(mul, 3) # 使用mul创建triple函数,把第一个定位参数定为3
triple(7) # 测试triple函数
21
list(map(triple,range(1,10))) # 在map中使用triple函数
[3, 6, 9, 12, 15, 18, 21, 24, 27]
# 使用partial构建一个便利的Unicode规范化函数
import unicodedata ,functools
nfc=functools.partial(unicodedata.normalize,'NFC')
# partial的第一个参数是可调用对象,后面跟着任意个要绑定的定位参数和关键字

标签:函数,metro,编程,支持,attrgetter,operator,import,name
来源: https://www.cnblogs.com/Reion/p/15764249.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有