Übersicht
Für das spezifische Käsebeispiel stimme ich mit vielen der anderen Antworten über die Verwendung von Standardwerten überein, um eine zufällige Initialisierung zu signalisieren oder eine statische Fabrikmethode zu verwenden. Es kann jedoch auch verwandte Szenarien geben, die Sie im Sinn hatten, wo es est Wert in alternativen, prägnanten Möglichkeiten, den Konstruktor aufzurufen, ohne die Qualität der Parameternamen oder Typinformationen zu beeinträchtigen.
Seit Python 3.8 und functools.singledispatchmethod
kann in vielen Fällen helfen, dies zu erreichen (und die flexiblere multimethod
kann in noch mehr Szenarien gelten). ( Dieser verwandte Beitrag beschreibt, wie man dasselbe in Python 3.4 ohne eine Bibliothek erreichen kann). Ich habe in der Dokumentation für beide keine Beispiele gesehen, die speziell das Überladen von __init__
wie Sie fragen, aber es scheint, dass die gleichen Grundsätze für das Überladen jeder Member-Methode gelten (wie unten gezeigt).
"Single Dispatch" (verfügbar in der Standardbibliothek) erfordert, dass es mindestens einen Positionsparameter gibt und dass der Typ des ersten Arguments ausreicht, um zwischen den möglichen überladenen Optionen zu unterscheiden. Für das spezifische Käse-Beispiel trifft dies nicht zu, da Sie zufällige Löcher haben wollten, wenn keine Parameter angegeben wurden, aber multidispatch
unterstützt dieselbe Syntax und kann verwendet werden, solange jede Methodenversion anhand der Anzahl und des Typs aller Argumente zusammen unterschieden werden kann.
Beispiel
Im Folgenden finden Sie ein Beispiel für die Anwendung beider Methoden (einige Details sind aus Gründen der Übersichtlichkeit angegeben) mypy was mein Ziel war, als ich das Projekt ins Leben rief):
from functools import singledispatchmethod as overload
# or the following more flexible method after `pip install multimethod`
# from multimethod import multidispatch as overload
class MyClass:
@overload # type: ignore[misc]
def __init__(self, a: int = 0, b: str = 'default'):
self.a = a
self.b = b
@__init__.register
def _from_str(self, b: str, a: int = 0):
self.__init__(a, b) # type: ignore[misc]
def __repr__(self) -> str:
return f"({self.a}, {self.b})"
print([
MyClass(1, "test"),
MyClass("test", 1),
MyClass("test"),
MyClass(1, b="test"),
MyClass("test", a=1),
MyClass("test"),
MyClass(1),
# MyClass(), # `multidispatch` version handles these 3, too.
# MyClass(a=1, b="test"),
# MyClass(b="test", a=1),
])
Ausgabe:
[(1, test), (1, test), (0, test), (1, test), (1, test), (0, test), (1, default)]
Anmerkungen:
- Ich würde den Alias normalerweise nicht als
overload
aber es hat dazu beigetragen, dass der Unterschied zwischen den beiden Methoden nur noch eine Frage des verwendeten Imports ist.
- Le site
# type: ignore[misc]
Kommentare sind für die Ausführung nicht erforderlich, aber ich füge sie ein, um die mypy
die nicht gerne dekoriert __init__
noch anrufen __init__
direkt.
- Wenn Sie mit der Dekorator-Syntax nicht vertraut sind, sollten Sie wissen, dass die
@overload
vor der Definition von __init__
ist nur Zucker für __init__ = overload(the original definition of __init__)
. In diesem Fall, overload
ist eine Klasse, so dass die resultierende __init__
ist ein Objekt, das eine __call__
Methode, so dass sie wie eine Funktion aussieht, die aber auch eine .register
Methode, die später aufgerufen wird, um eine weitere überladene Version von __init__
. Das ist ein bisschen unübersichtlich, aber es gefällt mypy, weil keine Methodennamen doppelt definiert werden. Wenn Sie sich nicht um mypy kümmern und sowieso vorhaben, die externe Bibliothek zu verwenden, multimethod
hat auch einfachere alternative Möglichkeiten, überladene Versionen anzugeben.
- Definition von
__repr__
ist nur dazu da, die Druckausgabe sinnvoll zu gestalten (man braucht sie im Allgemeinen nicht).
- Beachten Sie, dass
multidispatch
ist in der Lage, drei zusätzliche Eingabekombinationen zu verarbeiten, die keine Positionsparameter haben.
11 Stimmen
Ich denke init ist kein Konstruktor, sondern ein Initialisierer. neu wäre ein Konstrukteur
0 Stimmen
Verwandt (kein Duplikat): Wie kann ich doppelte Methodennamen in einer Python-Klasse erkennen?