132

私はPythonクラスを持っていますが、実行時に必要なインスタンスは1つだけなので、属性はインスタンスごとではなく、クラスごとに1回だけ持つだけで十分です。複数のインスタンスが存在する場合(これは発生しません)、すべてのインスタンスが同じ構成である必要があります。次のオプションのどれがより良いまたはより「慣用的な」Pythonになるのだろうか。

クラス変数:

class MyController(Controller):

  path = "something/"
  children = [AController, BController]

  def action(self, request):
    pass

インスタンス変数:

class MyController(Controller):

  def __init__(self):
    self.path = "something/"
    self.children = [AController, BController]

  def action(self, request):
    pass
4

4 に答える 4

166

とにかくインスタンスが1つしかない場合は、インスタンスごとにすべての変数を作成するのが最善です。これは、変数へのアクセスが(少し)速くなるためです(クラスからインスタンスへの「継承」により、「ルックアップ」のレベルが1つ低くなります)。そして、この小さな利点と比較検討するための欠点はありません。

于 2010-04-26T15:16:24.033 に答える
46

マイクアレックスのアドバイスをさらにエコーし、自分の色を追加します...

インスタンス属性の使用は典型的なものです...より慣用的なPythonです。クラス属性は、ユースケースが特定されているため、あまり使用されません。同じことが静的メソッドとクラスメソッドと「通常の」メソッドにも当てはまります。これらは特定のユースケースに対応する特別な構造です。それ以外の場合は、Pythonプログラミングのあいまいな部分を知っていることを誇示したい、異常なプログラマーによって作成されたコードです。

Alexは返信の中で、ルックアップのレベルが1つ少なくなるため、アクセスが(少し)速くなると述べています...これがどのように機能するかをまだ知らない人のために、さらに明確にしましょう。これは変数アクセスと非常によく似ています。検索順序は次のとおりです。

  1. 地元の人
  2. 非地元住民
  3. グローバル
  4. ビルトイン

属性アクセスの場合、順序は次のとおりです。

  1. 実例
  2. クラス
  3. MRO(メソッド解決順序)によって決定された基本クラス

どちらの手法も「裏返し」の方法で機能します。つまり、最もローカルなオブジェクトが最初にチェックされ、次に外側のレイヤーが連続してチェックされます。

path上記の例では、属性を検索しているとしましょう。""のような参照に遭遇するとself.path、Pythonは最初にインスタンス属性を調べて一致するものを探します。それが失敗すると、オブジェクトがインスタンス化されたクラスをチェックします。最後に、基本クラスを検索します。Alexが述べたように、インスタンスで属性が見つかった場合、他の場所を探す必要がないため、少し時間を節約できます。

ただし、クラス属性を主張する場合は、その追加のルックアップが必要です。または、他の方法は、インスタンスの代わりに、たとえば。のMyController.path代わりに、クラスを介してオブジェクトを参照することですself.path。これは遅延ルックアップを回避する直接ルックアップですが、alexが以下で説明するように、これはグローバル変数であるため、保存しようと思っていたビットが失われます([global]クラス名へのローカル参照を作成しない限り) )。

つまり、ほとんどの場合、インスタンス属性を使用する必要があります。ただし、クラス属性がジョブに適したツールである場合があります。両方を同時に使用するコードは、インスタンス属性オブジェクトと同じ名前のクラス属性へのシャドウselfアクセスのみを取得するため、最も注意が必要です。この場合、属性を参照するには、クラス名による属性へのアクセスを使用する必要があります。

于 2010-04-26T16:14:23.793 に答える
26

疑わしい場合は、インスタンス属性が必要になる可能性があります。

クラス属性は、意味のある特別な場合のために予約するのが最適です。非常に一般的な唯一のユースケースはメソッドです。インスタンスが知る必要のある読み取り専用定数にクラス属性を使用することは珍しくありませんが(ただし、これの唯一の利点は、クラスの外部からのアクセスも必要な場合です)、それらに状態を格納することには注意が必要です。 、それはめったにあなたが望むものではありません。インスタンスが1つしかない場合でも、他の場合と同じようにクラスを作成する必要があります。これは通常、インスタンス属性を使用することを意味します。

于 2010-04-26T15:22:14.387 に答える
5

Pythonでクラス変数にアクセスするパフォーマンスでの同じ質問-ここでのコードは@EdwardLoperから採用されました

ローカル変数はアクセスが最も速く、モジュール変数、クラス変数、インスタンス変数の順でほぼ関連付けられています。

変数にアクセスできるスコープは4つあります。

  1. インスタンス変数(self.varname)
  2. クラス変数(Classname.varname)
  3. モジュール変数(VARNAME)
  4. ローカル変数(varname)

テスト:

import timeit

setup='''
XGLOBAL= 5
class A:
    xclass = 5
    def __init__(self):
        self.xinstance = 5
    def f1(self):
        xlocal = 5
        x = self.xinstance
    def f2(self):
        xlocal = 5
        x = A.xclass
    def f3(self):
        xlocal = 5
        x = XGLOBAL
    def f4(self):
        xlocal = 5
        x = xlocal
a = A()
'''
print('access via instance variable: %.3f' % timeit.timeit('a.f1()', setup=setup, number=300000000) )
print('access via class variable: %.3f' % timeit.timeit('a.f2()', setup=setup, number=300000000) )
print('access via module variable: %.3f' % timeit.timeit('a.f3()', setup=setup, number=300000000) )
print('access via local variable: %.3f' % timeit.timeit('a.f4()', setup=setup, number=300000000) )

結果:

access via instance variable: 93.456
access via class variable: 82.169
access via module variable: 72.634
access via local variable: 72.199
于 2018-10-12T10:21:23.933 に答える