2017-05-08 3 views
0

Ich möchte eine Klasse zur Laufzeit überschreiben (patchen). In meinem Fall benutze ich gui2py und möchte einige seiner Funktionen außer Kraft setzen, um Image in MenuItems zu unterstützen, ohne den Code des endgültigen Programms zu ändern.Python: Überschreiben (Affepatching) Klasse

das heißt ich habe

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() 

Das wird nicht funktionieren.

Allerdings, wenn ich ändern direkt gui/menu.py

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

Dann funktioniert es

Download This für eine Arbeits Demo

+0

Ich schätze das Problem ist, Sie patching '__init__' nur durch die Funktion als ein Klassenattribut festlegen. Sie sollten es zuvor in eine [Instanzmethode] (https://docs.python.org/2/library/types.html#types.MethodType) umwandeln. –

+0

Irgendwie funktioniert das "__init__" wie erwartet, es ist die Klasseneigenschaft _image_, die die Änderung vornimmt. Wenn es in der Quelle direkt geändert oder überschrieben wird – Magen

+0

Was ist Ihre Fehlermeldung dann? –

Antwort

0

Ok, nach Stunden der Forschung scheint es, wie dies Die korrekte Methode, um einer Klasse ein Attribut hinzuzufügen:

Jetzt funktioniert es gut

+0

Es ist nichts falsch mit 'gui.MenuItem.image = ...' (es sei denn, 'MenuItem's Meta-Klasse definiert '__setattr__' und stört irgendwie). Ich denke, Ihre Lösung funktioniert in den meisten Fällen auch, aber eine Fehlermeldung wäre hilfreich, um herauszufinden, warum der vorherige Ansatz nicht funktioniert hat. Beachten Sie, dass, wenn 'gui.MenuItem' ein Attribut' image' hat, es immer noch dasselbe Attribut hat. Im '__mro__' ist es nur das neue' image', das zuerst für Instanzen von '_MenuItem' auflöst. Beachten Sie außerdem, dass alle Typüberprüfungen wie "type (_MenuItem()) == OriginalMenuItem" fehlschlagen, wenn ein Objekt diese Referenz vor dem Patch gespeichert hat. –

Verwandte Themen