2017-01-01 4 views
2

Was ist der richtige Weg, um ein Funktionsargument mit Anmerkungen zu versehen, das ein Klassenobjekt anstelle einer Instanz dieser Klasse erwartet?Wie man Typinstanzen (anstelle von Klasseninstanzen) kommentiert?

Im Beispiel unten wird some_class Argument erwartet, dass eine Typ-Instanz sein (weicht ist eine Klasse), aber das Problem hier ist, dass type zu weit gefasst ist:

def construct(some_class: type, related_data:Dict[str, Any]) -> Any: 
    ... 

In dem Fall, wo some_class ein erwartet spezifische Menge von Typen Objekte, mit type hilft überhaupt nicht. Das typing Modul könnte in der Notwendigkeit einer Klasse generisch sein, das dies tut:

def construct(some_class: Class[Union[Foo, Bar, Baz]], related_data:Dict[str, Any]) -> Union[Foo, Bar, Baz]: 
    ... 

In dem obigen Beispiel some_class ist die Foo, Bar oder Faz Klasse, keine Instanz davon. Es sollte ihre Positionen im Klassenbaum nicht interessieren, weil some_class: Class[Foo] auch ein gültiger Fall sein sollte. Daher

# classes are callable, so it is OK 
inst = some_class(**related_data) 

oder

# instances does not have __name__ 
clsname = some_class.__name__ 

oder

# an operation that only Foo, Bar and Baz can perform. 
some_class.a_common_classmethod() 

sollten OK sein, um mypy, pytype, PyCharm usw.

Wie kann dies mit aktuellen Implementierung erfolgen (Python 3.6 oder früher)?

+0

Wenn Sie spezifischer als "Typ" sein müssen, führen Sie entweder eine Metaklasse oder eine abstrakte Basisklasse ein. – jonrsharpe

+0

@jonrsharpe - Eine Metaklasse würde den Trick machen, glaube ich, aber ich habe dieses Level in Python noch nicht erreicht. Mit der Einführung von Variablenanmerkungen in 3.6 (einschließlich einer 'ClassVar' zur Unterscheidung von Instanzvariablen von Klassenvariablen) frage ich mich, warum ich' type' verwenden sollte, um Klassenobjekte zu kommentieren, wenn es so viele Möglichkeiten gibt, Klasseninstanzen zu kommentieren. Vielleicht muss ich auf ein zukünftiges Update oder ein Rezept warten :). –

+0

Es scheint, dass ich mich auf 'typing.Type' verlassen muss und etwas wie' Foo = TypeVar ['Foo', bond = Bar] 'machen muss, wobei' Bar' ein ABC ist, dann nehmen wir das obige Beispiel: ' def konstruieren (some_class: Typ [Foo], ...) -> Foo'. Ich mag es besonders nicht, 'TypeVar' zu benutzen, aber es scheint der einzige Weg zu sein ... –

Antwort

2

Um ein Objekt, das eine Klasse darstellt, mit Anmerkungen zu versehen, verwenden Sie typing.Type. Zum Beispiel würde dies die Art Prüfer sagen, dass some_class ist Klasse Foo oder eine ihrer Unterklassen:

from typing import Type 
class Foo: ... 
class Bar(Foo): ... 
class Baz: ... 
some_class: Type[Foo] 
some_class = Foo # ok 
some_class = Bar # ok 
some_class = Baz # error 
some_class = Foo() # error 

Beachten Sie, dass Type[Union[Foo, Bar, Baz]] und Union[Type[Foo], Type[Bar], Type[Baz]] völlig gleichwertig sind.

Wenn some_class eine beliebige Anzahl von Klassen sein könnte, möchten Sie sie möglicherweise alle von der gleichen Basisklasse erben lassen und Type[BaseClass] verwenden. Beachten Sie, dass die Vererbung vorerst nicht virtuell sein muss (mypy-Unterstützung für die virtuelle Vererbung ist being discussed).

Bearbeitet, um zu bestätigen, dass Type[Union[... zulässig ist.

Verwandte Themen