Python prüfen, ob eine Instanz eine Liste enthält?

87

Wie mache ich pythonisch:

var = 7.0
var_is_good = isinstance(var, classinfo1) or isinstance(var, classinfo2) or isinstance(var, classinfo3) or ... or  isinstance(var, classinfoN)

Es scheint albern, dass ich nicht einfach eine Liste von Klasseninfos einreichen kann:

var_is_good = isinstanceofany( var, [classinfo1, classinfo2, ... , classinfoN] )

Was ist also die isinstanceofanyFunktion?

D Adams
quelle
Wenn es wie eine Zahl addiert, wie eine Zahl subtrahiert, wie eine Zahl multipliziert ... warum müssen Sie wissen, ob es eine Zahl ist? Siehe Duck Typing für weitere Details.
Makoto
Mein spezieller Anwendungsfall ist eine Funktion, die a zurückgibt (Funktion, die zurückgibt (entweder ein numberODER, das einen Sympy-Ausdruck zurückgibt)). Ich möchte überprüfen, ob die von mir generierte Funktion das tut, was sie tun soll, wenn ich sie an andere Funktionen weitergebe.
D Adams
Warum gibt Ihre Funktion nichts Homogenes zurück? Das ist, was der Geruch hier ist; Sie können schnell und locker mit dem Tippen von Enten werden, aber Sie sollten konsequent sein, was Sie zurückgeben.
Makoto
Ich denke, ich könnte immer einen Sympy-Ausdruck zurückgeben, der manchmal eine Zahl ergibt und manchmal Variablen enthält.
D Adams
Das ist es, was ich denke, dass Sie hier tun wollen; Anstatt mehrere verschiedene Typen zurückzugeben, geben Sie den einen Typ zurück und reduzieren Sie ihn gegebenenfalls auf eine Zahl.
Makoto

Antworten:

191

isinstance()nimmt ein Tupel von Klassen für das zweite Argument. Es wird return true , wenn das erste Argument eine Instanz ist jede der Arten in dieser Reihenfolge:

isinstance(var, (classinfo1, classinfo2, classinfo3))

Mit anderen Worten, bietet diese Funktionalität isinstance() bereits sofort an.

Aus der isinstance()Dokumentation :

Wenn classinfo weder ein Klassenobjekt noch ein Typobjekt ist, kann es sich um ein Tupel von Klassen- oder Typobjekten handeln oder rekursiv andere solche Tupel enthalten (andere Sequenztypen werden nicht akzeptiert).

Hervorhebung von mir; beachte die rekursive Natur; (classinfo1, (classinfo2, classinfo3))ist auch eine gültige Option.

Martijn Pieters
quelle
Hilfreich, danke!
Yaakov Bressler
11

Sie waren dem Titel Ihrer Frage schon ziemlich nahe. Sie könnten anyund eine Liste verwenden:

var = 7.0
var_is_good = any([isinstance(var, classinfo1),
                   isinstance(var, classinfo2),
                   isinstance(var, classinfo3), ...
                   isinstance(var, classinfoN)])

Aber ein Blick in die Dokumente von isinstanceenthüllt:

Geben Sie true zurück, wenn das Objektargument eine Instanz des classinfo-Arguments oder einer (direkten, indirekten oder virtuellen) Unterklasse davon ist. Wenn object kein Objekt des angegebenen Typs ist, gibt die Funktion immer false zurück. Wenn classinfo keine Klasse ist (Typobjekt), kann es sich um ein Tupel von oder rekursiv andere solche Tupel enthalten (andere Sequenztypen werden nicht akzeptiert). Wenn classinfo kein Typ oder Tupel von Typen und solchen Tupeln ist, wird eine TypeError-Ausnahme ausgelöst.

Dies bedeutet, dass dies der bessere Weg ist

var = 7.0
var_is_good = isinstance(var, (classinfo1,
                               classinfo2,
                               classinfo3,
                               ...,
                               classinfoN))
Martin Thoma
quelle
2
Die Wiederholung isinstancenur mit dem classinfoWechsel scheint nicht sehr Pythonic mir.
Makoto
1
Versuchen Sie es var.__class__. Ist es das was du willst? @ Makoto: Ich stimme zu. Überhaupt nicht pythonisch!
Flamenco
@ Makoto Yup. Aber das hätte D Adams wahrscheinlich leicht finden können, wenn er in den Dokumenten nach "any" gesucht hätte. Ich habe meine Antwort auf die bessere Version erweitert ... aber Martijn Pieters war offensichtlich schneller ... noch einmal.
Martin Thoma
3
any()mit einer Liste ist .. sinnlos. Verwenden Sie einen Generatorausdruck, wenn Sie ihn verwenden müssen any(). Dann profitieren Sie zumindest vom frühen Beenden.
Martijn Pieters
Ich denke, das isinstancemit Tupel ist der richtige Weg. Ich wollte nur die Lösung erwähnen, anyda es das zu sein schien, wonach er im Titel fragt.
Martin Thoma
4

Dies wird Ihr Problem lösen:

valid_instance_types = <tuple of types you want to allow>
var_is_good = isinstance(var, valid_instance_types)

Basierend auf der Dokumentation gibt es viele Möglichkeiten, Werte von Typen an zu übergebenisinstance .

Sie könnten sich auch mit Sinnlichkeit befassen, wenn Sie versuchen, eine kompliziertere Validierung durchzuführen, von der dies nur ein Teil ist.

Nathaniel Ford
quelle
isinstance () bietet diese Funktionalität bereits an. Übergeben Sie als zweites Argument ein Tupel mit allen erforderlichen Typen
RFV
@ RFV5s Ja .... das zeigt das Beispiel, das ich hier bereitgestellt habe. Was ist Ihr Einwand?
Nathaniel Ford
1

Sie sollten im Allgemeinen nicht verwenden isinstance, aber was Sie tun möchten, können Sie mit der integrierten Funktion any () erreichen.

var_is_good = any(isinstance(var, t) for t in [type1, type2, type3])
Chad S.
quelle
7
Das ist übertrieben; isinstance()bietet die Funktionalität sofort ohne Verwendung any().
Martijn Pieters
@MartijnPieters Ich wusste nicht, dass isinstance mehrere Typen annehmen kann, aber ich denke, die Antwort ist immer noch gut, da die Frage allgemeiner lauten kann: "Wie überprüfe ich, ob einer der Rückgabewerte einer bestimmten Funktion vorliegt?" mit verschiedenen Parametern ist wahr "
Chad S.
Ob Sie verwenden sollten oder nicht, isinstance()ist irrelevant.
RFV
@ChadS. Ich möchte Sie fragen, warum er Ihrer Meinung nach nicht verwenden sollte isinstance(). Vielen Dank.
Idature
Weil Python die Typprüfung meidet. Es ist viel zusätzlicher Code (und CPU-Zyklen) für wenig Nutzen. Das Tippen von Enten wird bevorzugt.
Chad S.