5

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

def remove_empty(fn):
    def filtered():
        return filter(lambda x: x != '', fn())
    return filtered

对此:

some_string.split('\n')

为了删除空字符串。是否可以?甚至是个好主意?

4

3 回答 3

6

从某种意义上说是可能的;这取决于你的意思。像这样的装饰器语法......

@dec
def foo():
    pass

真的只是糖:

def foo():
    pass
foo = dec(foo)

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

func = dec(func)

但是内置类的方法存在于该类的命名空间中,并且不能直接修改该命名空间,正如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']

或者更直接(更符合装饰器使用的精神):

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

在这个特定示例的情况下,我更喜欢显式过滤器。但我可以想象,例如,一个内置类的子类,它做一些记忆或类似的事情。

于 2012-09-18T12:14:47.060 回答
5

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

str.split = remove_empty(str.split)

但这是不允许的:

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'
于 2012-09-18T11:52:42.107 回答
1

当然是的。写吧

remove_empty(lambda: some_string.split('\n'))()
于 2012-09-18T11:51:35.820 回答