[英]Dynamically assign special methods to objects but not classes in Python
我要執行以下操作:
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()
但這看起來很丑。
謝謝。
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
>>>
這是花哨的版本,您在其中“使其看起來像”是將特殊方法分配為實例屬性(盡管在幕后它仍然屬於該類):
>>> 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)
請注意, a.__int__
不會是方法(只有屬於類屬性的函數將成為方法),因此self
不會隱式傳遞。
關於覆蓋__int__
的細節,我沒有什么要補充的。 但是我注意到關於您的樣本的一件事需要討論。
當您為對象手動分配新方法時, 不會自動傳遞“ self”。我已經修改了示例代碼以使觀點更清楚:
class A(object): pass
a = A()
a.foo = lambda self: 3
a.foo()
如果運行此代碼,則會引發異常,因為您將0個參數傳遞給了“ foo”,並且需要1。 如果刪除“自我”,則可以正常工作。
Python僅在必須在對象類中查找方法並且發現的函數是“常規”函數時,才自動在參數前添加“自我”。 (“異常”函數的示例:類方法,可調用對象,綁定方法對象。)如果將可調用對象粘貼到對象本身,它們將不會自動獲得“自我”。
如果您希望自己在那里,請使用閉合。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.