Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中,动态地将特殊方法分配给对象,而不是类_Python_Dynamic_Methods - Fatal编程技术网

在Python中,动态地将特殊方法分配给对象,而不是类

在Python中,动态地将特殊方法分配给对象,而不是类,python,dynamic,methods,Python,Dynamic,Methods,我想做以下工作: 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' 但这看起来相当丑陋

我想做以下工作:

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'
但这看起来相当丑陋


谢谢。

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

要创建一个特殊的类,其实例可以具有相互独立的特殊方法,您需要为每个实例提供自己的类——然后您可以在不影响其他实例的情况下为实例的(单个)类分配特殊方法,并从此过上幸福的生活。如果您想让它看起来像是在为实例分配属性,而实际上是为每个实例类的个性化属性分配属性,那么您当然可以通过一个特殊的
\uuuuuu setattr\uuuu
实现来实现

下面是一个简单的例子,使用显式的“assign to class”语法:

这是一个奇特的版本,您“让它看起来像”将特殊方法指定为实例属性(当然,在幕后它仍然属于类):


对于新样式的类,唯一可行的方法是在类上有一个调用实例属性的方法(如果存在):


请注意,
a.\uuuuu int\uuuu
将不是一个方法(只有作为类属性的函数才会成为方法),因此
self
不会隐式传递。

关于重写
\uuuuu int\uu
的细节,我没有任何补充。但我注意到你的样品有一点值得讨论

手动为对象分配新方法时,“self”不会自动传入。我已经修改了您的示例代码,以使我的观点更清楚:

class A(object): pass

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

a.foo()
如果您运行此代码,它会引发异常,因为您向“foo”传递了0个参数,而1是必需的。如果删除“self”,效果很好

如果Python必须在对象类中查找方法,并且找到的函数是“普通”函数,则Python只会自动在参数前加上“self”。(异常函数的示例:类方法、可调用对象、绑定方法对象。)如果将可调用对象粘贴到对象本身,它们不会自动获得“self”


如果您想让self留在那里,请使用闭包。

谢谢。这看起来比使用Thomas的方法更干净,因为我想要所有的特殊方法。速度也应该提高。那么我就在基类中重写new。@MTsoul,如果您愿意,当然可以使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu.如果c和d都更改了它们的class属性,代码示例如何工作?一个类的所有实例不是都共享同一个class属性吗?这就是为什么我想使用new,并为每个需要自己特殊方法的对象创建一个新类。@MTsoul,
assert c.\uuuuu class\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu有一个语句
self.\uuuuu class\uuuu=…
,它为每个成员创建并设置一个原始的新类对象<代码>\uuuuuuuuuu
可以像
\uuuuuuuuuuu
一样做的很好,但是我更喜欢在可行的地方(比如这里!)使用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,而
只能用于工作
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!非常感谢,Alex。我应该补充一点,您不必像调用特殊方法一样调用从特殊方法调用的实例属性——事实上,您可能不应该这样做。
>>> 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
class A(object):
    def __int__(self):
        if '__int__' in self.__dict__:
            return self.__int__()
        raise ValueError

a = A()
a.__int__ = lambda: 3
int(a)
class A(object): pass

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

a.foo()