簡體   English   中英

動態地將特殊方法分配給對象,而不是Python中的類

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM