Kraft/sicherstellen, dass python-Klasse von Attributen des bestimmten Typs
Wie kann ich verhindern, dass eine Klasse member-variable auf einen bestimmten Typ in Python?
Längere version:
Habe ich eine Klasse, die mehrere member-Variablen, die von außen auf die Klasse. Aufgrund der Art, wie Sie verwendet werden, müssen Sie bestimmte Arten, entweder int oder Liste. Wenn das C++ war, ich würde einfach machen Sie privat und zu tun, Typ-überprüfung in der 'set' - Funktion. Da das nicht möglich, gibt es eine Möglichkeit zum einschränken der Typ der Variablen, so dass ein Fehler/exception zur Laufzeit Auftritt, wenn Sie ein Wert zugewiesen, der falsche Typ? Oder brauche ich, um zu überprüfen, Ihre Art, in jeder Funktion, die Sie verwendet?
Dank.
isinstance
überprüft, aber sonst ist gut (duck typing).InformationsquelleAutor thornate | 2012-02-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie eine Eigenschaft wie die anderen Antworten es -
also, wenn Sie wollen constraina einzelnes Attribut, sagen Sie "bar",
und beschränken es auf eine Ganzzahl, könnten Sie code schreiben:
Funktioniert:
(Es gibt auch eine neue Art des Schreibens Eigenschaften, mit der "Eigenschaft" built-in als Malerin der getter-Methode - aber ich bevorzuge die alte Art und Weise, wie ich es oben).
Natürlich, wenn man viele Attribute auf Ihre Klassen, und schützen möchten alle von Ihnen in dieser Art und Weise, er beginnt, sich zu ausführlich. Nichts zu befürchten - Python-introspection-Fähigkeiten erlauben es, erstellen Sie eine Klasse decorator, die automatisieren könnte dies mit einem minimum an Linien.
Und verwenden Sie einfach
auto_attr_check
als Klasse decorator, und declar derAttribute, die Sie wollen in der Klasse Körper gleich die Typen der Attribute benötigen, zu beschränken, zu:
Isinstance akzeptiert ein Tupel von Instanzen - da heißt es auf diesem code, kann man einfach ein Tupel von Typen die es gibt - es sollte nur funktionieren: ` bar = int, float`
InformationsquelleAutor jsbueno
Dies ist im Allgemeinen keine gute Idee, nach den Gründen, die @yak erwähnt in seinem Kommentar. Sie sind im Grunde zu, dass der Nutzer, von der Lieferung gültige Argumente, die über die richtigen Attribute/Verhalten, aber nicht in der vererbungsstruktur Sie hart codiert in.
Haftungsausschluss beiseite, es gibt ein paar Optionen für das, was Sie zu tun versuchen. Das Hauptproblem ist, dass es gibt keine privaten Attribute in Python. Also, wenn Sie müssen nur eine einfache alte Objekt-Referenz, sagen
self._a
Sie können nicht garantieren, dass die Benutzer nicht direkt festgelegt, obwohl Sie haben einen setter, die nicht Typ-überprüfung für Sie. Die folgenden Optionen zeigen, wie man wirklich durchzusetzen, die Art der überprüfung.Überschreiben von __setattr__
Diese Methode ist nur geeignet für eine (sehr) geringe Anzahl von Parametern, dass Sie dies tun. Die
__setattr__
Methode, welche aufgerufen wird, wenn Sie verwenden die Punktnotation, um weisen ein reguläres Attribut. Zum Beispiel,Wenn wir jetzt tun
A().a = 32
es nennen würdeA().__setattr__('a', 32)
unter der Haube. In der Tatself.a = a0
im__init__
verwendetself.__setattr__
als gut. Sie können diese nutzen, um die Durchsetzung der Typ-check:Der Nachteil dieser Methode ist, dass Sie haben, um eine separate
if name == ...
für jeden Typ, den Sie überprüfen möchten (oderif name in ...
zu überprüfen, mehrere Namen für einen bestimmten Typ). Der Vorteil ist, dass es ist die einfachste Art und Weise zu machen es unmöglich für den Benutzer zu umgehen, den Typ zu überprüfen.Eine Eigenschaft
Eigenschaften sind Objekte, ersetzen Sie Ihre normalen Attribut mit einem descriptor-Objekt (in der Regel durch die Verwendung eines decorator). Deskriptoren können
__get__
und__set__
Methoden, die definieren, wie das zugrunde liegende Attribut zugegriffen wird. Dies ist eine Art, wie wenn man die entsprechendenif
Niederlassung in__setattr__
und steckte es in eine Methode, die ausgeführt wird, nur für dieses Attribut. Hier ist ein Beispiel:Einer etwas anderen Weise zu tun, das gleiche kann gefunden werden in @jsbueno Antwort.
Während Sie eine Eigenschaft auf diese Weise ist die nette und meist löst das problem, es gibt aber ein paar Probleme. Die erste ist, dass Sie eine "private"
_a
Attribut, das der Benutzer ändern kann, direkt, unter Umgehung Ihren Typ zu überprüfen. Das ist fast das gleiche problem, wie mit einem einfachen getter-und setter, außer dass jetzta
zugänglich ist wie die "richtige" Eigenschaft, die Weiterleitungen auf die Set-hinter den kulissen, so dass es weniger wahrscheinlich, dass der Benutzer, wird mess with_a
. Das zweite Problem ist, dass Sie eine überflüssige getter, um die Eigenschaft der Arbeit als lese- /Schreibzugriff. Diese Fragen sind Gegenstand der diese Frage.Schaffen Sie eine Echte Setter-Nur Descriptor
Diese Lösung ist wahrscheinlich die robusteste insgesamt. Es wird vorgeschlagen, in der akzeptierte Antwort zu der Frage oben erwähnt. Im Grunde, anstatt eine Eigenschaft, die eine Reihe von Rüschen und die Annehmlichkeiten, die Sie nicht loswerden kann, erstellen Sie Ihre eigenen Deskriptor (und Lackierer) und verwenden, dass für alle Attribute, die erforderlich Typprüfung:
Setter lagern der tatsächliche Wert direkt in die
__dict__
von der Instanz zu vermeiden recursing in sich auf unbestimmte Zeit. Dies macht es möglich, den Wert eines Attributs ohne Angabe eine explizite getter. Da der Deskriptora
nicht die__get__
Methode, die Suche wird fortgesetzt, bis es feststellt, dass das Attribut im__dict__
. Dadurch wird sichergestellt, dass alle sets gehen Sie durch die descriptor - /Set, während Sie erhält, ermöglichen den direkten Zugriff auf den Attribut-Wert.Wenn Sie eine große Anzahl von Parametern, erfordern eine Prüfung wie diese, können Sie die Linie verschieben
self.__dict__['a'] = value
in der descriptor ist__set__
Methode:Update
Python ist3.6 ist dies für Sie fast aus-der-box: https://docs.python.org/3.6/whatsnew/3.6.html#pep-487-descriptor-protocol-enhancements
TL;DR
Für eine sehr kleine Anzahl von Parametern, müssen Typ-überprüfung, überschreiben
__setattr__
direkt. Für eine größere Anzahl von Parametern verwenden Sie die Set-nur-Deskriptor, wie oben gezeigt. Mit Eigenschaften, die direkt für diese Art von Anwendung stellt mehr Probleme, als es löst.InformationsquelleAutor Mad Physicist
Da Python 3.5, die Sie verwenden können,Typ-Hinweise, um anzuzeigen, dass ein class-Attribut sollte von einem bestimmten Typ. Dann, Sie könnten so etwas wie MyPy als Teil der continuous integration-Prozess, um zu überprüfen, dass alle Aufträge eingehalten werden.
Beispielsweise für das folgende Python-Skript:
MyPy geben würde die folgende Fehlermeldung:
Wenn Sie möchten, dass die Typen zur Laufzeit durchgesetzt werden, könnte die erzwingen Paket.
Aus der README:
InformationsquelleAutor ostrokach
Hinweis 1: @Blckknght danke für deinen fairen Kommentar. Ich vermisste die Rekursion Problem in meiner viel zu einfache test-suite.
Anmerkung 2: ich schrieb diese Antwort, wenn ich ganz am Anfang war von learning Python. Jetzt würde ich eher verwenden, Python-Deskriptoren finden Sie unter e.g link1, link2.
Dank für die bisherigen Beiträge und einige denken, ich glaube, ich habe herausgefunden, eine viel mehr benutzerfreundliche Art und Weise, wie zu beschränken, ein class-Attribut zu sein, der bestimmte Art.
Zuerst erstellen wir eine Funktion, die universell tests für Typ:
Dann haben wir einfach zu verwenden und anwenden, die es in unseren Klassen über setter. Ich denke, das ist relativ einfach, und Folgen Sie TROCKEN, vor allem, wenn Sie exportieren Sie es in ein separates Modul für feed Ihre gesamte Projekt. Siehe Beispiel unten:
Tests sinnvolle Ergebnisse produzieren. Finden erste tests:
Tests, Ergebnis:
return self.name
, weil das eben ruft die get-Methode wieder! Sie sollten wahrscheinlich nicht explizit suchen, bis Ihr Wert inself.__dict__
, da es ist, wo du bist-Einstellung. Eine andere Möglichkeit wäre die Verwendung einer anderen Attribut-Namen (wie_name
stattname
) für den Wert.InformationsquelleAutor CapedHero
Können Sie dieselbe Art von
property
wie Sie erwähnen in C++. Erhalten Sie Hilfe für die Eigenschaft von http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/.Link nur beantworten, sind schlecht, und in der Tat, der link ist gebrochen.
InformationsquelleAutor Nilesh
Können Sie es tun, genau wie Sie sagen, Sie haben gesagt, Sie würden es tun, in C++; machen die Zuordnung zu Ihnen zu gehen durch eine setter-Methode und die Set-Methode den Typ überprüfen. Die Konzepte der "private Staat" und "public interfaces" in Python erfolgt mit Dokumentation und Konvention, und es ist ziemlich unmöglich, Kraft jedermann zu benutzen, Ihre setter anstatt direkt zuordnen der Variablen. Aber wenn man den Parametern Namen mit einem Unterstrich beginnt und dokumentieren Sie die setter, wie die Art und Weise zu verwenden, Ihre Klasse, das sollte es tun (nicht verwenden
__names
mit zwei Unterstrichen; es ist fast immer mehr ärger als es Wert ist, es sei denn, du bist eigentlich in der situation, die Sie sind entworfen, in der die widerstreitenden Attribut-Namen in einer Vererbungshierarchie). Nur besonders stumpfe Entwickler vermeiden die einfache Möglichkeit, mit der Klasse so, wie es dokumentiert die Arbeit zugunsten herauszufinden, was die internen Bezeichnungen und verwenden Sie direkt; oder Entwickler sind frustriert, dass Sie Ihre Klasse verhält sich ungewöhnlich (für Python) und nicht so dass Sie verwenden eine benutzerdefinierte Liste-wie Klasse anstelle einer Liste.Können Sie Eigenschaften, wie in anderen Antworten beschrieben haben, um dies zu tun, während immer noch macht es so Aussehen, wie Sie die Zuweisung an Attribute direkt.
Persönlich finde ich die versuche zu erzwingen, geben Sicherheit in Python ziemlich sinnlos. Nicht, weil ich denke, dass statische Typ-überprüfung wird immer schlechter, aber weil selbst wenn man könnte hinzufügen, Typ-Anforderungen auf Ihrem Python-Variablen gearbeitet, 100% der Zeit, Sie einfach nicht wirksam bei der Aufrechterhaltung der Sicherheit, dass das Programm frei ist vom Typ Fehler, da Sie nur werfen von Ausnahmen zur Laufzeit.
Darüber nachdenken; wenn Ihr statisch kompilierte Programm erfolgreich kompiliert ohne Fehler, wissen Sie, dass es völlig frei von allen Fehlern, die der compiler erkennen kann (im Fall von Sprachen wie Haskell oder Quecksilber, das ist eine ziemlich gute Garantie, aber immer noch nicht abgeschlossen ist; im Fall von Sprachen wie C++ oder Java... meh).
Aber in Python, die Art der Fehler wird erst bemerkt, wenn es schon mal ausgeführt. Das bedeutet, selbst wenn Sie könnten, erhalten Sie die volle statische type enforcement überall in Ihrem Programm haben, müssen Sie die regelmäßige Ausführung von test-Suiten mit 100% code coverage, wirklich wissen, dein Programm ist frei von Fehler. Aber wenn Sie regelmäßig durchgeführte tests mit voller Abdeckung, die Sie würde wissen wenn Sie hatte jede Art Fehler, auch ohne den Versuch der Durchsetzung Typen! So ist der Vorteil wirklich nur doesn ' T scheinen es mir Wert. Sie wegwerfen Python ' s Stärke (Flexibilität), ohne zuzunehmen mehr als eine Kleinigkeit in einer seiner Schwächen (statische Fehlererkennung).
Es ist nicht zu akzeptieren, eine ganze Zahl, wenn Sie wirklich brauchen eine Liste. Es ist zu akzeptieren, was (entsprechend brav)
append
Methode. Warum sollte Sie ablehnen, meineRope
Klasse (spezialisierte Liste von strings), wenn der code, den Sie geschrieben habe perfekt funktioniert gut auf? In einer realen Welt-Projekt habe ich eigentlich ein Modul mit 5 verschiedenen Variationen der dict-wie die Klasse (mit keine gemeinsame Oberklasse für alle von Ihnen, außerobject
). Sie wäre sinnlos, wenn alle die Bibliothek-code, den ich verwende explizit die benötigten Instanzen derdict
."und es ist ziemlich unmöglich, jemanden zu verwenden, Ihre setter, eher als direkt zuweisen die variable" tatsächlich - das stimmt nicht n Python. Wenn Sie machen Verwendung von Deskriptoren, die leicht materialisiert mit dem
property
Helfer callable), würde es erfordern einige hässliche hacken um nicht zu verwenden, die setter-Funktion überhaupt.Mein Punkt war, dass die hässliche hacken ist immer möglich (und in der Regel nicht sehr schwierig), wenn Sie sich entschieden haben. Also es wird nicht aufhören, die Menschen spielen, die durch die Regeln erklärt in Ihrer Dokumentation,, die nicht versuchen, Zugriff auf die private variable direkt sowieso, und es wird nicht aufhören, die Menschen, die beschlossen haben, (wo auch immer Grund), die Sie brauchen, um zu bekommen, um die Regeln herum.
OO Kapselung nicht über die Verhütung bereit Zugriff auf Variablen als eine Frage der Sicherheit. Sie Steuern das gesamte system, in dem gleichen Prozess - in Java können Sie den Zugriff dann mit der Reflexion Werkzeuge und C++ haben Sie raw-Speicher zugreifen. In diesem Aspekt Python ist wohl auch besser, weil es Sie nicht geben ein Falsches Gefühl der Sicherheit.
InformationsquelleAutor Ben
Ich weiß, diese Diskussion hat sich erledigt, aber eine viel einfachere Lösung ist die Verwendung der Python-Struktur-Modul unten zeigen. Dies würde erfordern, dass Sie einen container für Ihre Daten, bevor Sie einen Wert zuweisen, aber es ist sehr effektiv bei der Aufbewahrung der Daten-Typ static. https://pypi.python.org/pypi/structures
InformationsquelleAutor Jon