我曾尝试使用sip包装类型的abc.ABCMeta
,并且在使用abc.ABC
进行子类化时效果很好。
class QABCMeta(wrappertype, ABCMeta):
pass
class WidgetBase(QWidget, metaclass=QABCMeta):
...
class InterfaceWidget(WidgetBase, ABC):
...
class MainWidget(InterfaceWidget):
...
但是它不适用于typing.Generic
。
class QGenericMeta(wrappertype, GenericMeta):
pass
class WidgetBase(QWidget, Generic[T], metaclass=QGenericMeta):
...
class GenericWidget(WidgetBase[float]):
...
它提出了:
line 980, in __new__
self if not origin else origin._gorg)
TypeError: can't apply this __setattr__ to sip.wrappertype object
我希望它像往常一样使用通用子类:
class TableBase(QTableWidget, Generic[T]):
@abstractmethod
def raw_item(self, row: int) -> T:
...
def data(self) -> Iterator[T]:
yield from (self.raw_item(row) for row in range(self.rowCount()))
class MainTable(TableBase[float]):
def raw_item(self, row: int) -> float:
return float(self.item(row, 1).text()) # implementation
table = MainTable()
for data in table.data():
data: float
但是在没有继承data
的情况下,Any
仍然是Generic[T]
。
它可以用PEP 560解决以进行类型检查吗?
答案 0 :(得分:3)
好吧,我找到了答案。
由于typing.Generic
的元类是abc.ABC
,因此它也应该基于abc.ABCMeta
。但这仅适用于Python 3.7或更高版本。
然后,只需使用type(QObject)
而不是sip.wrappertype
:
# -*- coding: utf-8 -*-
from abc import abstractmethod, ABC, ABCMeta
from typing import TypeVar, Generic, Iterator
from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import QTableWidget
QObjectType = type(QObject)
T = TypeVar('T')
class QABCMeta(QObjectType, ABCMeta):
pass
class BaseWidget(QTableWidget, Generic[T], metaclass=QABCMeta):
@abstractmethod
def raw_item(self, row: int) -> T:
...
def data(self) -> Iterator[T]:
yield from (self.raw_item(row) for row in range(self.rowCount()))
class TestWidget(BaseWidget[float], ABC): # optional inherit ABC.
def raw_item(self, row: int) -> float:
return float(self.item(row, 1).text())
if __name__ == '__main__':
w = TestWidget()
for f in w.data():
pass
此代码适用于PyCharm IDE,变量f
的注释为float
。
将PyQt5
更改为PySide2
时,它也有效!