Найти - Пользователи
Полная версия: Наследование метоклассом
Начало » Python для новичков » Наследование метоклассом
1
Serbis
Вот в чем вопрос, у меня имеется класс вида
class infoLay(QtGui.QWidget):
  def __init__(self, parent=None):
    QtGui.QWidget.__init__(self, None)
    
    self.ean_edit = QtGui.QLineEdit()
    self.ean_edit.setDisabled(1)
    self.ean_edit.setMinimumWidth(70)
    self.ean_edit.setMaximumWidth(100)
#Бла Бла бла еще много строчек кода
Он прекрасно работает и делает сваю qt хрень. Но так уж получилось что мне нужно теперь его сделать метаклассом, и вот тут я полный профан:
class infoLayMeta(type):
  def __init__(cls, name, bases, dict):
    super(infoLayMeta, cls).__init__(name, bases, dict)
    cls.instance = None
    
  def __call__(self,*args,**kw):
        if self.instance is None:
            self.instance = super(SingletonMeta, self).__call__(*args, **kw)
        return self.instance
class infoLay(object):
  __metaclass__ = infoLayMeta
def __init__(self):
  self.ean_edit = QtGui.QLineEdit()
  self.ean_edit.setDisabled(1)
  self.ean_edit.setMinimumWidth(70)
  self.ean_edit.setMaximumWidth(100)
 #Бла бла бла
Суть перевода в метакласс - создание синглтона. Но вот вопрос - как мне наследовать QtGui.QWidget если попытка его наследования классом infoLay приводит к

TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
fata1ex
Вообще, можно обойтись и без метакласса. Код я вам уже приводил.

Если позарез нужен метакласс:
>>> class Singleton(type):
...     def __init__(cls, name, bases, dict):
...         super(Singleton, cls).__init__(name, bases, dict)
...         cls.instance = None 
...         
...     def __call__(cls, *args, **kwargs):
...         if cls.instance is None:
...             cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
...         return cls.instance
...         
>>> class A(object):
...     __metaclass__ = Singleton
...     
>>> class B(object):
...     pass
...     
>>> foo, bar = B(), B()
>>> foo == bar
False
>>> foo, bar = A(), A()
>>> foo == bar
True
>>> id(foo), id(bar)
(174132204, 174132204)

Хм, походу у вас написано тоже самое :)

Почитайте раздел “Конфликтующие метаклассы” здесь.
Есть также вот такой костыль.
reclosedev
Serbis
Суть перевода в метакласс - создание синглтона.
Целесообразно ли? Может проще в модуле сделать функцию, которая будет возвращать инстанс, создавая его если еще не создан?

Причина в том, что классы из PySide/PyQt содержат свой метакласс.
Когда я пытался унаследоваться от QtGui.QListWidget и collections.MutableSequence, помогло вот это:
http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/
import noconflict
 
class ListWidget(QtGui.QListWidget, collections.MutableSequence):
    __metaclass__ = noconflict.classmaker()
    ...

Синглтон,с использованием noconflict будет выглядеть примерно так (если очень сильно нужен):
class InfoLayMetaHelper(object):
    __metaclass__ = infoLayMeta
 
class infoLay(QtGui.QWidget, InfoLayMetaHelper):
    __metaclass__ = noconflict.classmaker()
 
    def __init__(self):
        self.ean_edit = QtGui.QLineEdit()
        self.ean_edit.setDisabled(1)
        self.ean_edit.setMinimumWidth(70)
        self.ean_edit.setMaximumWidth(100)
# test
assert  infoLay() is infoLay()
PooH
Я дико извиняюсь, но почему нельзя просто создать экземпляр класса на уровне модуля? Вроде же гарантировано, что код уровня модуля выполнится один раз?
reclosedev
PooH
Я дико извиняюсь, но почему нельзя просто создать экземпляр класса на уровне модуля? Вроде же гарантировано, что код уровня модуля выполнится один раз?
В общем случае можно, и это удобно. Но если это наследник QWidget, его нельзя создать до создания экземпляра QApplication.
from PySide import QtGui
 
w = QtGui.QWidget()
print "Ok"
Вывод:
QWidget: Must construct a QApplication before a QPaintDevice

Хотя тут есть вариант: импоритровать модуль с экземпляром после создания QApplication, но он не очень удобен.
Serbis
reclosedev
Serbis
Суть перевода в метакласс - создание синглтона.
Целесообразно ли? Может проще в модуле сделать функцию, которая будет возвращать инстанс, создавая его если еще не создан?

Причина в том, что классы из PySide/PyQt содержат свой метакласс.
Когда я пытался унаследоваться от QtGui.QListWidget и collections.MutableSequence, помогло вот это:
http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/
import noconflict
 
class ListWidget(QtGui.QListWidget, collections.MutableSequence):
    __metaclass__ = noconflict.classmaker()
    ...

Синглтон,с использованием noconflict будет выглядеть примерно так (если очень сильно нужен):
class InfoLayMetaHelper(object):
    __metaclass__ = infoLayMeta
 
class infoLay(QtGui.QWidget, InfoLayMetaHelper):
    __metaclass__ = noconflict.classmaker()
 
    def __init__(self):
        self.ean_edit = QtGui.QLineEdit()
        self.ean_edit.setDisabled(1)
        self.ean_edit.setMinimumWidth(70)
        self.ean_edit.setMaximumWidth(100)
# test
assert  infoLay() is infoLay()

Спасибо, конфликта метаклассов больше не возникает, но есть одно но - конструктор класса infoLay отрабатывается сразу после запуска цикла программы, в результате:

QWidget: Must construct a QApplication before a QPaintDevice
Аварийный останов
reclosedev
Serbis
но есть одно но - конструктор класса infoLay отрабатывается сразу после запуска цикла программы, в результате:

QWidget: Must construct a QApplication before a QPaintDevice
Аварийный останов
Может забыли убрать проверочный код?
# test
assert infoLay() is infoLay()
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB