functools下的partial模块应用
问题
你有一个被其他python代码使用的callable对象,可能是一个回调函数或者是一个处理器, 但是它的参数太多了,导致调用时出错。
解决方案
如果需要减少某个函数的参数个数,你可以使用 functools.partial() 。 partial() 函数允许你给一个或多个参数设置固定的值,减少接下来被调用时的参数个数。 为了演示清楚,假设你有下面这样的函数:
def spam(a, b, c, d):
print(a, b, c, d)
现在我们使用 partial() 函数来固定某些参数值:
>>> from functools import partial
>>> s1 = partial(spam, ) # a =
>>> s1(, , ) >>> s1(, , ) >>> s2 = partial(spam, d=) # d =
>>> s2(, , ) >>> s2(, , ) >>> s3 = partial(spam, , , d=) # a = , b = , d =
>>> s3() >>> s3() >>> s3() >>>
可以看出 partial() 固定某些参数并返回一个新的callable对象。这个新的callable接受未赋值的参数, 然后跟之前已经赋值过的参数合并起来,最后将所有参数传递给原始函数。
讨论
本节要解决的问题是让原本不兼容的代码可以一起工作。下面我会列举一系列的例子。
第一个例子是,假设你有一个点的列表来表示(x,y)坐标元组。 你可以使用下面的函数来计算两点之间的距离:
points = [ (, ), (, ), (, ), (, ) ] import math
def distance(p1, p2):
x1, y1 = p1
x2, y2 = p2
return math.hypot(x2 - x1, y2 - y1)
说明一下这里的math.hypot默认是以坐标原点为几点计算坐标到原点的直线距离
import math
print(math.hypot(,))
>>>
现在假设你想以某个点为基点,根据点和基点之间的距离来排序所有的这些点。 列表的 sort() 方法接受一个关键字参数来自定义排序逻辑, 但是它只能接受一个单个参数的函数(distance()很明显是不符合条件的)。 现在我们可以通过使用 partial() 来解决这个问题:
>>> pt = (, )
>>> points.sort(key=partial(distance,pt))
>>> points
[(, ), (, ), (, ), (, )]
>>>
更进一步,partial() 通常被用来微调其他库函数所使用的回调函数的参数。 例如,下面是一段代码,使用 multiprocessing 来异步计算一个结果值, 然后这个值被传递给一个接受一个result值和一个可选logging参数的回调函数:
def output_result(result, log=None):
if log is not None:
log.debug('Got: %r', result) # A sample function
def add(x, y):
return x + y if __name__ == '__main__':
import logging
from multiprocessing import Pool
from functools import partial logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('test') p = Pool()
p.apply_async(add, (, ), callback=partial(output_result, log=log))
p.close()
p.join()
当给 apply_async() 提供回调函数时,通过使用 partial() 传递额外的 logging 参数。 而 multiprocessing 对这些一无所知——它仅仅只是使用单个值来调用回调函数。
作为一个类似的例子,考虑下编写网络服务器的问题,socketserver 模块让它变得很容易。 下面是个简单的echo服务器:
from socketserver import StreamRequestHandler, TCPServer class EchoHandler(StreamRequestHandler):
def handle(self):
for line in self.rfile:
self.wfile.write(b'GOT:' + line) serv = TCPServer(('', ), EchoHandler)
serv.serve_forever()
不过,假设你想给EchoHandler增加一个可以接受其他配置选项的 __init__ 方法。比如:
class EchoHandler(StreamRequestHandler):
# ack is added keyword-only argument. *args, **kwargs are
# any normal parameters supplied (which are passed on)
def __init__(self, *args, ack, **kwargs):
self.ack = ack
super().__init__(*args, **kwargs) def handle(self):
for line in self.rfile:
self.wfile.write(self.ack + line)
这么修改后,我们就不需要显式地在TCPServer类中添加前缀了。 但是你再次运行程序后会报类似下面的错误:
Exception happened during processing of request from ('127.0.0.1', )
Traceback (most recent call last):
...
TypeError: __init__() missing required keyword-only argument: 'ack'
初看起来好像很难修正这个错误,除了修改 socketserver 模块源代码或者使用某些奇怪的方法之外。 但是,如果使用 partial() 就能很轻松的解决——给它传递 ack 参数的值来初始化即可,如下:
from functools import partial
serv = TCPServer(('', ), partial(EchoHandler, ack=b'RECEIVED:'))
serv.serve_forever()
在这个例子中,__init__() 方法中的ack参数声明方式看上去很有趣,其实就是声明ack为一个强制关键字参数。 关于强制关键字参数问题我们在7.2小节我们已经讨论过了,读者可以再去回顾一下。
很多时候 partial() 能实现的效果,lambda表达式也能实现。比如,之前的几个例子可以使用下面这样的表达式:
points.sort(key=lambda p: distance(pt, p))
p.apply_async(add, (, ), callback=lambda result: output_result(result,log))
serv = TCPServer(('', ),
lambda *args, **kwargs: EchoHandler(*args, ack=b'RECEIVED:', **kwargs))
这样写也能实现同样的效果,不过相比而已会显得比较臃肿,对于阅读代码的人来讲也更加难懂。 这时候使用 partial() 可以更加直观的表达你的意图(给某些参数预先赋值)。
functools下的partial模块应用的更多相关文章
- windows下安装python模块
如何在windows下安装python模块 1. 官网下载安装包,比如(pip : https://pypi.python.org/pypi/pip#downloads) pip-9.0.1.tar. ...
- Linux下安装opencv模块
最近微信上流行的给自己的头像加一顶圣诞帽,想用python写一个程序自己实现一下,其中需要用到opencv import cv2 现在记录一下如何在Linux系统(ubutun)下安装该模块: 参考了 ...
- debian+python3.5环境下安装paramiko模块:
debian+python3.5环境下安装paramiko模块: 1.确保安装了操作系统安装了libssl-dev,zlib1g-dev (redhat,centos下这两包包名为openssl-d ...
- 【LDAP安装】在已编译安装的PHP环境下安装LDAP模块
在已编译安装的PHP环境下安装LDAP模块 (乐维温馨提示:其他模块也能以这个方式安装) 1.在PHP源码包内找到ldap模块文件 cd php-5.6.37 cd ext/ldap/ 2.phpiz ...
- python下的select模块使用 以及epoll与select、poll的区别
python下的select模块使用 以及epoll与select.poll的区别 先说epoll与select.poll的区别(总结) 整理http://www.zhihu.com/question ...
- selenium从入门到应用 - 5,页面对象设计模式下的页面模块
本系列所有代码 https://github.com/zhangting85/simpleWebtest 本文将介绍一个Java+TestNG+Maven+Selenium的web自动化测试脚本环境下 ...
- PHP window下安装Spl_Types模块
1. Window下,Spl_Types的模块的下载地址:http://pecl.php.net/package/SPL_Types/0.4.0/windows 2. php的可执行文件已经加到系统的 ...
- linux下利用GPRS模块发短信、打电话
一.开发环境 内核版本:linux-3.0 开发板:FL2440(nandflash:K9F1G08 128M) GPRS模块:SIM900 二.与发短信和拨号相关的 AT 指 ...
- mac下Nginx+lua模块编译安装
Nginx的nb之处就不说了,lua也是一个小巧的脚本语言,由标准C编写而成,几乎可以运行在所有的平台上,也非常强大,其他特性请自行度娘.nginx_lua_module是由淘宝的工程师清无(王晓哲) ...
随机推荐
- win7 中 sql server2005 卸载简介
注:卸载前一定要做好备份,一定要清理干净,不然重装会出错(只针对完全卸载,没试过只删除一个版本的) 工具:①Windows Install Clean Up ②SrvInstw.exe 1.停止所有 ...
- tesseract-ocr安装问题
今天安装tesseract-ocr的时候,载了坑,记录一下. 1. 安装时语言库的选择,我把 aditional language data 这一项全选中了,装的时候那叫一个慢啊,差不多3个小时装好的 ...
- 使用 cmd连接 Oracle,MySql,SQL Server 数据库
1. Oracle cmd连接数据库 语法: sqlplus 用户/口令(密码)@服务器IP/数据库实例名(SID) 1.1 方式一 数据库服务在本机上IP可以用localhost替换 sqlplus ...
- shell 关于字符切割 cut
shell中运用于字符切割的是cut 其中 参数分别代表得意义是: -d :后面接分隔字符,将一段信息分割为数段,与 -f 一起使用 -f :将-d分割出来的数段 用 -f 取出第几段的意思 -c : ...
- netsh winsock reset命令,作用是重置 Winsock 目录
Win xp重置 编辑 要为 Windows XP 重置 Winsock,请按照下列步骤操作: 1.单击“开始”,运行中输入cmd. 2.然后输入命令 netsh winsock reset. 3.重 ...
- 华为无线AP4030,FIA--FAT模式更改
因为买回来的时候才注意到是APfit模式的,只是想作为一个无线路由点接入网络的,只有更改模式,在网上找了很多,实验了两天也还是成功了. 1.准备工具:网线.console线一条.TFTP软件或者FTP ...
- LeetCode算法题-Reverse String(Java实现)
这是悦乐书的第205次更新,第217篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第73题(顺位题号是344).编写一个以字符串作为输入并返回字符串的函数.例如: 输入: ...
- 团队作业—预则立&&他山之石
团队作业-预则立&&他山之石 Deadline: 2017.10.24 22:00pm 作业要求 一.确立团队选题,建立和初步熟悉团队git的协作方式.项目后续的代码.文档都要通过gi ...
- [福大软工] Z班——个人技术博客评分
个人技术博客 作业地址 https://edu.cnblogs.com/campus/fzu/SoftwareEngineering2015/homework/1070 作业要求 个人技术博客单次作业 ...
- spring简述
1. 什么是Spring Spring:SE/EE开发的一站式框架.(有EE开发每一层的解决方案) WEB层:SpringMVC Service层:Spring的Bean管理,Spring的声明式事务 ...