Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 6, 2012 19:02:40

Serbis
От:
Зарегистрирован: 2012-02-13
Сообщения: 38
Репутация: +  0  -
Профиль   Отправить e-mail  

Наследование метоклассом

Вот в чем вопрос, у меня имеется класс вида

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



Отредактировано Serbis (Июнь 6, 2012 19:44:23)

Офлайн

#2 Июнь 6, 2012 20:54:34

fata1ex
От:
Зарегистрирован: 2009-07-11
Сообщения: 732
Репутация: +  52  -
Профиль   Отправить e-mail  

Наследование метоклассом

Вообще, можно обойтись и без метакласса. Код я вам уже приводил.

Если позарез нужен метакласс:

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

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

Почитайте раздел “Конфликтующие метаклассы” здесь.
Есть также вот такой костыль.



Отредактировано fata1ex (Июнь 6, 2012 21:01:14)

Офлайн

#3 Июнь 6, 2012 20:58:37

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Наследование метоклассом

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

Офлайн

#4 Июнь 7, 2012 06:23:32

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Наследование метоклассом

Я дико извиняюсь, но почему нельзя просто создать экземпляр класса на уровне модуля? Вроде же гарантировано, что код уровня модуля выполнится один раз?



Вот здесь один из первых отарков съел лаборанта. Это был такой умный отарк, что понимал даже теорию относительности. Он разговаривал с лаборантом, а потом бросился на него и загрыз…

Офлайн

#5 Июнь 7, 2012 09:10:32

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Наследование метоклассом

PooH
Я дико извиняюсь, но почему нельзя просто создать экземпляр класса на уровне модуля? Вроде же гарантировано, что код уровня модуля выполнится один раз?
В общем случае можно, и это удобно. Но если это наследник QWidget, его нельзя создать до создания экземпляра QApplication.
from PySide import QtGui
 
w = QtGui.QWidget()
print "Ok"
Вывод:
QWidget: Must construct a QApplication before a QPaintDevice

Хотя тут есть вариант: импоритровать модуль с экземпляром после создания QApplication, но он не очень удобен.

Офлайн

#6 Июнь 7, 2012 12:24:40

Serbis
От:
Зарегистрирован: 2012-02-13
Сообщения: 38
Репутация: +  0  -
Профиль   Отправить e-mail  

Наследование метоклассом

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
Аварийный останов



Офлайн

#7 Июнь 7, 2012 13:00:08

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Наследование метоклассом

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

QWidget: Must construct a QApplication before a QPaintDevice
Аварийный останов
Может забыли убрать проверочный код?
# test
assert infoLay() is infoLay()

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version