2010-07-07 19 views
7

下面的代碼不會在Python 3.x的工作,但它使用老式類工作:__bases__不起作用!下一步是什麼?

class Extender: 
    def extension(self): 
     print("Some work...") 

class Base: 
    pass 

Base.__bases__ += (Extender,) 

Base().extension() 

的問題很簡單:我怎樣才能動態地添加(在運行時)一超類到Python 3.x中的類?

但是我已經準備好了,答案很難! )

+9

你的基地不再屬於你嗎?答案會很難? – Borealid 2010-07-07 08:37:55

+0

我認爲這是不可能的,因爲所有的類都是Python 3中的新類,如果'Base'同時具有'object'和'Extender'作爲基類,MRO就會變得模糊不清。改爲創建一個從「Base」和「Extender」繼承的新類。 'Extender'也可能是ABC。 – Philipp 2010-07-07 08:50:43

回答

4

至於我這是不可能的。但是你可以動態地創建新類:

class Extender(object): 
    def extension(self): 
     print("Some work...") 

class Base(object): 
    pass 

Base = type('Base', (Base, Extender, object), {}) 
Base().extension() 
+0

謝謝!你的解決方案運作良好:) 但是我已經更新了一點:$這足以添加一個新的基類:'Base = type('Base',(Extender,),{})'如果添加'Base'和'object 「他們再次在MRO中出現兩次,我認爲解釋器會慢慢尋找屬性。 – DenisKolodin 2010-07-07 10:50:48

+0

@DenisKolodin:MRO中的兩個基地是不同的課程:新課程和舊課程。查看Base [___ mro __]中的cls的[id(cls)],看看它們是不同的。 – unutbu 2010-07-07 12:49:24

+0

我已經完全測試並發現一個嚴重的區別((( )類型將僅針對新實例進行更改,但使用__bases__我可以更改我需要的存在實例中的屬性 此解決方案不相似! ( – DenisKolodin 2010-07-08 07:26:32

3

看來,它可以動態改變Base.__bases__ 如果Base.__base__object。 (通過動態更改,我的意思是,所有從Base繼承的預先存在的實例也會動態更改,否則請參閱Mykola Kharechko's solution)。

如果Base.__base__是一些虛擬的類TopBase,然後分配給Base.__bases__似乎工作:

class Extender(object): 
    def extension(self): 
     print("Some work...") 

class TopBase(object): 
    pass 

class Base(TopBase): 
    pass 

b=Base() 
print(Base.__bases__) 
# (<class '__main__.TopBase'>,) 

Base.__bases__ += (Extender,) 
print(Base.__bases__) 
# (<class '__main__.TopBase'>, <class '__main__.Extender'>) 
Base().extension() 
# Some work... 
b.extension() 
# Some work... 

Base.__bases__ = (Extender, TopBase) 
print(Base.__bases__) 
# (<class '__main__.Extender'>, <class '__main__.TopBase'>) 
Base().extension() 
# Some work... 
b.extension() 
# Some work... 

該測試在Python 2工作(爲新 - 老樣式類)和Python 3中。我不知道它爲什麼可行,而這不是:

class Extender(object): 
    def extension(self): 
     print("Some work...") 

class Base(object): 
    pass 

Base.__bases__ = (Extender, object) 
# TypeError: __bases__ assignment: 'Extender' deallocator differs from 'object' 
+0

「無法創建一致的」錯誤的原因是因爲您試圖將Base .__ base__從值(object,)更改爲(object,Extender) ,這是根據mro-order錯誤的方法(同樣,你不能說'類X(object,Extender)'類似的錯誤),但是'Base .__ bases__ + =(Extender,)+ Base .__ bases__ ''只會拋出''E'釋放器與'object''不同,這是另一個錯誤,但仍然是錯誤。 – driax 2015-08-19 02:17:50

+0

@driax:是的,謝謝你的解釋。 – unutbu 2015-08-19 12:22:18

+2

For未來的參考,有一個關於釋放器錯誤的開放式CPython問題:https://bugs.python.org/issue672115(從2003年開始,所以不要屏住呼吸) – driax 2015-08-19 13:50:09

相關問題