it-swarm.com.de

Ist es eine gute Praxis, Instanzvariablen in einer Klasse in Python als None zu deklarieren?

Betrachten Sie die folgende Klasse:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

Meine Kollegen neigen dazu, es so zu definieren:

class Person:
    name = None
    age = None

    def __init__(self, name, age):
        self.name = name
        self.age = age

Der Hauptgrund dafür ist, dass der Editor ihrer Wahl die Eigenschaften für die automatische Vervollständigung anzeigt.

Persönlich mag ich letzteres nicht, weil es keinen Sinn macht, dass für eine Klasse diese Eigenschaften auf None gesetzt sind.

Welches wäre besser und aus welchen Gründen?

74
Remco Haszing

Ich nenne die letztere schlechte Praxis unter der Regel "Das macht nicht das, was Sie denken".

Die Position Ihres Mitarbeiters kann wie folgt umgeschrieben werden: "Ich werde eine Reihe von klassenstatischen quasi-globalen Variablen erstellen, auf die nie zugegriffen wird, die jedoch Platz in den Namespace-Tabellen der verschiedenen Klassen beanspruchen (__dict__). nur um meine IDE etwas zu tun. "

72
StarWeaver

1. Machen Sie Ihren Code leicht verständlich

Code wird viel häufiger gelesen als geschrieben. Erleichtern Sie die Arbeit Ihres Code-Betreuers (möglicherweise auch Sie selbst im nächsten Jahr).

Ich kenne keine harten Regeln, aber ich bevorzuge, um einen zukünftigen Instanzstatus eindeutig deklarieren zu lassen. Ein Absturz mit einem AttributeError ist schon schlimm genug. Es ist schlimmer, den Lebenszyklus eines Instanzattributs nicht klar zu sehen. Die Menge an mentaler Gymnastik, die erforderlich ist, um mögliche Anrufsequenzen wiederherzustellen, die zur Zuweisung des Attributs führen, kann leicht nicht trivial werden und zu Fehlern führen.

Daher definiere ich normalerweise nicht nur alles im Konstruktor, sondern bemühe mich auch, die Anzahl der veränderlichen Attribute auf ein Minimum zu beschränken.

2. Mischen Sie keine Mitglieder auf Klassen- und Instanzebene

Alles, was Sie direkt in der Deklaration class definieren, gehört zur Klasse und wird von allen Instanzen der Klasse gemeinsam genutzt. Z.B. Wenn Sie eine Funktion innerhalb einer Klasse definieren, wird sie zu einer Methode, die für alle Instanzen gleich ist. Gleiches gilt für Datenmitglieder. Dies ist völlig anders als Instanzattribute, die Sie normalerweise in __init__.

Datenelemente auf Klassenebene sind als Konstanten am nützlichsten:

class Missile(object):
  MAX_SPEED = 100  # all missiles accelerate up to this speed
  ACCELERATION = 5  # rate of acceleration per game frame

  def move(self):
    self.speed += self.ACCELERATION
    if self.speed > self.MAX_SPEED:
      self.speed = self.MAX_SPEED
    # ...
27
9000

Persönlich definiere ich die Mitglieder in der __ init __ () Methode. Ich habe nie daran gedacht, sie im Klassenteil zu definieren. Aber was ich immer mache: Ich initiiere alle Mitglieder in der __ init__ Methode, auch diejenigen, die in der __ init__ Methode nicht benötigt werden.

Beispiel:

class Person:
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._selected = None

   def setSelected(self, value):
        self._selected = value

Ich denke, es ist wichtig, alle Mitglieder an einem Ort zu definieren. Dadurch wird der Code besser lesbar. Ob es innerhalb von __ init __ () oder außerhalb ist, ist nicht so wichtig. Für ein Team ist es jedoch wichtig, sich zu mehr oder weniger demselben Codierungsstil zu verpflichten.

Oh, und Sie werden vielleicht bemerken, dass ich Mitgliedsvariablen jemals das Präfix "_" hinzufüge.

19
this.myself

Dies ist eine schlechte Praxis. Sie brauchen diese Werte nicht, sie überladen den Code und können Fehler verursachen.

Erwägen:

>>> class WithNone:
...   x = None
...   y = None
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> class InitOnly:
...   def __init__(self, x, y):
...     self.x = x
...     self.y = y
... 
>>> wn = WithNone(1,2)
>>> wn.x
1
>>> WithNone.x #Note that it returns none, no error
>>> io = InitOnly(1,2)
>>> InitOnly.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: class InitOnly has no attribute 'x'
11
Daenyth

Ich werde dann "ein bisschen wie docstrings" verwenden und dies für harmlos erklären, solange es immer None ist oder einen engen Bereich anderer Werte, die alle unveränderlich sind.

Es stinkt nach Atavismus und übermäßiger Bindung an statisch typisierte Sprachen. Und es nützt nichts als Code. Aber es hat einen kleinen Zweck, der in der Dokumentation verbleibt.

Es dokumentiert die erwarteten Namen. Wenn ich also Code mit jemandem kombiniere und einer von uns 'Benutzername' und der andere Benutzername hat, gibt es einen Hinweis auf die Menschen, dass wir uns getrennt haben und nicht dieselben Variablen verwenden.

Durch das Erzwingen einer vollständigen Initialisierung als Richtlinie wird das Gleiche auf pythonischere Weise erreicht. Wenn jedoch __init__ Tatsächlichen Code enthält, bietet dies einen klareren Ort zum Dokumentieren der verwendeten Variablen.

Offensichtlich ist das große Problem hier, dass es Leute dazu verleitet, mit anderen Werten als None zu initialisieren, was schlecht sein kann:

class X:
    v = {}
x = X()
x.v[1] = 2

hinterlässt eine globale Ablaufverfolgung und erstellt keine Instanz für x.

Aber das ist eher eine Eigenart in Python als Ganzes als in dieser Praxis, und wir sollten darüber bereits paranoid sein.

0