2017-05-08 134 views
0

我想在運行時覆蓋(修補)一個類。在我的情況下,我使用gui2py,並且要覆蓋它的一些功能來支持MenuItems中的圖像,但不更改最終程序的代碼。Python:覆蓋(猴子修補)類

即我已經

overrides.py

import gui,wx 

# this is the tricky line  
gui.MenuItem.image = gui.component.InitSpec() 

def menu__init__(self, parent, *args, **kwargs): 
    gui.menu.wx_DummyWindow.__init__(self, parent, *args, **kwargs) 
    wx.MenuItem.__init__(self, parentMenu=parent,id=kwargs['id'],text=kwargs['label'],kind=kwargs['style']) 

    if self.GetKind() == wx.ITEM_SEPARATOR: 
     self.parent.AppendSeparator()  
    else: 
     self.SetHelp(kwargs['help']) 
     # The next is added code 
     img = kwargs.get("image") 
     if img: 
      self.SetBitmap(wx.Bitmap(img)) 

     self.parent.AppendItem(self) 

gui.menu.wx_MenuItem.__init__ = menu__init__ 

program.py

from overrides import * 

with gui.Window(name='win', ): 

    with gui.MenuBar(name='menu',): 
     with gui.Menu(label=u'File', name='file',): 
      gui.MenuItem(label=u'Quit', name='quit', image='quit.png') 

gui.main_loop() 

這是行不通的。

但是如果我直接修改GUI/menu.py

class MenuItem(Component): 
    #add this line 
    image = InitSpec() 

然後它

Download This進行工作演示

+0

我想問題是你通過將函數設置爲類屬性來修補'__init__'。在這樣做之前,你應該把它變成一個[實例方法](https://docs.python.org/2/library/types.html#types.MethodType)。 –

+0

不知何故'__init__'按預期工作,它是改變的類屬性_image_。如果它直接在源代碼中修改或覆蓋 – Magen

+0

那麼你的錯誤信息是什麼? –

回答

0

好吧,研究小時後,好像這是將屬性添加到類的正確方法:

class _MenuItem(gui.MenuItem): 
    image = gui.component.InitSpec() 

# and then:   
gui.MenuItem = _MenuItem 

現在它工作正常

+0

'gui.MenuItem.image = ...'沒有錯(除非MenuItem的元類定義了'__setattr__'並以某種方式干擾)。我想你的解決方案在大多數情況下也能起作用,但是一個錯誤信息將有助於弄清爲什麼前一種方法不起作用。請注意,如果'gui.MenuItem'有一個屬性'image',它仍然具有相同的屬性。在'__mro__'中,這只是新的'image',它首先解決了'_MenuItem'的實例。還要注意,如果對象在修補程序之前存儲了該引用,則類型檢查(類型(_MenuItem())== OriginalMenuItem)將失敗。 –