如何改变Python函数的表示形式?

12
>>> def hehe():
...     return "spam"
... 
>>> repr(hehe)
'<function hehe at 0x7fe5624e29b0>'

我想要拥有:

>>> repr(hehe)
'hehe function created by awesome programmer'

我该怎么做?把__repr__放在hehe函数里面不起作用。

编辑:

如果你们想知道我为什么要这样做:

>>> defaultdict(hehe)
defaultdict(<function hehe at 0x7f0e0e252280>, {})

我只是不喜欢它在这里显示的方式。


3
为什么你想这样做? - Daniel Roseman
1
我在我的问题中回答了你的问题。 - arjunaskykok
4个回答

11

不,你不能更改函数对象的表示方式;如果你想要添加文档,你需要添加文档字符串:

def foo():
    """Frob the bar baz"""

并可以通过 help(foo)print foo.__doc__ 访问该内容。

您可以使用自定义的__repr__创建可调用对象,它的行为就像一个函数:

class MyCallable(object):
    def __call__(self):
        return "spam"
    def __repr__(self):
        return 'hehe function created by awesome programmer'

演示:

>>> class MyCallable(object):
...     def __call__(self):
...         return "spam"
...     def __repr__(self):
...         return 'hehe function created by awesome programmer'
... 
>>> hehe = MyCallable()
>>> hehe
hehe function created by awesome programmer
>>> hehe()
'spam'

函数对象不能被子类化。因此,需要像您所做的那样创建自己的类。 - User

9

通常情况下,当你想要改变函数的某些内容,比如函数签名、函数行为或函数属性时,你应该考虑使用一个装饰器。以下是如何实现你想要的功能:

class change_repr(object):
    def __init__(self, functor):
        self.functor = functor

        #  lets copy some key attributes from the original function
        self.__name__ = functor.__name__
        self.__doc__ = functor.__doc__

    def __call__(self, *args, **kwargs):
        return self.functor(*args, **kwargs)

    def __repr__(self):
        return '<function %s created by ...>' % self.functor.__name__


@change_repr
def f():
    return 'spam'


print f()  # spam
print repr(f)  # <function hehe created by ...>

请注意,您只能使用基于类的装饰器,因为您需要重写__repr__方法,而这是无法在函数对象中完成的。

“装饰器”似乎是您的装饰器的一个不好的名称(即太通用了!) - Andrew Jaffe

2

虽然不是你问题的直接答案,但也许你真正需要的是文档字符串(docstring)?

>>> def hehe():
...  '''hehe function created by awesome programmer'''
...  return 'spam'
...
>>> help(hehe)
Help on function hehe in module __main__:

hehe()
    hehe function created by awesome programmer

2

这是 Alexander Zhukov 的 答案 的稍微更灵活的版本:

def representation(repr_text):
    class Decorator(object):
        def __init__(self, functor):
            self.functor = functor

        def __call__(self, *args, **kwargs):
            return self.functor(*args, **kwargs)

        def __repr__(self):
            return (repr_text % self.functor.__name__ if '%' in repr_text
                    else repr_text)

    return Decorator

from collections import defaultdict

@representation('<function %s created by awesome programmer>')
def f():
    return list

dd = defaultdict(f)
print repr(dd)

输出:

defaultdict(<function f created by awesome programmer>, {})

由于representation()返回一个修饰器,如果您希望在多个函数上使用相同的样板代码,可以这样做:

myrepr = representation('<function %s created by awesome programmer>')

@myrepr
def f():
    ...

@myrepr
def g():
    ...

etc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接