我想更改某个班级的方法的__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中)?
答案 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>