2013-04-06 54 views
5

相關:Python object conversionPython:是否有更改實例類的用例?

我最近才知道,Python允許你改變一個實例的類,像這樣:

class Robe: 
    pass 

class Dress: 
    pass 

r = Robe() 
r.__class__ = Dress 

我試圖找出是否有這樣的情況,「蛻變」的對象像這可能是有用的。我在IDLE中搞砸了,有一點我注意到,分配一個不同的類不會調用新類的方法,儘管如果需要的話可以明確地完成。

幾乎每個我能想到的用例都會更好地服務於構圖,但我是一個編碼newb,所以我知道什麼。 ;)

回答

6

對於無關的類,很少有很好的理由對此進行此操作,例如RobeDress。沒有一點工作,很難確保你最終得到的對象處於健全的狀態。

但是,從基類繼承時,如果要使用非標準的工廠函數或構造函數來構建基礎對象,它可能很有用。下面是一個例子:

class Base(object): 
    pass 

def base_factory(): 
    return Base() # in real code, this would probably be something opaque 

def Derived(Base): 
    def __new__(cls): 
     self = base_factory()  # get an instance of Base 
     self.__class__ = Derived # and turn it into an instance of Derived 
     return self 

在這個例子中,派生類的__new__方法要使用base_factory方法,該方法返回Base類的實例來構造它的對象。通常這種工廠在圖書館的某個地方,並且你無法確定它是如何製作這個物品的(你不能只是自己撥打Base()或以得到相同的結果)。

的實例的屬性__class__被重寫,使得主叫Derived.__new__的結果將是Derived類,這保證了它會有Derived.__init__方法調用它(如果這樣的方法存在的話)的一個實例。

+0

這個答案看起來很徹底,但我是編程新手,因此很難理解它。忽略'__new__' /構造函數方面,我可以看到,如果某個庫中某個類定義了一個類,並且已經創建了自己的繼承它的類,那麼可以通過創建一個實例來創建後者的一個實例前者然後「轉化」。但是,爲什麼不簡單地實例化繼承類呢?我承認我不理解構造函數的概念或'__new__'方法的功能。 – henrebotha 2013-04-07 18:48:10

+1

@henrebotha:我建議閱讀關於[Python數據模型](http://docs.python.org/3/reference/datamodel.html#basic-customization)。調用類的'__new__'方法來構造它的實例。調用Derived()會觸發對Derived .__ new__的調用(如果存在)。通常'__new__'返回由'object .__ new__'創建的一個新對象(通過'super'調用),但它不必這樣做。在上面的例子中,我們從工廠函數中獲取了實例,然後對其進行了自定義。另見[這個前面的問題](http://stackoverflow.com/questions/15330755/construct-class-from-superclass-instance)。 – Blckknght 2013-04-07 19:42:51

2

我記得很久以前使用這種技術來在識別它們所持有的數據類型後「升級」現有對象。它是實驗性XMPP客戶端的一部分。 XMPP使用許多簡短的XML消息(「節」)進行通信。

當應用程序收到一個節時,它被解析爲一個DOM樹。然後,應用程序需要識別它是什麼樣的節(存在節,消息,自動查詢等)。例如,如果它被識別爲消息節,則DOM對象被「升級」爲提供諸如「get_author」,「get_body」等方法的子類。

我當然可以創建一個新類表示解析的消息,創建該類的新對象並從原始XML DOM對象複製相關數據。不過,改變對象類的好處有兩個。首先,XMPP是一個非常可擴展的標準,在代碼的其他部分在那裏或在調​​試時發現有用的情況下,仍然可以輕鬆訪問原始DOM對象。其次,剖析代碼告訴我,創建一個新對象,並明確地將數據複製不僅僅是重複使用會很快地消滅無論如何,差異有足夠的XMPP,它使用許多短消息到重要對象慢得多。

我不認爲任何這些理由證明在生產代碼中使用該技術的,除非也許你真的需要的CPython的(不是大)加速。這只是一個破解,我發現它有助於在實驗應用程序中使代碼變得更短更快。還要注意,這種技術很容易在非CPython實現中破壞JIT引擎,使代碼變得更慢!

+0

關於JIT編譯器有趣的地方。 – henrebotha 2013-04-06 21:50:58

相關問題