我想做以下事情:
class A(object): pass
a = A()
a.__int__ = lambda self: 3
i = int(a)
不幸的是,这引发了:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string or a number, not 'A'
如果我将“特殊”方法分配给A类而不是它的实例,这似乎只有作用。有没有追索权?
我想到的一种方式是:
def __int__(self):
# No infinite loop
if type(self).__int__.im_func != self.__int__.im_func:
return self.__int__()
raise NotImplementedError()
但这看起来很丑陋。
感谢。
答案 0 :(得分:8)
Python总是在类上查找特殊方法,而不是实例(除了旧的,又称“遗留”类的类 - 它们已经被弃用并且已经在Python 3中消失了,因为奇怪的语义是主要是在实例上查找特殊方法,所以你真的不想要使用它们,相信我! - 。)。
要创建一个特殊的类,其实例可以具有彼此独立的特殊方法,您需要为每个实例提供自己的类 - 然后您可以在实例的(个体)类上分配特殊方法在不影响其他情况的情况下,从此过上幸福的生活。如果你想让它看起来像你正在为一个属性分配实例,而实际上分配给个性化的每个实例类的一个属性,你当然可以用一个特殊的__setattr__
实现来实现。< / p>
这是一个简单的例子,带有明确的“赋值给类”语法:
>>> class Individualist(object):
... def __init__(self):
... self.__class__ = type('GottaBeMe', (self.__class__, object), {})
...
>>> a = Individualist()
>>> b = Individualist()
>>> a.__class__.__int__ = lambda self: 23
>>> b.__class__.__int__ = lambda self: 42
>>> int(a)
23
>>> int(b)
42
>>>
这里是花哨的版本,你可以“让它看起来像”你将特殊方法指定为一个实例属性(当然在场景后面它仍然属于课程):
>>> class Sophisticated(Individualist):
... def __setattr__(self, n, v):
... if n[:2]=='__' and n[-2:]=='__' and n!='__class__':
... setattr(self.__class__, n, v)
... else:
... object.__setattr__(self, n, v)
...
>>> c = Sophisticated()
>>> d = Sophisticated()
>>> c.__int__ = lambda self: 54
>>> d.__int__ = lambda self: 88
>>> int(c)
54
>>> int(d)
88
答案 1 :(得分:2)
适用于新式类的唯一方法是在类上调用属性的方法(如果存在):
class A(object):
def __int__(self):
if '__int__' in self.__dict__:
return self.__int__()
raise ValueError
a = A()
a.__int__ = lambda: 3
int(a)
请注意,a.__int__
不是方法(只有属于类的属性的函数才会成为方法),因此self
不会隐式传递。
答案 2 :(得分:0)
关于覆盖__int__
的具体细节,我没有任何补充。但是我注意到你的样本有一件事需要讨论。
当你手动为对象分配新方法时,“self”不会自动传入。我修改了你的示例代码,使我的观点更加清晰:
class A(object): pass
a = A()
a.foo = lambda self: 3
a.foo()
如果运行此代码,则会抛出异常,因为您将0个参数传递给“foo”,并且需要1。如果你删除“自我”它可以正常工作。
如果必须在对象的类中查找方法并且它找到的函数是“正常”函数,Python只会自动为参数添加“self”。 (“异常”函数的示例:类方法,可调用对象,绑定方法对象。)如果将callables粘贴到对象本身,它们将不会自动获得“self”。
如果您想要自己,请使用闭包。