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

问题描述 投票:12回答:3

我想改变我的一个类的方法的__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中)?

python python-3.x instance method-overriding
3个回答
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__方法时,他们返回方法。


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传递给包装方法。


0
投票

我遇到了同样的问题,我对这里的任何一个解决方案都不满意。 Martijn使用描述符的解决方案是正确的方法,但它并不像提供装饰器的解决方案那样优雅(参数名称的一些选择以及他的解决方案的结构不必要地混淆)。 Navin的解决方案不是一个好方法,因为它需要手动设置“real_self”;这正是描述符的目的。在这里,我想覆盖__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__方法。

© www.soinside.com 2019 - 2024. All rights reserved.