fluent python part3 一等函数

第 5 章 一等函数

在这里插入图片描述

5.1 把函数视作对象

>>> def factorial(n):
...     """return n!"""
...     return 1 if n < 2 else n * factorial(n - 1)
...
>>> factorial(42)
1405006117752879898543142606244511569936384000000000
>>> factorial.__doc__
'return n!'
>>> type(factorial)
<class 'function'>
>>> fact = factorial
>>> fact
<function factorial at 0x0000017B71F1B740>
>>> fact(5)
120
>>> list(map(fact, range(10)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

有了一等函数,就可以使用函数式风格编程。函数式编程的特点之一是使用高阶函数

5.2 高阶函数

接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higher-order function),map 函数就是一例

按单词长度排序:

>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
>>> sorted(fruits, key=len)
['fig', 'apple', 'cherry', 'banana', 'raspberry', 'strawberry']

按韵脚排序:

>>> def reverse(word):
...     return word[::-1]
...
>>> sorted(fruits, key=reverse)
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']

在这里插入图片描述

5.3 匿名函数

>>> sorted(fruits, key=lambda x: x[::-1])
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']

lambda 句法只是语法糖:与 def 语句一样,lambda 表达式会创建函数对象。这是 Python 中几种可调用对象的一种

5.4 可调用对象

python 定义了 7 中可调用对象:

  • 用户定义的函数:包括 def 和 lambda
  • 内置函数:如 len()
  • 内置方法:如 dict.get
  • 方法:在类的定义体中定义的函数。
  • 类:因为 Python 没有 new 运算符,所以调用类相当于调用构造函数
  • 类的实例:如果类定义了 call 方法,那么它的实例可以作为函数调用
  • 生成器函数:使用 yield 关键字的函数或方法。调用生成器函数返回的是生成器对象

在这里插入图片描述

5.5 用户定义的可调用类型

不仅 Python 函数是真正的对象,任何 Python 对象都可以表现得像函数。为此,只需实现实例方法 call

class BingoCage:def __init__(self, item):self._item = list(item)shuffle(self._item)def pick(self):try:return self._item.pop()except IndexError:raise LookupError('pick from empty BingoCage')def __call__(self):return self.pick()
>>> b1 = BingoCage(range(3))
>>> b1.pick()
2
>>> b1()
3
>>> callable(b1)
True

5.6 函数内省

列出常规对象没有而函数有的属性:

在这里插入图片描述

5.8 获取关于参数的信息

在这里插入图片描述

5.9 函数注解

注解:为函数声明中的参数和返回值附加元数据

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

在这里插入图片描述
在这里插入图片描述

5.10 支持函数式编程的包

operator模块

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

from functools import reduce
from operator import muldef fact(n):return reduce(mul, range(1, n + 1))if __name__ == '__main__':print(fact(5))

在这里插入图片描述

itemgetter 的常见用途:根据元组的某个字段给元组列表排序

在这里插入图片描述


第 6 章 使用一等函数实现设计模式

6.1 重构“策略”模式

使用函数实现“策略”模式

在这里插入图片描述

在这里插入图片描述

from collections import namedtupleCustomer = namedtuple('Customer', 'name fidelity')class LineItem:def __init__(self, product, quantity, price):self.product = productself.quantity = quantityself.price = pricedef total(self):return self.price * self.quantityclass Order:  # 上下文def __init__(self, customer, cart, promotion=None):self.customer = customerself.cart = list(cart)self.promotion = promotion      # function: dynamic binddef total(self):if not hasattr(self, '__total'):self.__total = sum(item.total() for item in self.cart)return self.__totaldef due(self):if self.promotion is None:discount = 0else:discount = self.promotion(self)return self.total() - discountdef __repr__(self):fmt = '<Order total: {:.2f} due: {:.2f}>'return fmt.format(self.total(), self.due())def fidelity_promo(order):return order.total() * .05 if order.customer.fidelity >= 1000 else 0def bulk_item_promo(order):discount = 0for item in order.cart:if item.quantity >= 20:discount += item.total() * .1return discountdef large_order_promo(order):distinct_items = {item.product for item in order.cart}if len(distinct_items) >= 10:return order.total() * .07return 0if __name__ == '__main__':joe = Customer('John Doe', 0)ann = Customer('Ann Smith', 1100)cart = [LineItem('banana', 4, .5),LineItem('apple', 10, 1.5),LineItem('watermelon', 5, 5.0)]# 为了把折扣策略应用到 Order 实例上,只需把促销函数作为参数传入Order(joe, cart, fidelity_promo)

选择最佳策略:简单的方式

在这里插入图片描述

找出模块中的全部策略

使用 globals() 获取全局符号表:

在这里插入图片描述

promos = [globals()[name] for name in globals() if name.endwith('_promo') and name != 'best_promo']
def best_promo(order):return max(promo(order) for promo in promos)

或者内省 promotions 模块,构建策略函数列表:

promos = [func for name, func in inspect.getmemebers(promotions, inspect.isfunction)]

6.2 “命令”模式

“命令”设计模式也可以通过把函数作为参数传递而简化

在这里插入图片描述
在这里插入图片描述


第 7 章 函数装饰器和闭包

7.1 装饰器基础知识

函数装饰器用于在源码中“标记”函数,以某种方式增强函数的行为

在这里插入图片描述

def deco(fn):def inner():print("inner")return inner@deco
def foo():print("foo")if __name__ == '__main__':foo()		# "inner"

在这里插入图片描述

7.2 Python 何时执行装饰器

在这里插入图片描述

registry = []def register(fn):print(f'running register({fn})')registry.append(fn)return fn@register
def f1():print('running f1()')@register
def f2():print('running f2()')def f3():print('running f3()')if __name__ == '__main__':print('running main')print('registry -> ', registry)f1()f2()f3()
running register(<function f1 at 0x7f2fb6b36268>)
running register(<function f2 at 0x7f2fb6b362f0>)
running main
registry ->  [<function f1 at 0x7f2fb6b36268>, <function f2 at 0x7f2fb6b362f0>]
running f1()
running f2()
running f3()Process finished with exit code 0

register 在模块中其他函数之前运行(两次)

在这里插入图片描述

7.4 变量作用域规则

在这里插入图片描述
Python 编译函数的定义体时,它判断 b 是局部变量,因为在函数中给它赋值了

Python 不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量

在这里插入图片描述

7.5 闭包

闭包指延伸了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量。函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量

在这里插入图片描述
使用类 + 可调用对象实现:

class Averager:def __init__(self):self.series = []def __call__(self, new_value):self.series.append(new_value)total = sum(self.series)return total / len(self.series)

在这里插入图片描述
使用高阶函数实现:

def make_averager():series = []def averager(new_value):series.append(new_value)total = sum(series)return total / len(series)return averager

调用 make_averager 时,返回一个 averager 函数对象。每次调用 averager 时,它会把参数添加到系列值中,然后计算当前平均值
在这里插入图片描述
综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定

7.6 nolocal 声明

在这里插入图片描述

def make_averager():count = 0total = 0def averager(new_value):nonlocal count, totalcount += 1total += new_valuereturn total / countreturn averager

7.7 实现一个简单的装饰器

下面定义了一个装饰器,它会在每次调用被装饰的函数时计时,然后把经过的时间、传入的参数和调用的结果打印出来:

import timedef clock(func):def clocked(*args):t0 = time.perf_counter()result = func(*args)  # func is a freevarelapsed = time.perf_counter() - t0name = func.__name__arg_str = ', '.join(repr(arg) for arg in args)print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))return resultreturn clocked@clock
def snooze(seconds):time.sleep(seconds)@clock
def factorial(n):return n if n < 2 else n * factorial(n - 1)if __name__ == '__main__':print('*' * 40, 'Calling snooze(.123)')snooze(.123)print('*' * 40, 'Calling factorial(6)')print('6! =', factorial(6))pass
**************************************** Calling snooze(.123)
[0.12306906s] snooze(0.123) -> None
**************************************** Calling factorial(6)
[0.00000069s] factorial(1) -> 1
[0.00001145s] factorial(2) -> 2
[0.00001898s] factorial(3) -> 6
[0.00002650s] factorial(4) -> 24
[0.00003265s] factorial(5) -> 120
[0.00004110s] factorial(6) -> 720
6! = 720

在这里插入图片描述
设计模式中定义的装饰器模式:动态地给一个对象添加一些额外的职责。这与函数装饰器是相同的

改进后的装饰器:

def clock(func):@functools.wraps(func)def clocked(*args, **kwargs):t0 = time.time()result = func(*args, **kwargs)  # func is a freevarelapsed = time.time() - t0name = func.__name__arg_lst = []if args:arg_lst.append(', '.join(repr(arg) for arg in args))if kwargs:pairs = [f'{k}={w}' for k, w in sorted(kwargs.items())]arg_lst.append(', '.join(pairs))arg_str = ', '.join(arg_lst)print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))return resultreturn clocked

7.8 标准库中的装饰器

lru_cache

使用 DP 的思想优化递归程序
在这里插入图片描述

@clock
def fibonacci(n):return n if n < 2 else fibonacci(n - 2) + fibonacci(n - 1)

进行了大量重复运算:

[0.00000030s] fibonacci(0) -> 0
[0.00000040s] fibonacci(1) -> 1
[0.00004730s] fibonacci(2) -> 1
[0.00000030s] fibonacci(1) -> 1
[0.00000040s] fibonacci(0) -> 0
[0.00000030s] fibonacci(1) -> 1
[0.00002010s] fibonacci(2) -> 1
[0.00003850s] fibonacci(3) -> 2
[0.00010310s] fibonacci(4) -> 3
[0.00000020s] fibonacci(1) -> 1
[0.00000020s] fibonacci(0) -> 0
[0.00000020s] fibonacci(1) -> 1
[0.00001670s] fibonacci(2) -> 1
[0.00003420s] fibonacci(3) -> 2
[0.00000010s] fibonacci(0) -> 0
[0.00000030s] fibonacci(1) -> 1
[0.00001650s] fibonacci(2) -> 1
[0.00000020s] fibonacci(1) -> 1
[0.00000020s] fibonacci(0) -> 0
[0.00000020s] fibonacci(1) -> 1
[0.00001700s] fibonacci(2) -> 1
[0.00003310s] fibonacci(3) -> 2
[0.00006550s] fibonacci(4) -> 3
[0.00011620s] fibonacci(5) -> 5
[0.00023630s] fibonacci(6) -> 8

使用 lru_cache 改善性能后:

@functools.lru_cache()		# () 接受参数,functools.lru_cache(maxsize=128, typed=False)
@clock
def fibonacci(n):return n if n < 2 else fibonacci(n - 2) + fibonacci(n - 1)
[0.00000030s] fibonacci(0) -> 0
[0.00000040s] fibonacci(1) -> 1
[0.00004980s] fibonacci(2) -> 1
[0.00000050s] fibonacci(3) -> 2
[0.00006920s] fibonacci(4) -> 3
[0.00000050s] fibonacci(5) -> 5
[0.00008840s] fibonacci(6) -> 8
8

singledispatch

因为 Python 不支持重载方法或函数,使用 @singledispatch 装饰的普通函数会变成泛函数(generic function):根据第一个参数的类型,以不同方式执行相同操作的一组函数

import time
from functools import singledispatch
from collections import abc
import numbers
import html@singledispatch
def htmlize(obj):content = html.escape(repr(obj))return f'<pre>{content}</pre>'@htmlize.register(str)
def _(text):content = html.escape(text).replace('\n', '<br>\n')return '<p>{0}</p>'.format(content)@htmlize.register(numbers.Integral)
def _(n):return '<pre>{0} (0x{0:x})</pre>'.format(n)@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):inner = '</li>\n<li>'.join(htmlize(item) for item in seq)return '<ul>\n<li>' + inner + '</li>\n</ul>'

在这里插入图片描述

7.9 叠放装饰器

装饰器是函数,因此可以组合起来使用

在这里插入图片描述

7.10 参数化装饰器

解析源码中的装饰器时,Python 把被装饰的函数作为第一个参数传给装饰器函数。那怎么让装饰器接受其他参数呢?答案是:创建一个装饰器工厂函数,把参数传给它,返回一个装饰器,然后再把它应用到要装饰的函数上。

一个参数化的注册装饰器

在这里插入图片描述

registry = set()def register(active=True):def decorate(func):print(f'running register(active={active}) -> decorate({func})')if active:registry.add(func)else:registry.discard(func)return funcreturn decorate@register(active=False)
def f1():print('running f1()')@register()
def f2():print('running f2()')def f3():print('running f3()')if __name__ == '__main__':print(registry)pass

register() 要返回 decorate,然后把它应用到被装饰的函数上

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/132761.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【物联网】简要介绍最小二乘法—C语言实现

最小二乘法是一种常用的数学方法&#xff0c;用于拟合数据和寻找最佳拟合曲线。它的目标是找到一个函数&#xff0c;使其在数据点上的误差平方和最小化。 文章目录 基本原理最小二乘法的求解应用举例使用C语言实现最小二乘法总结 基本原理 假设我们有一组数据点 ( x 1 , y 1 …

pandas读取一个 文件夹下所有excel文件

我这边有个需求&#xff0c;是要求汇总一个文件夹所有的excel文件&#xff0c; 其中有.xls和 .xlsx文件&#xff0c;同时还excel文件中的数据可能还不一致&#xff0c;会有表头数据不一样需要一起汇总。 首先先遍历子文件夹并读取Excel文件&#xff1a; 使用os库来遍历包含子文…

LeetCode 面试题 04.09. 二叉搜索树序列

文章目录 一、题目二、C# 题解 一、题目 从左向右遍历一个数组&#xff0c;通过不断将其中的元素插入树中可以逐步地生成一棵二叉搜索树。 给定一个由不同节点组成的二叉搜索树 root&#xff0c;输出所有可能生成此树的数组。 点击此处跳转题目。 示例 1: 输入: root [2,1,3]…

记录:移动设备软件开发(activity组件)

目录 前言Android简介和发展Android应用的基本组件介绍Activity组件Activity简介Activity的状态和生命周期 小结 前言 移动设备软件开发是指为智能手机、平板电脑等移动设备设计和开发应用程序的过程。移动设备软件开发涉及多种技术、平台和工具&#xff0c;例如Android、iOS、…

9.14号作业

仿照vector手动实现自己的myVector&#xff0c;最主要实现二倍扩容功能 有些功能&#xff0c;不会 #include <iostream>using namespace std; //创建vector类 class Vector { private:int *data;int size;int capacity; public://无参构造Vector(){}//拷贝构造Vector(c…

一个方法用js生成随机双色球、大乐透

代码如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><s…

002 Linux 权限

前言 本文将会向您介绍关于linux权限方面的内容&#xff0c;包括文件类型&#xff0c;如何切换用户、基本权限、粘滞位等等 Linux具体的用户 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受限制 普通用户&#xff1a;在linux下做有限的事情。 超级用户的…

NDK (ndk)报错 Unity requires NDK r19 (64-bit)(19.0.05232133)

一、介绍 在 Android 添加 NDK ndk 的时候&#xff0c;出现 Unity requires NDK r19 (64-bit)(19.0.05232133)。 二、环境 1、Unity 2020.3.48f1c1 2、Android NDK 配置 三、报错信息 NDK (ndk)报错 Unity requires NDK r19 (64-bit)(19.0.05232133) 四、解决方法 1、下…

【力扣每日一题】2023.9.13 检查骑士巡视方案

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个n*n大小的矩阵&#xff0c;矩阵的元素表示骑士已经行动的次数&#xff0c;问我们骑士能不能按照矩阵里元素顺序来巡视整个…

vue前后端分离单点登录,结合长token和短token进行登录

单点登录背景 在公司发展初期&#xff0c;公司拥有的系统不多&#xff0c;通常一个两个&#xff0c;每个系统都有自己的登录模块&#xff0c;运营人员每天用自己的账号登陆&#xff0c;很方便&#xff0c;但是&#xff0c;随着企业的发展&#xff0c;用到的系统随之增加&#x…

06-Redis缓存高可用集群

上一篇&#xff1a;05-Redis高可用集群之水平扩展 1.集群方案比较 哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态&#xff0c;如果master节点异常&#xff0c;则会做主从切换&#xff0c;将某一台slave作为master&#xff0c…

指引型树型组件的封装

最近&#xff0c;由于业务的需要&#xff0c;需要做一个指向形树型组件。在寻找各种文章后&#xff0c;终于有了思路。&#x1f912;&#x1f912;&#x1f912; 树型组件的思路主要是递归。谈到递归&#xff0c;我们首先要有递归的出口。递归的出口就是没有孩子节点了。这个时…

ESP32主板-MoonESP32

产品简介 Moon-ESP32主板&#xff0c;一款以双核芯片ESP32-E为主芯片的主控板&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;低功耗&#xff0c;板载LED指示灯&#xff0c;引出所有IO端口&#xff0c;并提供多个I2C端口、SPI端口、串行端口&#xff0c;方便连接&#xff0c;…

性能监控-grafana+prometheus+node_exporter

Prometheus是一个开源的系统监控和报警工具。它由SoundCloud开发并于2012年发布&#xff0c;后来成为了一个独立的开源项目&#xff0c;并得到了广泛的应用和支持。 Prometheus的主要功能包括采集和存储各种系统和应用程序的监控数据&#xff0c;并提供强大的查询语言PromQL来…

【C++基础】观察者模式(“发布-订阅”模式)

本文参考&#xff1a;观察者模式 - 摩根斯 | 爱编程的大丙 观察者模式允许我们定义一种订阅机制&#xff0c;可在对象事件发生时通知所有的观察者对象&#xff0c;使它们能够自动更新。观察者模式还有另外一个名字叫做“发布-订阅”模式。 发布者&#xff1a; 添加订阅者&…

K8s上安装gitlab-ce

文章目录 K8s上安装gitlab-ce操作如下gitlab-deployment.yml K8s上安装gitlab-ce 前言   使用pv-pvc来持久化gitlab的数据&#xff0c;配置&#xff0c;日志文件。   pod启动后需要需要修改external_url然后重启pod。 操作如下 mkdir -p /mnt/data01/gitlab ctr -n k8s.…

自动驾驶多任务框架Hybridnets——同时处理车辆检测、可驾驶区域分割、车道线分割模型部署(C++/Python)

一、多感知任务 在移动机器人的感知系统&#xff0c;包括自动驾驶汽车和无人机&#xff0c;会使用多种传感器来获取关键信息&#xff0c;从而实现对环境的感知和物体检测。这些传感器包括相机、激光雷达、雷达、惯性测量单元&#xff08;IMU&#xff09;、全球导航卫星系统&am…

PSP - 蛋白质序列提取 Transformer 蛋白质语言模型 ESM2 特征

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132888139 蛋白质语言模型 ESM (Evolutionary Scale Modeling) 是一种利用深度学习技术来预测蛋白质结构和功能的方法。ESM 通过在大规模的蛋白质…

【毕设选题】 大数据二手房数据爬取与分析可视化 -python 数据分析 可视化

# 1 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。 为了大家能够顺利以及最少的精力通…

​Qt for Python 入门¶​

本页重点介绍如何从源代码构建Qt for Python&#xff0c;如果你只想安装PySide2。 与你需要运行&#xff1a;pip pip install pyside2有关更多详细信息&#xff0c;请参阅我们的快速入门指南。此外&#xff0c;您可以 查看与项目相关的常见问题解答。 一般要求 Python&#xf…