use*_*873 1 python python-2.7 python-3.x
我是python编程的新手,我想知道如何增强内置函数的功能(Monkeypatch)
例如
我知道sum()内置函数只允许在数字项上
>>> sum([4,5,6,7]) #22
Run Code Online (Sandbox Code Playgroud)
我想使sum函数允许项目列表为字符串,如下所示
例如
>>> sum(['s','t','a','c','k']) # 'stack'
Run Code Online (Sandbox Code Playgroud)
提前致谢
aba*_*ert 12
你不能像类,对象,模块等那样真正"monkeypatch"一个函数.
其他所有东西最终都归结为属性集合,因此用不同的属性替换一个属性或添加新属性既简单又有用.另一方面,功能基本上是原子的.*
当然,您可以通过替换sum函数来monkeypatch内置模块.但我不认为这就是你所要求的.(如果你是,见下文.)
无论如何,你不能修补sum,但你可以编写一个新的功能,如果你想要的话,可以使用相同的名称(可能有一个原始函数的包装器 - 你会注意到,这正是装饰器所做的).
但实际上没有办法用来sum(['s','t','a','c','k'])做你想做的事情,因为sum默认情况下从0开始并添加内容.并且您不能将字符串添加到0.**
当然,您总是可以传递显式start而不是使用默认值,但您必须更改您的调用代码以发送相应的start.在某些情况下(例如,您发送文字列表显示的地方),这很明显; 在其他情况下(例如,在通用功能中)它可能不是.这仍然无法在这里工作,因为sum(['s','t','a','c','k'], '')只会提出一个TypeError(尝试并阅读错误以了解原因),但它会在其他情况下起作用.
但是没有办法避免必须知道适当的起始值sum,因为这是sum有效的.
如果你考虑一下,sum概念上相当于:
def sum(iterable, start=0):
reduce(operator.add, iterable, start)
Run Code Online (Sandbox Code Playgroud)
这里唯一真正的问题是start,对吗?reduce允许你保留起始值,它将从iterable中的第一个值开始:
>>> reduce(operator.add, ['s', 't', 'a', 'c', 'k'])
'stack'
Run Code Online (Sandbox Code Playgroud)
那是sum不可能做到的.但是,如果你真的想,你可以重新定义sum它可以:
>>> def sum(iterable):
... return reduce(operator.add, iterable)
Run Code Online (Sandbox Code Playgroud)
… 要么:
>>> sentinel = object()
>>> def sum(iterable, start=sentinel):
... if start is sentinel:
... return reduce(operator.add, iterable)
... else:
... return reduce(operator.add, iterable, start)
Run Code Online (Sandbox Code Playgroud)
但请注意,sum对于整数而言,这将比原始序列慢得多,并且它将引发一个TypeError而不是返回0空序列,依此类推.
如果你确实想要monkeypatch内置函数(而不是仅仅使用新名称定义一个新函数,或者在模块中使用同名的新函数来隐藏内置函数globals()),这里有一个适用于Python 3.1+的示例,只要你的模块使用普通的全局字典(除非你在嵌入式解释器或exec调用或类似的程序中运行,否则它们将是这样的):
import builtins
builtins.sum = _new_sum
Run Code Online (Sandbox Code Playgroud)
换句话说,与monkeypatching任何其他模块相同.
在2.x中,调用模块__builtin__.关于它如何通过全局变量访问的规则在2.3左右变化,在3.0中再变化.查看builtins/ __builtin__了解详情.
*当然,这不是很真实.函数在其代码对象之上具有名称,闭包单元列表,文档字符串等.甚至代码对象也是一系列字节码,您可以使用bytecodehacks或硬编码hackery.除了它sum实际上是一个内置函数,而不是一个函数,所以它甚至没有可以从Python访问的代码......无论如何,它足够接近大多数目的来说函数是原子的东西.
**当然,你可以将字符串转换为一些知道如何将自身添加到整数的子类(通过忽略它们),但实际上,你不想这样做.
不是猴子修补,只是重新定义sum,以使其适用于字符串.
>>> import __builtin__
def sum(seq, start = 0):
if all(isinstance(x,str) for x in seq):
return "".join(seq)
else:
return __builtin__.sum(seq, start)
...
>>> sum([4,5,6,7])
22
>>> sum(['s','t','a','c','k'])
'stack'
Run Code Online (Sandbox Code Playgroud)