問題描述
我曾嘗試使用 sip 包裝器類型的 abc.ABCMeta
,它在使用 abc.ABC
進行子類化時效果很好.
I had tried the abc.ABCMeta
with sip wrapper type, and it works well when subclass with 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
我希望它像往常一樣使用通用子類:
I expected it to use generic subclass as usual:
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
但是在沒有繼承Generic[T]
的情況下,data
仍然是Any
.
But the data
is still Any
when without inherit Generic[T]
.
可以用 PEP 560 解決類型檢查嗎?
Can it solved with PEP 560 to do type checking?
推薦答案
嗯,我找到了答案.
由于typing.Generic
的元類是abc.ABC
,它也應該基于abc.ABCMeta
.但這僅適用于 Python 3.7 或更高版本.
Since the metaclass of typing.Generic
is abc.ABC
, it should based on abc.ABCMeta
too. But this is only works with Python 3.7 or above.
然后,只需使用 type(QObject)
而不是 sip.wrappertype
:
And then, just use type(QObject)
instead of 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
.
This code is works for PyCharm IDE, the annotation of variable f
is float
.
把PyQt5
改成PySide2
也可以!
這篇關于如何在沒有元類沖突的情況下將泛型類型與 PyQt 子類一起使用?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!