web-dev-qa-db-ja.com

Pythonにはクラスプロトタイプ(または前方宣言)がありますか?

ファイルに一連のPythonクラスがあります。一部のクラスは他のクラスを参照しています。

私のコードは次のようなものです:

class A():
    pass

class B():
    c = C()

class C():
    pass

それを実行しようとすると、NameError: name 'C' is not defined。十分に公正ですが、それを機能させる方法はありますか、それとも対応するためにクラスを手動で並べ替える必要がありますか? C++では、クラスプロトタイプを作成できます。 Pythonに同等のものはありますか?

(私は実際にDjangoモデルで遊んでいますが、問題を複雑にすることはしませんでした)。

36
Mat

Pythonでは、プロトタイプ自体は作成しませんが、「クラス属性」とインスタンスレベルの属性の違いを理解する必要があります。上記の例では、インスタンスレベルの属性ではなく、クラスBのクラス属性を宣言しています。

これはあなたが探しているものです:

class B():
    def __init__(self):
        self.c = C()
35
Joe Holloway

実際、上記のすべてはPythonに関する素晴らしい観察結果ですが、どれも問題を解決しません。

Djangoは物事を内省する必要があります。

right必要なことを行う方法は次のとおりです。

class Car(models.Model):
    manufacturer = models.ForeignKey('Manufacturer')
    # ...

class Manufacturer(models.Model):
    # ...

リテラルクラス参照ではなく、クラス名をstringとして使用していることに注意してください。 Djangoは、Pythonが前方宣言を提供しないという問題を正確に処理するために、この代替手段を提供します。

この質問は、常にお客様に問題を尋ねる必要があるという従来のサポート質問を思い出させます:「あなたは何ですか本当に何をしようとしているのですか?」

55
verveguy

これは提示された問題を解決します(しかし、jholloway7が応答したときにインスタンス属性を本当に探していると思います):

class A:
    pass

class B:
    pass

class C:
    pass

B.c = C()
8
truppo

Pythonには、プロトタイプやRubyスタイルのオープンクラスはありません。しかし、本当に必要な場合は、newをオーバーロードするメタクラスを作成して、現在のネームスペースを検索して、クラスがすでに存在するかどうかを確認し、存在する場合は既存のタイプオブジェクトを返すようにすることができます。新しいものを作成するよりも。しばらく前に書いたORMでこのようなことをしましたが、非常にうまくいきました。

4
Erik Engbrecht

クラス属性とインスタンス属性に関するすべての正解。ただし、エラーが発生する理由は、クラスを定義する順序にすぎません。もちろん、クラスCはまだ定義されていません(インポート時にクラスレベルのコードがすぐに実行されるため)。

class A():
    pass

class C():
    pass

class B():
    c = C()

動作します。

0
Ali Afshar

質問が出されてから10年後、私は同じ問題に遭遇しました。参照はinitメソッド内で行う必要があると人々は提案していますが、クラスが実際にインスタンス化される前に、「クラス属性」としてデータにアクセスする必要がある場合があります。そのため、記述子を使用した簡単な解決策を考え出しました。

class A():
    pass

class B():
    class D(object):
        def __init__(self):
            self.c = None
        def __get__(self, instance, owner):
            if not self.c:
                self.c = C()
            return self.c
    c = D()

class C():
    pass

>>> B.c
>>> <__main__.C object at 0x10cc385f8>
0
Louis Ng