Python: cómo reajustar o reemplazar dinámicamente una clase con una clase base diferente

Estoy tratando de crear una clase común que quiero usar dentro de diferentes aplicaciones.

La idea: una clase que se podría utilizar como una clase base para las creaciones de la interfaz de usuario. Esta clase se basará en un widget de las aplicaciones en su sistema gui específico (PySide o PyQt)

Esto me permitiría seguir el mismo flujo de código para generar gui. Me gusta tener las mismas estructuras dentro de mi canalización y hace que sea mucho más fácil trabajar en diferentes aplicaciones con los mismos comandos.

El problema: PyQt y PySide están comstackdos en C ++ y no siguen la estructura de clase de Python

Intenté muchas cosas diferentes para que funcionara, pero cada vez que tengo stock en algún momento y no obtengo el resultado que quiero.

  1. Probar (rebase):

    en este bash utilicé __class__ para volver a clasificar la clase en sí.

     from PyQt4 import QtGui, QtCore class UiMainBase(object): PARENT = QtGui.QMainWindow def __init__(self, uiFile=None, parent=None): if parent: self.PARENT = parent self.__class__ = self.PARENT if __name__ == "__main__": import sys from PySide import QtGui as PySideGui class MyGui(UiMainBase): def __init__(self, uiFile): super(MyGui, self).__init__(uiFile, PySideGui.QMainWindow) Ui = r"C:\pythonTest\ui\test.ui" app = PySideGui.QApplication(sys.argv) win = MyGui(Ui) win.show() sys.exit(app.exec_()) 

Los errores que recibo son razonables y no tienen que ser explicados.

  # 1st Error : Traceback (most recent call last): #[..] File "C:/pythonTest/ui/ui.py", line 18, in __init__ self.__class__ = self.PARENT TypeError: __class__ assignment: only for heap types # 2nd Error (without parsing the parent # argument to __init__ of super in MyGui) : Traceback (most recent call last): #[..] File "C:/pythonTest/ui/uiTest.py", line 18, in __init__ self.__class__ = self.PARENT TypeError: __class__ assignment: 'MyGui' object layout differs from 'QMainWindow' 
  1. Probar (rebase):

    en este bash utilicé __bases__ para volver a clasificar la clase en sí.

     from PyQt4 import QtGui, QtCore class UiMainBase(object): PARENT = QtGui.QMainWindow def __init__(self, uiFile=None, parent=None): if parent: self.PARENT = parent self.__bases__= (self.PARENT,) if __name__ == "__main__": import sys from PySide import QtGui as PySideGui class MyGui(UiMainBase): def __init__(self, uiFile): super(MyGui, self).__init__(uiFile, PySideGui.QMainWindow) Ui = r"C:\pythonTest\ui\test.ui" app = PySideGui.QApplication(sys.argv) win = MyGui(Ui) print win.__bases__ # <- shows what base the object has win.show() sys.exit(app.exec_()) 

En este resultado, podemos ver que el objeto ahora tiene la base correcta, pero no los métodos y las variables (ni siquiera si llamo super después de configurar __bases__ ).

   # <- the base Traceback (most recent call last): File "C:/pythonTest/ui/uiTest.py", line 34, in  win.show() AttributeError: 'MyGui' object has no attribute 'show' 
  1. Probar (decorador):

    en lugar de volver a generar un objeto, intenté reemplazar la clase con otro que tiene la base correcta

     from PyQt4 import QtGui, QtCore def GetUiObject(uiClass): parentWidget = uiClass.PARENT # <- Gets the original value, # not the latest, why? class ParentUI(parentWidget, uiClass): def __init__(self, *args, **kwargs): super(ParentUI, self).__init__() uiClass.__init__(self, *args, **kwargs) #[..] def __call__(self, cls): for func in uiClass.__dict__: setattr(cls, func, uiClass.__dict__[func]) #ParentUI = type("ParentUI", (parentWidget,),ParentUI.__dict__.copy()) return ParentUI @GetUiObject class UiMainBase( object ): PARENT = QtGui.QMainWindow def __init__(self, uiFile=None, *args, **kwargs): """constructor..""" #[..] if __name__ == "__main__": import sys from PySide import QtGui as PySideGui UiMainBase.PARENT = PySideGui.QMainWindow # <- specify the application # ui architecture as parent class MyGui(UiMainBase): def __init__(self, uiFile=None): # This variant of base class definition doesn't allow parsing # the parent argument with with it # (__init__ will be executed after base is set) super(MyGui, self).__init__(uiFile=None) print self.menuBar () # <- check used ui architecture 

El resultado de esta variante no produce errores y se imprime: , pero MyGui no se basa en PySideGui.QMainWindow como esperaba

EDITAR:

¿Por qué no definir clases con una base de PySide y una con una base de PyQt4 ?

Porque quiero dejarlo abierto para un uso genral y posteriores ampliaciones. Debe ser libre de configurar un widget principal, que está definido por la aplicación ( PySide o PyQt ). Pero cada aplicación tiene su propio método o función para obtener su MainWindow. Por lo tanto, si desea extender algunos widgets de esta MainWindow, o simplemente agregar una nueva interfaz de usuario, debe definirla como principal o directamente desde ella. Algunas aplicaciones y sus API no admiten una interfaz de PySide.QtGui.QMainWindow generada de forma gratuita desde el tipo PySide.QtGui.QMainWindow o PyQt4.QtGui.QMainWindow . Esa es la razón principal por la que estaba tratando de hacerlo de esta manera. Por supuesto, podría crear una clase UiMainWindow para cada aplicación y UiMainWindow en su ventana principal (esto es lo que hago por ahora), pero estaba tratando de hacerla más genérica y global para mi API de canalización.

Ejemplo de uso:

Este ejemplo es para 3DS-Max y dentro de un módulo de su integración de canalización.

 from pythonLibrary.file import Path from qtLibrary.ui import UiMainBase from blurdev.gui import Window UiMainBase.PARENT = Window class UiWidget( UiMainBase ): """ This class creates a widget which is parented to the PySide implementation of blur's Python in 3DS-Max """ def __init__(self, uiFile=None): super(UiWidget, self).__init__() if uiFile: self.loadUi(uiFile, self) self.show() #[..] class PublishUi(UiWidget): def __init__(self): uiFile = Path.Combine(__file__,self.__class__.__name__+".ui") super(PublishUi, self).__init__(uiFile) #[..] if __name__ == "__main__": # This should be called from a menu entry inside 3DS-Max publishWindow = PublishUi() 

¿Alguien tiene una solución para esta situación?

Saludos, Michael

Haga una función de fábrica que genere dinámicamente la clase base correcta. En la vida real, probablemente memorizaría la fábrica para que siempre devuelva el mismo objeto de clase para un padre determinado, en lugar de crear múltiples clases idénticas.

 from PyQt4 import QtGui, QtCore def BaseFactory(parent): class UiMainBase(parent): .... return UiMainBase if __name__ == "__main__": import sys from PySide import QtGui as PySideGui # UiMainBase = BaseFactory(QtGui.QMainWindow) UiMainBase = BaseFactory(PySideGui.QMainWindow) class MyGui(UiMainBase): ... Ui = r"C:\pythonTest\ui\test.ui" app = PySideGui.QApplication(sys.argv) win = MyGui(Ui)