Was ist die beste (idiomatische) Art und Weise den Typen eines Python-Variable zu überprüfen? [Duplikat]

StackOverflow https://stackoverflow.com/questions/378927

  •  22-08-2019
  •  | 
  •  

Frage

    

Diese Frage bereits eine Antwort hier:

         

Ich muss wissen, ob eine Variable in Python ein String oder ein dict ist. Gibt es etwas falsch mit dem folgenden Code?

if type(x) == type(str()):
    do_something_with_a_string(x)
elif type(x) == type(dict()):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

Aktualisieren . Ich avisser Antwort akzeptiert (obwohl ich meine Meinung ändern, wenn jemand erklärt, warum isinstance über type(x) is bevorzugt wird)

Aber dank nakedfanatic mich daran erinnert, dass es oft sauberer einen dict zu verwenden (als case-Anweisung) als eine if / elif / else Serie.

Lassen Sie mich auf meinem Anwendungsfall erarbeiten. Wenn eine Variable ein String ist, muss ich es in einer Liste setzen. Wenn es ein dict ist, brauche ich eine Liste der eindeutigen Werte. Hier ist, was ich kam mit:

def value_list(x):
    cases = {str: lambda t: [t],
             dict: lambda t: list(set(t.values()))}
    try:
        return cases[type(x)](x)
    except KeyError:
        return None

Wenn isinstance bevorzugt wird, wie würden Sie diese Funktion value_list() schreiben?

War es hilfreich?

Lösung

Was passiert, wenn jemand einen Unicode-String an Ihre Funktion übergibt? Oder eine Klasse von dict abgeleitet? Oder eine Klasse Implementierung einer dict-ähnliche Schnittstelle? Folgender Code umfasst zunächst zwei Fälle. Wenn Sie Python verwenden 2.6 Sie können collections.Mapping stattdessen verwenden möchten von dict gemäß der ABC PEP .

def value_list(x):
    if isinstance(x, dict):
        return list(set(x.values()))
    elif isinstance(x, basestring):
        return [x]
    else:
        return None

Andere Tipps

type(dict()) sagt „eine neue dict machen, und dann herauszufinden, was seine Art ist“. Es ist schneller zu sagen, nur „dict“. Aber wenn Sie möchten, geben Sie einfach überprüfen, einen idiomatischen Weg ist isinstance(x, dict).

Beachten Sie, dass isinstance umfasst auch Unterklassen (dank Dustin ):

class D(dict):
    pass

d = D()
print("type(d) is dict", type(d) is dict)  # -> False
print("isinstance (d, dict)", isinstance(d, dict))  # -> True

eingebaute Typen in Python haben in Namen gebaut:

>>> s = "hallo"
>>> type(s) is str
True
>>> s = {}
>>> type(s) is dict
True

btw beachten Sie die ist Operator. Allerdings Typprüfung (wenn man es so nennen will) wird in der Regel durch Umwickeln einen typspezifischen Tests in einer try-except-Klausel durchgeführt, da es nicht so ist viel die Art der Variablen, die wichtig sind, sondern darum, ob Sie können eine bestimmte tun etwas mit ihm oder nicht.

isinstance ist über Art preferrable weil es wertet auch als wahr, wenn Sie eine Objektinstanz zu vergleichen, mit ihm übergeordnete Klasse ist, was im Grunde bedeutet, dass Sie nicht immer müssen einen speziellen Fall Ihre alten Code für sie mit dict oder str Subklassen verwenden.

Zum Beispiel:

 >>> class a_dict(dict):
 ...     pass
 ... 
 >>> type(a_dict()) == type(dict())
 False
 >>> isinstance(a_dict(), dict)
 True
 >>> 

Natürlich kann es Situationen geben, in denen Sie dieses Verhalten nicht wünschen würden, aber das ist -hopefully- viel weniger verbreitet als Situationen, in denen Sie es wollen.

Ich glaube, ich für die Ente eingeben Ansatz gehen - „wenn es wie eine Ente geht, ist es wie eine Ente quakt, seine eine Ente“. Auf diese Weise brauchen Sie keine Sorgen zu machen, wenn die Zeichenfolge ist eine Unicode oder ascii.

Hier ist, was ich tun werde:

In [53]: s='somestring'

In [54]: u=u'someunicodestring'

In [55]: d={}

In [56]: for each in s,u,d:
    if hasattr(each, 'keys'):
        print list(set(each.values()))
    elif hasattr(each, 'lower'):
        print [each]
    else:
        print "error"
   ....:         
   ....:         
['somestring']
[u'someunicodestring']
[]

Die hier Experten sind willkommen auf dieser Art der Nutzung von Duck-Typing zu kommentieren, ich habe mit ihm gewesen, aber hätte dahinter in letzter Zeit auf das genaue Konzept eingeführt und bin sehr begeistert. So würde Ich mag wissen, ob ein Overkill das ist zu tun.

Ich denke, es könnte bevorzugt werden, um tatsächlich tun

if isinstance(x, str):
    do_something_with_a_string(x)
elif isinstance(x, dict):
    do_somethting_with_a_dict(x)
else:
    raise ValueError

2 Alternative Formen, je nach Code der eine oder andere werden wahrscheinlich besser als als auch. Man ist nicht aussehen, bevor Sie springen

try:
  one, two = tupleOrValue
except TypeError:
  one = tupleOrValue
  two = None

Der andere Ansatz ist von Guido und ist eine Form der Funktion Überlastung, die Ihr Code läßt offenere beendet.

http://www.artima.com/weblogs/viewpost.jsp? thread = 155.514

Das sollte funktionieren - also nein, es ist nichts falsch mit Ihrem Code. Allerdings könnte es auch mit einem dict getan werden:

{type(str()): do_something_with_a_string,
 type(dict()): do_something_with_a_dict}.get(type(x), errorhandler)()

Ein bisschen kürzer und pythonic würden Sie nicht sagen?


Bearbeiten .. Achtsamkeit Avisser Rat, der Code auch, wie das funktioniert, und sieht besser aus:

{str: do_something_with_a_string,
 dict: do_something_with_a_dict}.get(type(x), errorhandler)()

Sie möchten typecheck auszuchecken. http://pypi.python.org/pypi/typecheck

Typ-Überprüfungsmodul für Python

Dieses Paket bietet leistungsstarke Laufzeit Typprüfung Einrichtungen für Python-Funktionen, Methoden und Generatoren. Ohne dass eine individuelle Präprozessor oder eine Änderung der Sprache ermöglicht das typecheck Paket Programmierer und Qualitätssicherung Ingenieure präzise Aussagen über den Eingang und Ausgang von, ihrem Code zu machen.

Ich habe einen anderen Ansatz wurde mit:

from inspect import getmro
if (type([]) in getmro(obj.__class__)):
    # This is a list, or a subclass of...
elif (type{}) in getmro(obj.__class__)):
    # This one is a dict, or ...

kann ich mich nicht erinnern, warum ich das isinstance statt verwendet, obwohl ...

*sigh*

Nein, Typprüfung Argumente in Python ist nicht erforderlich. Es ist nie erforderlich.

Wenn Ihr Code entweder einen String oder ein dict Objekt akzeptiert, Ihr Design ist gebrochen.

Das kommt von der Tatsache, dass, wenn Sie nicht wissen, bereits den Typ eines Objekts in Ihrem eigenen Programm, dann tust du etwas falsch bereits.

Typprüfung schmerzt die Wiederverwendung von Code und reduziert die Leistung. Mit einer Funktion, die führt verschiedene Dinge von der Art des Objekts abhängig vergangen ist Bug-anfällig und hat ein Verhalten schwerer zu verstehen und zu pflegen.

Sie haben folgende saner Optionen:

1) Erstellen Sie eine Funktion, die unique_values dicts in einzigartigen Wertelisten konvertiert:

def unique_values(some_dict):
    return list(set(some_dict.values()))

Machen Sie Ihre Funktion das Argument übernehmen bestanden ist immer eine Liste. Auf diese Weise, wenn Sie eine Zeichenfolge an die Funktion übergeben müssen, die Sie gerade tun:

myfunction([some_string])

Wenn Sie es ein dict passieren, was Sie tun:

myfunction(unique_values(some_dict))

Das ist die beste Wahl, es ist sauber, leicht zu verstehen und zu pflegen. Jemand den Code immediatelly lesen versteht, was geschieht, und Sie haben nicht typecheck zu.

2) Machen Sie zwei Funktionen, eine, die Listen von Zeichenketten und man akzeptiert, dass akzeptiert dicts. Sie können eine der anderen intern Anruf tätigen, in den bequemste Weg (myfunction_dict kann eine Liste von Strings erstellen und rufen myfunction_list).

In jedem Fall Sie typecheck nicht . Es ist völlig unnötig und hat nur Schattenseiten. Refaktorieren Code stattdessen in einer Weise, die Sie brauchen nicht zu typecheck. Sie nur Vorteile erhalten dabei sowohl im kurz- als auch langfristig.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top