web-dev-qa-db-ja.com

Pythonのクラスでインスタンス変数をNoneとして宣言することは良い習慣ですか?

次のクラスについて考えてみます。

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

私の同僚はそれを次のように定義する傾向があります:

class Person:
    name = None
    age = None

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

これの主な理由は、選択したエディターがオートコンプリートのプロパティを表示するためです。

個人的には、後者のクラスが嫌いです。クラスでこれらのプロパティがNoneに設定されているのは意味がないためです。

どちらがより良い練習になるでしょうか?

74
Remco Haszing

「これはあなたが思っていることをしない」というルールの下で、後者の悪い慣行を呼んでいます。

同僚の立場は次のように書き換えることができます。「私は、クラスの静的な準グローバル変数の束を作成します。これらの変数は、アクセスされることはありませんが、さまざまなクラスの名前空間テーブル(__dict__)、私にIDE何かをさせるだけです。 "

72
StarWeaver

1.コードを理解しやすくする

コードは書かれたよりもずっと頻繁に読み込まれます。コードのメンテナのタスクを簡単にします(来年はあなた自身かもしれません)。

ハードルールについては知りませんが、将来のインスタンスの状態を明確に宣言するためにpreferを使用しています。 AttributeErrorを使用してクラッシュするのは十分悪いことです。インスタンス属性のライフサイクルがはっきりと見えないことは、悪いことです。属性の割り当てにつながる可能性のある呼び出しシーケンスを復元するために必要な精神的な体操の量は、簡単ではなく、エラーにつながる可能性があります。

そのため、通常はすべてをコンストラクタで定義するだけでなく、可変属性の数を最小限に抑えるように努めています。

2.クラスレベルのメンバーとインスタンスレベルのメンバーを混在させない

class宣言内で定義したものはすべてクラスに属し、クラスのすべてのインスタンスで共有されます。例えば。クラス内で関数を定義すると、すべてのインスタンスで同じメソッドになります。同じことがデータメンバーにも当てはまります。これは、通常__init__で定義するインスタンス属性とはまったく異なります。

クラスレベルのデータメンバーは定数として最も役立ちます。

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

個人的には__ init __()メソッドでメンバーを定義します。クラスの部分でそれらを定義することを考えたことはありません。しかし、私が常に行うこと:__ init__メソッドで必要のないメンバーも含めて、__ init__メソッドのすべてのメンバーを初期化します。

例:

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

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

すべてのメンバーを1か所で定義することが重要だと思います。コードを読みやすくします。 __ init __()の内部か外部かは重要ではありません。しかし、チームが多かれ少なかれ同じコーディングスタイルに取り組むことが重要です。

ああ、あなたはあなたがメンバー変数に接頭辞「_」を追加したことに気付くかもしれません。

19
this.myself

これは悪い習慣です。これらの値は必要ありません。コードが散らかり、エラーが発生する可能性があります。

考慮してください:

>>> 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

私は「docstringsのようなもの」を使用して、これを無害であることを宣言します常にNoneであるか、または他の狭い範囲の値である限り、すべて不変です。

それはアタビズムの悪臭を放ち、静的に型付けされた言語に過度に執着します。そして、それはコードとしては良くありません。しかし、それはドキュメントに残っている小さな目的があります。

それは予想される名前が何であるかを文書化しているので、誰かとコードを組み合わせ、私たちの1人が「username」ともう1つのuser_nameを持っている場合、人間が別の方法で同じ変数を使用していないという手がかりがあります。

完全な初期化をポリシーとして強制すると、よりPython的な方法で同じことが実現されますが、実際のコードが__init__、これは使用中の変数を文書化するためのより明確な場所を提供します。

明らかに、ここでの大きな問題は、人々がNone以外の値で初期化するように誘惑することです。

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

グローバルトレースを残し、xのインスタンスを作成しません。

しかし、それはこのプラクティスよりも、Python全体としての奇妙なことであり、私たちはすでにそれについて偏執狂的であるはずです。

0