0

__init__()Python 3では、以下のようにクラス属性を関数の引数として使用できることがわかりました。

ファイル test.py:

class Foo:
    var1 = 23333
    def __init__(self, var=var1):
        self.var = var

コマンドで実行:

C:\Users\rikka\Desktop>py -3 -i test.py
>>> f1=Foo()
>>> f1.var
23333

しかし、dot.expression を使用すると、このクラスを初期化すると、インタープリターはエラーを報告します。

ファイルtest2.py:

class Foo:
    var1 = 23333
    def __init__(self, var=Foo.var1):
       self.var = var

コマンドで実行:

C:\Users\rikka\Desktop>py -3 -i test2.py
Traceback (most recent call last):
  File "test2.py", line 1, in <module>
    class Foo:
  File "test2.py", line 3, in Foo
    def __init__(self, var=Foo.var1):
NameError: name 'Foo' is not defined

Foo は環境のグローバルフレームの名前であるため、インタープリターが名前 'Foo' を見つけられない理由がわかりません。私が完全に理解していないPythonクラスに関するスコープ関連の概念はありますか?

4

2 に答える 2

6

関数のデフォルトは、呼び出されたときではなく、関数の定義時に設定されます。var1そのため、格納されるのは式ではなく、変数が表す23333です。クラスのビルド時にクラス本体のすべての名前が関数内のローカルとして扱われるvar1ため、関数が定義されたときにたまたまローカル変数になりますが、クラスのビルドがまだ完了していないため、名前はまだ存在しません。Foo

代わりにセンチネルを使用し、関数の本体で の現在の値を決定しますFoo.var1

def __init__(self, var=None):
    if var is None:
        var = Foo.var1
    self.var = var

Noneすぐに入手でき、実際の値として必要とされることはあまりないため、ここではセンチネルとして使用しました。個別の (つまり、デフォルト以外の) 値として設定できるようにする必要がある場合はvar、別のシングルトン センティネルを使用します。

_sentinel = object()

class Foo:
    var = 23333

    def __init__(self, var=_sentinel):
        if var is _sentinel:
            var = Foo.var1
        self.var = var
于 2015-09-24T13:07:03.560 に答える
1

問題は、その構築中に Foo を参照しようとしていることです。Foo.__init__が定義された時点、つまりFoo.varが評価された時点では、Fooまだ存在していません (そのメソッド、つまりFoo.__init__それ自体がまだ完全に構築されていないため)。

関数/メソッドのデフォルト パラメータは、関数/メソッドの定義中に解決されます。クラスは、定義後にのみ使用できます。クラス メソッド定義 (つまり、パラメーター) がクラス自体を参照する場合、循環依存が発生します。メソッドはクラスなしでは定義できず、クラスはそのメソッドなしでは定義できません。

そのような依存関係に実際にアプローチする方法については、Martijn Pieters の回答を参照してください。

于 2015-09-24T13:32:43.717 に答える