是否可以将我自己的装饰器应用于Python中的内置方法?

mus*_*rat 4 python decorator

我刚刚遇到Python装饰器.只是出于兴趣,您可以以某种方式将自己的装饰器应用于内置对象方法吗?说我想申请这个:

def remove_empty(fn):
    def filtered():
        return filter(lambda x: x != '', fn())
    return filtered
Run Code Online (Sandbox Code Playgroud)

对此:

some_string.split('\n')
Run Code Online (Sandbox Code Playgroud)

为了删除空字符串.可能吗?甚至是个好主意?

sen*_*rle 6

在某种意义上它是可能的; 这取决于你究竟是什么意思.像这样的装饰器语法......

@dec
def foo():
    pass
Run Code Online (Sandbox Code Playgroud)

这真的只是糖:

def foo():
    pass
foo = dec(foo)
Run Code Online (Sandbox Code Playgroud)

因此,没有什么可以阻止您在全局命名空间中的预定义函数上使用装饰器.

func = dec(func)
Run Code Online (Sandbox Code Playgroud)

但是内置类的方法存在于该类的命名空间中,并且该命名空间不能直接修改,正如chepner已经指出的那样.这是一件好事,因为它确保了类型的对象str将按预期运行!但是,你可以继承 str并以这种方式装饰方法.(以下在Python 2中有效;在Python 3中,将输出传递filter给列表.super也可能有点不同;我将来会发布Python 3更新.)

>>> def remove_empty(fn):
...     def filtered(*args, **kwargs):
...         return filter(lambda x: x != '', fn(*args, **kwargs))
...     return filtered
... 
>>> class WeirdString(str):
...     @remove_empty
...     def split(self, *args, **kwargs):
...         return super(WeirdString, self).split(*args, **kwargs)
... 
>>> 'This decorator is unnecessary\n\n\n'.split('\n')
['This decorator is unnecessary', '', '', '']
>>> WeirdString('This decorator is unnecessary\n\n\n').split('\n')
['This decorator is unnecessary']
Run Code Online (Sandbox Code Playgroud)

或更直接(以及更多的装饰精神使用):

>>> class WeirdString2(str):
...     split = remove_empty(str.split)
... 
>>> WeirdString2('This decorator is unnecessary\n\n\n').split('\n')
['This decorator is unnecessary']
Run Code Online (Sandbox Code Playgroud)

在这个特定示例的情况下,我更喜欢显式过滤器.但是我可以想象,例如,一个内置类的子类做一些memoization或类似的东西.


che*_*ner 5

恐怕答案是否定的。装饰器在定义函数时应用,并且str.split是预定义的。你可能认为你可以做一些明确的事情,比如

str.split = remove_empty(str.split)
Run Code Online (Sandbox Code Playgroud)

但这是不允许的:

Traceback (most recent call last):
  File "tmp.py", line 8, in <module>
    str.split = remove_empty(str.split)
TypeError: can't set attributes of built-in/extension type 'str'
Run Code Online (Sandbox Code Playgroud)