我可以更改Python绑定的方法对象吗';s\uuuu str\uuuuu()属性?

我可以更改Python绑定的方法对象吗';s\uuuu str\uuuuu()属性?,python,python-3.x,instance,overriding,Python,Python 3.x,Instance,Overriding,我想更改类的方法之一的\uu str\uu()属性 (注意:不要与“尝试更改方法\uu str\uu()”混淆。) 我有一个类MyClass,它有一个方法“some_method”。我可以通过以下方式更改MyClass的显示方式: class MyClass(): def __init__(self): pass def some_method(self): pass def __str__(self): return "I'm an instance of MyClas

我想更改类的方法之一的
\uu str\uu()
属性

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

我有一个类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)
我得到:

我是MyClass的一个实例

当我

print(my_class.some_method)
我得到:

我想看到的是:

你在my_类实例中使用的某个_方法

我已尝试覆盖
some\u方法的str方法

def some_method(self):
    def __str__(self):
        return "You dope!"
但是没有爱

试图在IPython对其进行暴力也没有更好的结果:

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

AttributeError:'method'object attribute'\uuuu str\uuuuuuuu'是只读的


是否有一种简单的编程方法(最好是在Python 3中)?

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

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')
演示:

>打印MyClass()。一些方法
在你使用的实例中使用了一些方法!
这是因为函数是;当调用
\uuuu get\uuuu
方法时,它们返回方法。

只需在方法上方添加
@toStr(“这是%s您的摄影!: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
Called re-repred method.
rc.re_repr_method.__name__ = re_repr_method
Test of custom repr.

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

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


请注意,在
\uu init\uuuu
中需要
self.some\u method.real\u self=self
,以确保将正确的
self
传递给包装方法。

我遇到了同样的问题,我对这里的两种解决方案都不满意。Martijn使用描述符的解决方案是正确的方法,但它没有提供装饰器的解决方案那么优雅(而且一些参数名称的选择以及他的解决方案的结构是不必要的混淆)。Navin的解决方案不是一个好方法,因为它需要手动设置“真实自我”;这正是描述符的目的。这里我想覆盖uuu repr uuuu而不是uuu str uuu,但这只是一个细节,解决方案是一样的

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

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)
输出:

I'm an instance of MyClass!
method is doing something... Here is an attrbute... [':D']
This is some_method You Dope! :P
Called re-repred method.
rc.re_repr_method.__name__ = re_repr_method
Test of custom repr.

理解所有这一切的关键是,当您在python中的类声明中编写方法时,您没有做任何特殊的事情——只是在该类的命名空间中定义一个函数。然而,一些语法上的甜点开始起作用(或者至少我相信会发生这种情况):Python然后将该方法包装在一个描述符中,该描述符处理以类的实例作为自参数调用该函数。所以,我们需要做的就是自己迈出这一步;与其让Python将我们的类级函数转换成一个方法,不如将它封装在一个描述符中,该描述符的u get u u方法返回一个可调用的,其u call u u方法调用我们想要作为方法的函数,但它有一个我们选择的u repr u u方法。

愚蠢的问题:Python方法甚至有属性吗?我不知道python方法是一个对象。。。是吗?@GreenAsJade:一切都是物体。但这并不意味着该语言可以轻松设置属性。@GreenAsJade正如他们所说,一切都是一个对象。是的,绑定方法是一个对象,至于这个问题,我认为你不能在绑定方法对象上设置属性。但是,您可以将函数包装在一个描述符中,该描述符构造一个自定义的绑定方法,比如对象(使用您想要的任何方法)来代替内置的绑定方法类型。如果希望
print[x.some\u method,x.other\u method]
正常工作,则需要替代
\u repr\uu
。在这种情况下,我建议将
保留在字符串周围。在这种情况下,“some_method”是MyClass的类变量吗?@GreenAsJade:所有常规方法也都是类属性;我刚刚制作了一个自定义的。这个实现很奇怪。我花了很长时间才理解您使用
func
self
参数所做的工作。我会发现一个基于decorator的实现更加清晰。@Martijn在我看来,这不是我第一次看到你写“函数是描述符”。但我觉得这是不对的。如果
foo
是一个函数,
hasattr(foo.\uuu class\uuuuuuuuu,“\uuuu get\uuuuuuuuuuu”)
是真的。但是,这并不能使
foo
成为描述符,因为:1/描述符是描述符定义类的实例,2/此实例必须定义为所有者类中的属性。简而言之,描述符是可以通过点符号访问的对象。所以严格来说,任何类之外的自由函数都不是描述符。您是否看到类似的情况?不,描述符是实现。你看过那本书了吗?函数是描述符,因为函数有一个
\uu get\uuu()
方法。在
f(self,*args,**kwargs)
中,实际上是将
\u temp
的实例传递给
f
。这看起来确实不错。我喜欢decorator定义在另一个文件中。我可以把它藏在图书馆里,远离用户。有没有办法让decorator自动提取方法名,而不是手动将其传递给decorator?@JS。是的,我已经修改了它,使用方法的
\uuuu name\uuuu
来生成字符串。这个实现不起作用。该方法接收到错误的
self
@AshwiniChaudhary值。我已修改
\u temp
以存储正确的
self
,并在调用
f
时使用该值。