流畅的python读书笔记-第五章 一等函数

高阶函数

接受函数为参数,或者把函数作为结果返回的函数是高阶函数
    def reverse(word):
        return word[::-1]
    
    
    fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
    
    print(reverse('testing'))
    
    print(sorted(fruits, key=reverse))

all 和 any 也是内置的归约函数。

all(iterable)

如果 iterable 的每个元素都是真值,返回 True;all([]) 返回True。

any(iterable)

只要 iterable 中有元素是真值,就返回 True;any([]) 返回False。

匿名函数

fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']

print(sorted(fruits, key=lambda word: word[::-1]))

可调用对象

如果类定义了 call 方法,那么它的 实例 可以作为函数调用。

因此判断对象能否调用,最安全的方法是使用内置的 callable() 函数

实现 call 方法的类是创建函数类对象的简便方式,

函数内省

用户定义的函数的属性 page 252

案例 生成html标签的函数

def tag(name, *content, cls=None, **attrs):
    """生成一个或多个HTML标签"""

    if cls is not None:
        attrs['class'] = cls

    if attrs:
        attr_str = ''.join(' %s="%s"' % (attr, value)
                           for attr, value
                           in sorted(attrs.items()))
    else:
        attr_str = ''

    if content:
        return '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content)
    else:
        return '<%s%s />' % (name, attr_str)


print(tag('br'))

print(tag('p', 'hello'))

print(tag('p', 'hello', 'world'))

print(tag('p', 'hello', 'world', cls='sidebar')) 

获取关于参数的信息

import bobo
@bobo.query('/')
def hello(person):
return 'Hello %s!' % person

bobo.query 装饰器把一个普通的函数(如 hello)与框架的请求处理
机制集成起来了。

Bobo 会内省 hello 函数,发现它需要一个名为 person
的参数,然后从请求中获取那个名称对应的参数,将其传给 hello 函
数,因此程序员根本不用触碰请求对象。

提取关于函数参数的信息

使用 inspect 模块

from clip import clip
from inspect import signature
sig = signature(clip)

print(sig)


print(str(sig))

for name, param in sig.parameters.items():
    print(param.kind, ':', name, '=', param.default)

inspect.signature 函数返回一个inspect.Signature 对象

  • 它有一个 parameters 属性,这是一个有序映射,
  • 把参数名和 inspect.Parameter 对象对应起来。
  • 各个Parameter 属性也有自己的属性,
  • 例如 name、default 和 kind。特殊的 inspect._empty 值表示没有默认值

kind 属性的值是 _ParameterKind 类中的 5 个值之一,列举如下。

  • POSITIONAL_OR_KEYWORD

    可以通过定位参数和关键字参数传入的形参(多数 Python 函数的参数属于此类)。

  • VAR_POSITIONAL

    定位参数元组。

  • VAR_KEYWORD

    关键字参数字典。

  • KEYWORD_ONLY

    仅限关键字参数(Python 3 新增)。

  • POSITIONAL_ONLY

    仅限定位参数;

inspect.Signature 对象有个 bind 方法,

它可以把任意个参数绑定到签名中的形参上,所用的规则与实参到形参的匹配方式一样。
框架可以使用这个方法在真正调用函数前验证参数,

示例 5-18 把tag 函数(见示例 5-10)的签名绑定到一个参数字典

>>> import inspect
>>> sig = inspect.signature(tag) ➊
>>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard',
... 'src': 'sunset.jpg', 'cls': 'framed'}
>>> bound_args = sig.bind(**my_tag) ➋
>>> bound_args
<inspect.BoundArguments object at 0x...> ➌
>>> for name, value in bound_args.arguments.items(): ➍
... print(name, '=', value)
...
name = img
cls = framed
attrs = {'title': 'Sunset Boulevard', 'src': 'sunset.jpg'}
>>> del my_tag['name'] ➎
>>> bound_args = sig.bind(**my_tag) ➏
Traceback (most recent call last):
...
TypeError: 'name' parameter lacking default value

❷ 把一个字典参数传给 .bind() 方法。
❸ 得到一个 inspect.BoundArguments 对象。
❹ 迭代 bound_args.arguments(一个 OrderedDict 对象)中的元
素,显示参数的名称和值。
❺ 把必须指定的参数 name 从 my_tag 中删除。
❻ 调用 sig.bind(**my_tag),抛出 TypeError,抱怨缺少 name 参
数。

函数注解

def clip(text: str, max_len: 'int > 0' = 80) -> str:
    print(text, max_len)


clip("sdf", 18)

print(clip.__annotations__)
  • 如果想注解返回值,在 ) 和函数声明末尾的 : 之间添加 -> 和一个表达式。
  • 各个参数可以在 : 之后增加注解表达式。如果参数有默认值,注解放在参数名和 = 号之间。

注解不会做任何处理,只是存储在函数的
annotations 属性(一

个字典)中:

operator模块

reduce计算阶乘

from functools import reduce


# 阶乘
def fact(n):
    print(reduce(lambda a, b: a * b, range(1, n + 1)))


# operator.mul 函数计算阶乘
from functools import reduce
from operator import mul


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

print(fact2(3))

itemgetter

展示了 itemgetter 的常见用途:根据元组的某个字段给元
组列表排序。在这个示例中,按照国家代码(第 2 个字段)的顺序打印
各个城市的信息。

metro_data = [
    ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
    ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
    ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
    ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
    ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]

### 演示使用 itemgetter 排序一个元组列表

from operator import itemgetter

for city in sorted(metro_data, key=itemgetter(1)):
    print(city)

如果把多个参数传给 itemgetter,它构建的函数会返回提取的值构成
的元组:

cc_name = itemgetter(1, 0)
for city in metro_data:
    print(cc_name(city))

attrgetter

此外,如果参数名中包含 .(点号),attrgetter 会深
入嵌套对象,获取指定的属性。

from collections import namedtuple

metro_data = [
    ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
    ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
    ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
    ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
    ('Sao Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]

## 就像数据格式化一样 数据带上标签
LatLong = namedtuple('LatLong', 'lat long')

Metropolis = namedtuple('Metropolis', 'name cc pop coord')

metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long))
               for name, cc, pop, (lat, long) in metro_data]

print(metro_areas[0])
print(metro_areas[0].coord.lat)

#
from operator import attrgetter

name_lat = attrgetter('name', 'coord.lat')

for city in sorted(metro_areas, key=attrgetter('coord.lat')):
    print(name_lat(city))

methodcaller 自行创建函数

它会自行创建函数。methodcaller 创建的函数会在对象上调用参数指定的方法
自己创建函数

from operator import methodcaller
s = 'The time has come'
upcase = methodcaller('upper')

print(upcase)

hiphenate = methodcaller('replace', ' ', '-')
print(hiphenate(s))

functools.partial冻结参数

functools.partial 这个高阶函数用于部分应用一个函数。部分应用

是指,基于一个函数创建一个新的可调用对象,把原函数的某些参数固定。

from operator import mul
from functools import partial

print(mul(3, 7))
# 第一个函数, 第二个固定的参数
triple = partial(mul, 3)
print(list(map(triple, range(1, 10))))

小总结

高阶函数

  • 接受函数为参数,或者把函数作为结果返回的函数是高阶函数.
  • Python 中常用的高阶函数有内置函数
  • sorted、min、max 和 functools. partial

实例 直接函数化运行

  • 从 lambda 表达式创建的简单函数到实现__call__ 方法的类实例。
  • 这些可调用对象都能通过内置的callable() 函数检测。

函数注解

  • 在 inspect 模块的帮助下,可以读取它们。
  • 例如,Signature.bind 方法使用灵活的规则把实参绑定到形参上,这与 Python 使用的规则一样。

operator 模块

  • 介绍了 operator 模块中的一些函数,
  • 以及functools.partial 函数,
  • 有了这些函数,函数式编程就不太需要功能有限的 lambda 表达式了

其他

  • all 和 any 也是内置的归约函数.
  • 用来判断是否所有都为真,或者有一个为真
    原文作者:小小梁
    原文地址: https://segmentfault.com/a/1190000014676694
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞