我可以更改Python绑定方法对象的__str __()属性吗?

时间:2014-01-25 00:19:46

标签: python python-3.x instance method-overriding

我想更改某个班级的方法__str__()属性。

(注意:不要与“尝试更改方法__str__()”混淆。)

我有一个MyClass类,它有一个方法'some_method'。我可以改变MyClass显示方式:

class MyClass():
    def __init__(self): pass
    def some_method(self): pass
    def __str__(self): return "I'm an instance of MyClass!"

当我实例化并打印MyClass时:

print(my_class)

我明白了:

I'm an instance of MyClass!

当我

print(my_class.some_method)

我明白了:

<bound method my_class.some_method of <gumble margle object at mumble-jumble>>

我想改为:

some_method in the instance my_class you Dope!

我已尝试覆盖some_method str 方法:

def some_method(self):
    def __str__(self):
        return "You dope!"

但没有爱。

试图在IPython中暴力破坏它并没有改善:

my_class.some_method.__str__ = lambda: "You Dope!"

,得到

AttributeError: 'method' object attribute '__str__' is read-only

是否有一种简单的方法可以以编程方式执行此操作(最好是在Python 3中)?

3 个答案:

答案 0 :(得分:7)

您需要使用自定义类而不是类函数:

class CustomFunction(object):
    def __init__(self, name):
        self.name = name

    def __call__(func, self):
        # This is the actual function
        pass

    def __get__(func, instance=None, type_=None):
        class CustomMethod(object):
            def __init__(self, instance, type_):
                self.im_self = instance
                self.im_class = type_
            def __call__(self, *args, **kw):
                return func(self.im_self, *args, **kw)
            def __str__(self):
                return '{} in the instance {} you Dope!'.format(func.name, self.im_self)

        return CustomMethod(instance, type_)

然后在你的课堂上使用它:

class MyClass():
    def __init__(self): pass

    some_method = CustomFunction('some_method')

演示:

>>> print MyClass().some_method
some_method in the instance <__main__.MyClass instance at 0x106b5ccb0> you Dope!

这是有效的,因为函数是descriptors;他们在调用__get__方法时返回方法。

答案 1 :(得分:3)

只需在方法上方添加@toStr("This is %s You Dope! :P")

class MyClass():
    @toStr("This is %s You Dope! :P")
    def some_method(self):
        print("method is doing something... Here is an attrbute... "+str(self.kk))
    def __str__(self): return "I'm an instance of MyClass!"
    def __init__(self):
        self.some_method.real_self = self
        self.kk = [":D"]
c = MyClass()
print(c)
c.some_method()
print(c.some_method)

输出:

I'm an instance of MyClass!
method is doing something... Here is an attrbute... [':D']
This is some_method You Dope! :P

在类上方的某处(可能是单独的文件)添加以下内容以创建注释:

def toStr(str):
    def decorator(f):
        class _temp:
            def __call__(self, *args, **kwargs):
                return f(self.real_self, *args, **kwargs)
            def __str__(self):
                return str%f.__name__
        return _temp()
    return decorator

请注意self.some_method.real_self = self中需要__init__才能确保将self传递给包装的方法。

答案 2 :(得分:0)

我遇到了同样的问题,我对这里的任何一种解决方案都不满意。 Martijn使用描述符的解决方案是正确的方法,但它不像提供装饰器的解决方案那样优雅(参数名称的一些选择以及他的解决方案的结构不必要地混淆)。 Navin的解决方案不是一个好方法,因为它需要手动设置&#34; real_self&#34 ;;这正是描述符的目的。在这里,我想覆盖__repr__而不是__str__,但这只是一个细节,解决方案是相同的。

这是我的装饰器,它返回一个描述符解决方案:

from functools import update_wrapper

# the usual outer function to allow the decorator to accept an argument
def custom_repr(repr_text):
    # the decorator itself
    def method_decorator(method):

        # Wrap the method in our own descriptor.
        class CustomReprDescriptor(object):

            def __get__(self, instance, owner):
                # Return our wrapped method when we call instance.method
                # This class encapsulates the method
                class MethodWrapper(object):
                    # Callable with custom __repr__ method
                    # Capture the instance and owner (type) from the __get__ call
                    def __init__(self):
                        self.im_self = instance
                        self.im_class = owner
                        self.im_func = method

                    # Call the wrapped method using the captured instance
                    def __call__(self, *args, **kwargs):
                        return self.im_func(self.im_self, *args, **kwargs)

                    # Capture the custom __repr__ text from the decorator call
                    def __repr__(self):
                        return repr_text
                # The call to __get__ returns our wrapped method with custom __repr__
                return update_wrapper(MethodWrapper(), method)
        # The decorator returns our custom descriptor
        return CustomReprDescriptor()
    return method_decorator

class TestClass(object):

    @custom_repr("Test of custom repr.")
    def re_repr_method(self):
        print "Called re-repred method."

tc = TestClass
tc.re_repr_method()
print "rc.re_repr_method.__name__ = " + tc.re_repr_method.__name__
print repr(tc.re_repr_method)

输出:

Called re-repred method.
rc.re_repr_method.__name__ = re_repr_method
Test of custom repr.

理解所有这一切的关键是当你在python中的类声明中编写一个方法时,你没有做任何特别的事情 - 只是在该类的命名空间中定义一个函数。然而,然后一些语法糖开始(或者至少我相信会发生这种情况):Python然后将该方法包装在描述符中,该描述符处理使用类的实例作为self参数调用该函数。所以,我们所要做的就是自己采取这一步骤;而不是让Python将我们的类级函数转换为方法,只需将它自己包装在一个描述符中,其__get__方法返回一个可调用的,其__call__方法调用我们想要的函数作为我们的方法,但它有我们选择的__repr__方法。 / p>