python subclasscheck & subclasshook

8

Die Methoden __subclasscheck__ und __subclasshook__ werden verwendet, um zu bestimmen, ob eine Klasse als Unterklasse eines anderen betrachtet wird. Ihre Dokumentation ist jedoch selbst in fortgeschrittenen Python-Büchern sehr begrenzt. Wie sollen sie verwendet werden und was ist ihr Unterschied (höhere Priorität, Seite der Beziehung, auf die sie sich beziehen usw.)?

    
blue_note 23.11.2016, 12:17
quelle

2 Antworten

2

Beide Methoden können verwendet werden, um das Ergebnis der integrierten Funktion issubclass() anzupassen.

__subclasscheck__

  

class.__subclasscheck__(self, subclass)

     

Gibt true zurück, wenn die Unterklasse als (direkte oder indirekte) Unterklasse der Klasse betrachtet werden soll. Wenn definiert, wird issubclass(subclass, class) implementiert.

     

Beachten Sie, dass diese Methoden nach dem Typ (Metaklasse) einer Klasse gesucht werden. Sie können nicht als Klassenmethoden in der aktuellen Klasse definiert werden. Dies entspricht der Suche nach speziellen Methoden, die für Instanzen aufgerufen werden. Nur in diesem Fall ist die Instanz selbst eine Klasse.

Diese Methode ist die spezielle Methode, die für die Anpassung des issubclass Checks verantwortlich ist. Wie die "Anmerkung" besagt, dass es auf der Metaklasse implementiert werden muss!

%Vor%

Diese Implementierung gibt False zurück, auch wenn Sie echte Unterklassen haben:

%Vor%

Es gibt tatsächlich interessantere Verwendungen für __subclasscheck__ Implementierungen. Zum Beispiel:

%Vor%

Bei dieser Implementierung gibt jede Klasse, die __len__ und __iter__ definiert, True in einem issubclass check zurück:

%Vor%

In diesen Beispielen habe ich die Oberklassen __subclasscheck__ nicht aufgerufen und dadurch das normale Verhalten issubclass deaktiviert (was durch type.__subclasscheck__ implementiert wird). Aber es ist wichtig zu wissen, dass Sie auch nur das erweitern normale Verhalten ändern können, anstatt es vollständig zu überschreiben:

%Vor%

__subclasshook__

  

__subclasshook__(subclass)

     

(Muss als Klassenmethode definiert sein.)

     

Überprüfen Sie, ob die Unterklasse als Unterklasse dieses ABCs betrachtet wird. Dies bedeutet, dass Sie das Verhalten von issubclass weiter anpassen können, ohne dass Sie register() für jede Klasse aufrufen müssen, die Sie als Unterklasse von ABC betrachten möchten. (Diese Klassenmethode wird von der Methode __subclasscheck__() des ABC aufgerufen.)

     

Diese Methode sollte True , False oder NotImplemented zurückgeben. Wenn sie True zurückgibt, wird die Unterklasse als eine Unterklasse dieses ABC betrachtet. Wenn sie False zurückgibt, wird die Unterklasse nicht als Unterklasse dieses ABC betrachtet, selbst wenn sie normalerweise eins wäre. Wenn es NotImplemented zurückgibt, wird die Unterklassenprüfung mit dem üblichen Mechanismus fortgesetzt.

Das wichtigste hier ist, dass es in der Klasse als classmethod definiert ist und von abc.ABC.__subclasscheck__ aufgerufen wird. Sie können es also nur verwenden, wenn Sie mit Klassen arbeiten, die eine ABCMeta metaclass haben:

%Vor%

Dies wird nur in die __subclasshook__ der ersten gehen:

%Vor%

Beachten Sie, dass nachfolgende Aufrufe von issubclass nicht mehr in __subclasshook__ übernommen werden, weil ABCMeta das Ergebnis zwischenspeichert:

%Vor%

Beachten Sie, dass Sie in der Regel überprüfen, ob das erste Argument die Klasse selbst ist. Das soll verhindern, dass Unterklassen das __subclasshook__ erben, anstatt die normale Unterklassenbestimmung zu verwenden.

Zum Beispiel (aus dem Modul CPython collections.abc ):

%Vor%

Wenn Sie also überprüfen, ob etwas eine Unterklasse von Hashable ist, wird die benutzerdefinierte __subclasshook__ -Implementierung verwendet, die von if cls is Hashable geschützt wird. Wenn Sie jedoch eine tatsächliche Klasse haben, die die Hashable -Schnittstelle implementiert, wollen Sie nicht, dass sie den __subclasshook__ -Mechanismus erbt, sondern den normalen Unterklassenmechanismus.

Zum Beispiel:

%Vor%

Auch wenn int implementiert __hash__ und __subclasshook__ prüft auf eine __hash__ Implementierung ist das Ergebnis in diesem Fall False . Es gibt immer noch __subclasshook__ von Hashable ein, aber es gibt sofort NotImplemented zurück, das an ABCMeta signalisiert, dass es mit der normalen Implementierung fortfahren soll. Wenn es nicht if cls is Hashable hätte, würde issubclass(int, MyHashable) True zurückgeben!

Wann sollten Sie __subclasscheck__ und wann __subclasshook__ verwenden?

Es kommt wirklich darauf an. __subclasshook__ kann für die Klasse anstelle der Metaklasse implementiert werden, erfordert aber, dass Sie ABCMeta (oder eine Unterklasse von ABCMeta ) als Metaklasse verwenden, da die Methode __subclasshook__ eigentlich nur eine Konvention ist, die von Pythons abc eingeführt wurde. Modul.

Sie können immer __subclasscheck__ verwenden, aber es muss in der Metaklasse implementiert werden.

In der Praxis verwenden Sie __subclasshook__ , wenn Sie Schnittstellen implementieren (weil diese normalerweise abc verwenden) und den Unterklassenmechanismus anpassen möchten. Und du benutzt __subclasscheck__ , wenn du deine eigenen Konventionen erfinden willst (wie abc ). In 99,99% der normalen (nicht spaßigen) Fälle benötigen Sie nur __subclasshook__ .

    
MSeifert 21.01.2018, 20:56
quelle
5

__subclasshook__ und __subclasscheck__ wird verwendet, um das Verhalten von issubclass function anzupassen. Viele weitere Informationen finden Sie im abc-Quellcode .

__subclasscheck__ wird nach dem Typ (Metaklasse) einer Klasse gesucht. Es sollte nicht für eine normale Klasse definiert werden.

__subclasshook__ prüft, ob die Unterklasse als Unterklasse eines ABC betrachtet wird. Dies bedeutet, dass Sie das Verhalten von issubclass weiter anpassen können, ohne register () für jede Klasse aufrufen zu müssen, die Sie als Unterklasse von ABC betrachten möchten.

Dies bedeutet, dass Sie __subclasshook__ in Ihrer ABC-Klasse mit einer Bedingung definieren können und alle Klassen, die diese Bedingung erfüllen, werden als Unterklasse betrachtet.

Zum Beispiel:

%Vor%     
Gennady Kandaurov 23.11.2016 14:17
quelle

Tags und Links