动态地为对象分配特殊方法,但不为Python分配类

Oli*_*eng 4 python methods dynamic

我想做以下事情:

class A(object): pass

a = A()
a.__int__ = lambda self: 3

i = int(a)
Run Code Online (Sandbox Code Playgroud)

不幸的是,这引发:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: int() argument must be a string or a number, not 'A'
Run Code Online (Sandbox Code Playgroud)

如果我将"特殊"方法分配给A类而不是它的实例,这似乎只能起作用.有任何追索权吗?

我想到的一种方式是:

def __int__(self):
    # No infinite loop
    if type(self).__int__.im_func != self.__int__.im_func:
        return self.__int__()
    raise NotImplementedError()
Run Code Online (Sandbox Code Playgroud)

但这看起来很丑陋.

谢谢.

Ale*_*lli 8

Python总是在类上查找特殊方法,而不是实例(除了旧的,也就是"遗留"类,类 - 它们已经被弃用并且已经在Python 3中消失了,因为奇怪的语义主要来自于查找在实例特殊的方法,所以你真的希望使用它们,相信我- !).

要创建一个特殊的类,其实例可以具有彼此独立的特殊方法,您需要为每个实例提供自己的类 - 然后您可以在实例的(个体)上分配特殊方法而不影响其他实例,并且在以后幸福地生活.如果你想让它看起来像是为一个属性分配实例,而实际上分配给个性化的每个实例类的一个属性,你当然可以通过一个特殊的__setattr__实现来获得它.

这是一个简单的例子,带有明确的"赋值给类"语法:

>>> 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
>>> 
Run Code Online (Sandbox Code Playgroud)

这里是花哨的版本,你可以"让它看起来像"你将特殊方法指定为实例属性(在场景后面它仍然会进入类):

>>> 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
Run Code Online (Sandbox Code Playgroud)