Soll ich die Arten von Konstruktorargumente überprüfen (und an anderen Orten zu)?

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

  •  03-07-2019
  •  | 
  •  

Frage

Python schreckt die Typen zu überprüfen. Aber in vielen Fällen kann dies nützlich sein:

  1. Überprüfen Konstruktorargumente. z.B. Feind Boolean Überprüfung, Bindfaden, dict usw. Wenn ich nicht tun und die Mitglieder des Objekts festgelegt auf die Argumente wird es zu Problemen führen, später.

  2. Funktionen prüfen Argumente.

  3. In Eigenschaften. Wenn jemand einen falschen Wert oder andere Art setzt, soll ich schnell reagieren.

War es hilfreich?

Lösung

Die einfache Antwort ist Nein , verwendet Polymorphismus, Ausnahmen usw.

  1. Im Fall von Konstruktorargumente vom falschen Typ ist, wird eine Ausnahme ausgelöst werden, wenn die Ausführung von Code, der s auf dem Parameter Wesen eines bestimmten Typs abhängen. Wenn es eine seltsame, domänenspezifische Sache ist, Ihre eigene Exception erhöhen. Surround Codeblöcke, die mit try-except und behandeln Fehler wahrscheinlich sind zum Scheitern verurteilt. So ist es besser, Ausnahmebehandlung zu verwenden. ( Das Gleiche gilt für Funktionsargumente )

  2. In Eigenschaften gilt das gleiche Argument. Wenn Sie den Wert empfangen werden Validierung, eine Assertion verwenden sein Angebot usw. zu überprüfen, ob der Wert vom falschen Typ ist, wird es sowieso nicht. Dann behandeln AssertionError.

In Python, behandeln Sie Programmierer als intelligente Wesen !! dokumentieren Sie einfach Ihren Code gut (Dinge klar machen), erhöhen Ausnahmen angemessen, wenn, schreiben polymorphen Code usw. Lassen Sie das Exception Handling (wo es nur angemessen ist) / Fehler im Aufbau des Client-Code.

Warnung
Verläßt Ausnahmebehandlung für die Kunden bedeutet nicht, dass Sie eine Menge Müll Fehler bei dem ahnungslosen Benutzer schmeißen sollen. Wenn möglich, behandeln Ausnahmen, die aufgrund der schlechten Konstruktion oder aus einem anderen Grunde im Code selbst auftreten können. Der Code sollte robust sein. Wo es nicht möglich ist, für Sie den Fehler zu behandeln, höflich den Benutzer / Client-Code-Programmierer informieren!

Hinweis:
Im Allgemeinen schlechte Argumente zu einem Konstruktor ist nicht etwas, was ich zu viel Sorgen machen.

Andere Tipps

Die Antwort ist fast immer „nein“. Die allgemeine Idee in Python, Ruby und einige andere Sprachen uns " Duck Typing " genannt. Sie sollten sich nicht, was etwas ist, nur wie es funktioniert. Mit anderen Worten, „wenn alles, was Sie wollen etwas, das Sie nicht brauchen quakt zu prüfen, ob es tatsächlich eine Ente.“

Im wirklichen Leben ist das Problem mit dem Setzen in all den Typprüfungen ist die Unfähigkeit, Eingänge mit alternativen Implementierungen zu ersetzen. Sie können für dict überprüfen, aber ich möchte vielleicht etwas passieren, in dem kein dict, sondern implementiert die dict-API.

Geben Sie

nur prüft, ob eine von vielen möglichen Fehler im Code zu überprüfen. Zum Beispiel nicht dazu gehört Bereichsprüfung (zumindest nicht in Python). Eine moderne Antwort auf die Behauptung, dass es braucht Typprüfung zu sein, ist, dass es effektiver ist Unit-Tests zu entwickeln, die dafür sorgen, dass nicht nur die Arten richtig, aber auch, dass die Funktionalität korrekt ist.

Ein weiterer Gesichtspunkt ist, dass Sie Ihre API-Nutzer wie mündigen Erwachsenen behandeln sollte, und vertrauen ihnen die API korrekt zu verwenden. Natürlich gibt es Zeiten, wenn die Eingangskontrolle hilfreich ist, aber das ist weniger verbreitet als man denkt. Ein Beispiel dafür ist eine Eingabe von nicht vertrauenswürdigen Quellen, wie aus dem öffentlichen Netz.

Überprüfen Sie alles, was Sie wollen, müssen Sie nur noch explizit sein. Das folgende Beispiel ist eine Konstruktor von einem Modul in der Standardbibliothek - es überprüft die extrasaction arg:

class DictWriter:
  def __init__(self, f, fieldnames, restval="", extrasaction="raise",
               dialect="excel", *args, **kwds):
      self.fieldnames = fieldnames    # list of keys for the dict
      self.restval = restval          # for writing short dicts
      if extrasaction.lower() not in ("raise", "ignore"):
          raise ValueError, \
                ("extrasaction (%s) must be 'raise' or 'ignore'" %
                 extrasaction)
      self.extrasaction = extrasaction
      self.writer = writer(f, dialect, *args, **kwds)

Es ist oft eine gute Sache zu tun. Prüfen auf explizite Typen ist wahrscheinlich nicht so nützlich in Python (wie andere gesagt haben), aber für rechtlichen Wert Überprüfung kann eine gute Idee sein. Der Grund ist es eine gute Idee ist, dass die Software näher an die Quelle des Fehlers fehlschlagen wird (es folgt das Fail-Fast-Prinzip). Auch wirken die Kontrollen als Dokumentation zu anderen Programmierern und sich. Noch besser ist es „ausführbare Dokumentation“, was gut ist, weil es Dokumentation ist, die nicht lügen können.

Ein schneller und schmutzig, aber vernünftiger Weg, um Ihre Argumente zu überprüfen, ist assert zu verwenden:

def my_sqrt(x):
    assert x >= 0, "must be greater or equal to zero"
    # ...

Ihre Argumente Geltendmachung ist eine Art des armen Mannes Design by Contract. (Sie vielleicht gefallen Design by Contract nachzuschlagen;. Ist es interessant)

AFAIU, wollen Sie sicherstellen, dass einige Objekte zu einem frühen Zeitpunkt ( „folgt einer Schnittstelle“) verhalten als die von der tatsächlichen Nutzung. In Ihrem Beispiel wollen Sie wissen, dass Objekte Beispiel Erstellungszeit angemessen sind, nicht, wenn sie werden tatsächlich genutzt wird.

Unter Berücksichtigung der Tatsache, dass wir hier Python reden, ich will nicht den Eindruck erwecken assert (was ist, wenn python -O oder eine Umgebungsvariable PYTHONOPTIMIZE auf 1 gesetzt ist, wenn Ihr Programm läuft?) Oder für bestimmte Arten Überprüfung (weil das unnötig die Einschränkung Typen können Sie verwenden), aber ich werde frühe Tests Funktionalität , etwas entlang der Linien deuten darauf hin:

def __init__(self, a_number, a_boolean, a_duck, a_sequence):

    self.a_number= a_number + 0

    self.a_boolean= not not a_boolean

    try:
        a_duck.quack
    except AttributeError:
        raise TypeError, "can't use it if it doesn't quack"
    else:
        self.a_duck= a_duck

    try:
        iter(a_sequence)
    except TypeError:
        raise TypeError, "expected an iterable sequence"
    else:
        self.a_sequence= a_sequence

habe ich try… except… else in diesem Vorschlag, weil ich die Instanzmitglieder setzen will nur , wenn der Test erfolgreich ist, auch wenn der Code geändert oder ergänzt. Sie haben es nicht so zu tun, natürlich.

Für Funktionsargumente und Festlegen von Eigenschaften, würde ich diese Tests nicht im Voraus tun, ich würde nur die zur Verfügung gestellten Objekte und handeln geworfen Ausnahmen verwenden, es sei denn, die verdächtigen Objekte verwendet nach einem langwierigen Prozess zu gehen.

„Wenn ich nicht und setzen die Mitglieder des Objekts auf die Argumente wird es später zu Problemen führen.“

Bitte sehr klar über die genaue Liste der „Probleme“, die später verursacht wird.

  • Wird es nicht funktionieren? Das, was try / except Blöcke sind für.

  • Wird es "seltsam" verhalten? Das ist wirklich selten und wird zu „near-miss“ Typen und Operatoren beschränkt. Das Standardbeispiel ist die Teilung. Wenn Sie ganze Zahlen erwartet, bekam aber Gleitkommazahlen, dann Teilung kann nicht tun, was man wollte. Aber das mit dem // festgelegt, gegen / Division Operatoren.

  • Wird es einfach falsch sein, aber immer noch zu vervollständigen erscheinen? Das ist wirklich selten, und würde eine recht-sorgfältig gestaltete Art erfordern, die Standard-Namen verwendet, aber tat nicht-Standard-Dinge. Zum Beispiel

    class MyMaliciousList( list ):
        def append( self, value ):
            super( MyMaliciousList, self ).remove( value )
    

Other than that, ist es schwer, Dinge zu haben, „später Probleme verursachen“. Bitte aktualisieren Sie Ihre Frage mit speziellen Beispielen „Probleme“.

Wie Dalke sagt, die Antwort ist fast immer „nein“. In Python, kümmern Sie in der Regel nicht, dass ein ein Parameter ist eine bestimmte Art, sondern vielmehr, dass es verhält sie wie eine bestimmte Art. Dies ist bekannt als " Duck Typing ". Es gibt zwei Möglichkeiten zu testen, ob ein Parameter verhält sich wie einen bestimmten Typ: (1) Sie es verwenden können, als ob sie verhielten sich wie erwartet und eine Ausnahme auslösen, wenn / falls es nicht der Fall ist, oder (2 ) können Sie eine Schnittstelle definieren, wie diese Art sollte verhalten beschreibt und Test Übereinstimmung mit dieser Schnittstelle.

zope.interface ist meine bevorzugte Schnittstelle System für Python, aber es gibt einige andere. Mit einem von ihnen, definieren Sie eine Schnittstelle, dann erklären, dass eine bestimmte Art zu dieser Schnittstelle entspricht oder einen Adapter definieren, die Ihre Art in etwas verwandelt, das an diese Schnittstelle nicht entspricht. Sie können dann behaupten (oder Test, wie Sie wollen), dass paramters bieten (in der zope.interface Terminologie), die eine Schnittstelle.

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