《流畅的Python》第五章学习笔记


在Python中,函数是一等对象。

一等对象

  • 在运行时创建

  • 能赋值给变量或数据结构中的元素

  • 能作为参数传给函数

  • 能作为函数的返回结果

第二点和第三点在实际编写代码的时候经常用到!

高阶函数

接受函数为参数,或者把函数作为结果返回的函数就是高阶函数。

常见的高阶函数:

  • map

  • filter

  • reduce

函数式语言通常会提供这三个高阶函数

在Python中可以使用列表推导式来替代实现

def fact(n):
    return 1 if n < 2 else n * fact(n - 1)


print(list(map(fact, range(6))))
print([fact(n) for n in range(6)])

匿名函数

使用lambda关键字可以创建匿名函数

除了作为参数传递给高阶函数之外,不建议使用匿名函数。

Lundh提出的匿名函数重构秘籍:

  1. 编写注释,说明lambda表达式的作用

  2. 研究注释,找出一个名称来概括注释

  3. 把lambda表达式转换成def语句,使用那个名称来定义函数

  4. 删除注释

一般的lambda表达式要么难以阅读,要么无法写出。

可调用对象

使用callable()方法查看对象是否是可调用对象

只要实现__call__方法,任何Python对象都可以调用

class A():
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def add(self):
        return self.a + self.b

    def __call__(self, *args, **kwargs):
        return self.a + self.b


if __name__ == '__main__':
    a = A(1, 2)
    print(a.add())
    print(a())

关于参数的信息

from inspect import signature


def clip(text, max_len=80):
    end = None
    if len(text) > max_len:
        space_before = text.rfind(" ", 0, max_len)
        if space_before >= 0:
            end = space_before
        else:
            space_before = text.rfind(" ", max_len)
        if space_before >= 0:
            end = space_before
    if end is None:
        end = len(text)
    return text[:end].rstrip()


if __name__ == '__main__':
    print(clip.__defaults__)  # (80,) 默认值
    print(clip.__code__)
    print(clip.__code__.co_varnames)  # ('text', 'max_len', 'end', 'space_before') 全部变量 包含局部变量
    print(clip.__code__.co_argcount)  # 2 入参个数
    sig = signature(clip)
    print(sig)  # (text, max_len=80) 
    for name, param in sig.parameters.items():
        print(f"{param.kind}:{name}={param.default}")
        # 1:text=<class 'inspect._empty'>
        # 1:max_len=80

函数注解

为函数声明中参数和返回值附加元数据

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

注解不会做任何处理,知识存储在函数的__annotations__属性中

使用inspect.signature()函数可以提取注解。

注解的最大作用是:为IDE和lint程序的静态检查功能提供额外的类型信息

itemgetter

返回一个根据索引提取元素的函数

from operator import itemgetter
class itemgetter:
    """
    Return a callable object that fetches the given item(s) from its operand.
    After f = itemgetter(2), the call f(r) returns r[2].
    After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])
    """
    __slots__ = ('_items', '_call')

    def __init__(self, item, *items):
        if not items:
            self._items = (item,)
            def func(obj):
                return obj[item]
            self._call = func
        else:
            self._items = items = (item,) + items
            def func(obj):
                return tuple(obj[i] for i in items)
            self._call = func

    def __call__(self, obj):
        return self._call(obj)

    def __repr__(self):
        return '%s.%s(%s)' % (self.__class__.__module__,
                              self.__class__.__name__,
                              ', '.join(map(repr, self._items)))

    def __reduce__(self):
        return self.__class__, self._items

等价于

def itemgetter(*items):
    if len(items) == 1:
        item = items[0]
        def g(obj):
            return obj[item]
    else:
        def g(obj):
            return tuple(obj[item] for item in items)
    return g

实现取出对象中的一个元素的功能

from operator import itemgetter

a = [0, 1, 2, 3, 4]
x = itemgetter(1)
print(x(a))  # 1

x = itemgetter(1, 2)
print(x(a))  # (1, 2)

x = itemgetter(1, 2, 3)
print(x(a))  # (1, 2, 3)

使用lambda实现

x = lambda x: x[1]
print(x(a))

attrgetter

返回一个根据名称提取对象属性的函数

class attrgetter:
    """
    Return a callable object that fetches the given attribute(s) from its operand.
    After f = attrgetter('name'), the call f(r) returns r.name.
    After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).
    After h = attrgetter('name.first', 'name.last'), the call h(r) returns
    (r.name.first, r.name.last).
    """
    __slots__ = ('_attrs', '_call')

    def __init__(self, attr, *attrs):
        if not attrs:
            if not isinstance(attr, str):
                raise TypeError('attribute name must be a string')
            self._attrs = (attr,)
            names = attr.split('.')
            def func(obj):
                for name in names:
                    obj = getattr(obj, name)
                return obj
            self._call = func
        else:
            self._attrs = (attr,) + attrs
            getters = tuple(map(attrgetter, self._attrs))
            def func(obj):
                return tuple(getter(obj) for getter in getters)
            self._call = func

    def __call__(self, obj):
        return self._call(obj)

    def __repr__(self):
        return '%s.%s(%s)' % (self.__class__.__module__,
                              self.__class__.__qualname__,
                              ', '.join(map(repr, self._attrs)))

    def __reduce__(self):
        return self.__class__, self._attrs

等价于

def attrgetter(*items):
    if any(not isinstance(item, str) for item in items):
        raise TypeError('attribute name must be a string')
    if len(items) == 1:
        attr = items[0]
        def g(obj):
            return resolve_attr(obj, attr)
    else:
        def g(obj):
            return tuple(resolve_attr(obj, attr) for attr in items)
    return g

def resolve_attr(obj, attr):
    for name in attr.split("."):
        obj = getattr(obj, name)
    return obj

methodcaller

返回调用对象方法的一个函数

class methodcaller:
    """
    Return a callable object that calls the given method on its operand.
    After f = methodcaller('name'), the call f(r) returns r.name().
    After g = methodcaller('name', 'date', foo=1), the call g(r) returns
    r.name('date', foo=1).
    """
    __slots__ = ('_name', '_args', '_kwargs')

    def __init__(*args, **kwargs):
        if len(args) < 2:
            msg = "methodcaller needs at least one argument, the method name"
            raise TypeError(msg)
        self = args[0]
        self._name = args[1]
        if not isinstance(self._name, str):
            raise TypeError('method name must be a string')
        self._args = args[2:]
        self._kwargs = kwargs

    def __call__(self, obj):
        return getattr(obj, self._name)(*self._args, **self._kwargs)

    def __repr__(self):
        args = [repr(self._name)]
        args.extend(map(repr, self._args))
        args.extend('%s=%r' % (k, v) for k, v in self._kwargs.items())
        return '%s.%s(%s)' % (self.__class__.__module__,
                              self.__class__.__name__,
                              ', '.join(args))

    def __reduce__(self):
        if not self._kwargs:
            return self.__class__, (self._name,) + self._args
        else:
            from functools import partial
            return partial(self.__class__, self._name, **self._kwargs), self._args

等价于

def methodcaller(name, /, *args, **kwargs):
    def caller(obj):
        return getattr(obj, name)(*args, **kwargs)
    return caller

比如我要将字符串中的空格替换为-

s = 'Hello World'
change_s = methodcaller('replace', ' ', '-')
print(change_s(s))  # Hello-World

partial

冻结参数

from functools import partial


def add(a, b):
    return a + b


add1 = partial(add, b=3)
print(add1(1))
print(add1(2))

一个计算a+b的函数,我们把它其中的一个入参固定为3,这样我们只需要传入一个参数就可以计算了

不指定冻结的形参的话,默认是冻结左侧的形参,该函数中的a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值