Typhinweise für eine kombinierte Mix-in-Klasse und Unterklasse führen zu TypeErrorsPython

Python-Programme
Anonymous
 Typhinweise für eine kombinierte Mix-in-Klasse und Unterklasse führen zu TypeErrors

Post by Anonymous »

Der folgende Codeausschnitt verbindet einige Datenklassen und GUI-Klassen mit PySide6 (der Qt-Bibliothek).
Die Klasse HasDataobject ist hier der Schlüssel. Es definiert einen Mix-In für Unterklassen von QGraphicsItem. Es fügt ein Attribut hinzu (

Code: Select all

dataobject
) und Methode (

Code: Select all

update_visibility()
) zu diesen Klassen hinzufügen.

Code: Select all

from typing import TypeVar, Generic, Protocol

from PySide6.QtWidgets import QGraphicsItem, QGraphicsEllipseItem
# QGraphicsEllipseItem is a subclass of QGraphicsItem

### Data objects ###

class VisibleData:
def is_visible(self) -> bool:
return True

class MyNode(VisibleData):
pass

VisibleDataType = TypeVar('VisibleDataType', bound=VisibleData)

### Visual objects (using PySide6) ###

class QGraphicsItemProtocol(Protocol):
"""Define the methods of QGraphicsItem that HasDataobject uses."""
def setVisible(self, visible: bool, /):
...

class HasDataobject(Generic[VisibleDataType]):
"""Mix-in class. Adds an update_visibility() method, and
a dataobject attribute. The dataobject must have a
is_visible() method, as defined in VisibleData.
Any subclass of HasDataobject must also be a subclass of
QGraphicsItem, which defines setVisible()."""
dataobject: VisibleDataType
def update_visibility(self):
self.setVisible(self.dataobject.is_visible())

class Circle(QGraphicsEllipseItem, HasDataobject[MyNode]):
def __init__(self):
super().__init__()
pass
Der obige Code funktioniert ohne Probleme. Pyright oder andere Codevalidatoren werden sich jedoch darüber beschweren, dass setVisible keine bekannte Methode ist (reportAttributeAccessIssue):

Code: Select all

self.setVisible(self.dataobject.is_visible())
Der einfachste Weg, dies zu unterdrücken, ist das Hinzufügen von # type:ignore, aber ich bevorzuge es, explizit zu machen, was in der Dokumentzeichenfolge beschrieben wird: Jede Unterklasse von HasDataobject muss auch eine Unterklasse von QGraphicsItem sein.
Mein erster Gedanke war, HasDataobject zu einem zu machen Unterklasse von QGraphicsItem:

Code: Select all

class HasDataobject(QGraphicsItem, Generic[VisibleDataType])
Das führte jedoch zu dem folgenden RuntimeError in der Circle.__init__-Methode:

RuntimeError: Sie können ein PySide6.QtWidgets.QGraphicsEllipseItem-Objekt in der Klasse Circle nicht zweimal initialisieren!

Also ist mein zweiter Versuch Verwenden Sie das oben definierte QGraphicsItemProtocol:

Code: Select all

class HasDataobject(Generic[VisibleDataType], QGraphicsItemProtocol)
Das ergibt jedoch einen

TypeError: Es kann keine konsistente Methodenauflösungsreihenfolge (MRO) für die Basen Generic, QGraphicsItemProtocol erstellt werden

Als nächstes habe ich versucht, die beiden Basisklassen umzukehren:

Code: Select all

class HasDataobject(QGraphicsItemProtocol, Generic[VisibleDataType])
Das führt jedoch wiederum zu einem Problem bei der Definition der Circle-Klasse:

TypeError: Metaklassenkonflikt: Die Metaklasse einer abgeleiteten Klasse muss eine (nicht strenge) Unterklasse der Metaklassen aller ihrer Basen sein

Ich stecke jetzt etwas fest. Wie kann ich Typhinweise in einem obigen Code verwenden und Pyright (und mich selbst) glücklich machen?
PS: Vorschläge und Best Practices sind willkommen. Ich habe sogar mit dem Gedanken gespielt, HasDataobject zu einer echten Klasse zu machen (has-a QGraphicsItem statt is-a QGraphicsItem) anstelle eines Mix-Ins, aber Unterklassen sind wirklich vorteilhaft, da sie die Leistungsfähigkeit von Qt mit Dingen wie scene.addItem(a_circle) ermöglichen.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post