89581


**実行環境**  
Python 3.10.4

* * *
[code]

    class Sample:
        var = 10
        def func(self, arg=var): # working
            ...
    
[/code]

[code]

    class Sample:
        var = 10
        def func(self, arg=Sample.var): # not working
            ...
    
[/code]

クラス変数は，<クラス名>.<変数名>のようにしてアクセスするものであると考えていたのですが，メソッド定義時，デフォルト引数にクラス変数を設定する際に関しては，変数名をそのまま用いないとエラーが送出されます．(コード3行目)

メソッド定義時にSampleスコープの中からのみvarを探すためだろうか，という想像をしましたが，一貫性の観点からこの動作に少し違和感を覚えます．

抽象的な質問で恐縮ですが，この動作についてご教示頂けたら幸いです．また公式ドキュメントにこの動作に関する記述があれば是非お知らせください．


CC BY-SA 4.0
2022-06-24T08:31:41.483
89577
2022-06-24T14:56:57.623
51374
question
python python3
クラスメソッドのデフォルト引数にクラス変数を用いることについて


仕様等へのリンクはありませんが、おそらくこの質問記事が同様のことを扱っていると思われます。  
[How to use a class variable as a default argument value in
Python](https://stackoverflow.com/q/53527546/9014308)  
質問がこちら：

> I want to use a class variable as a default argument value in a static
> method. But when I reference the class, I get an error `NameError: name
> 'MyClass' is not defined`
[code]

>     class MyClass:
>  
>         x = 100
>         y = 200
>  
>         @staticmethod
>         def foo(x = MyClass.x, y = MyClass.y):
>             return x*y
>  
[/code]

回答がこちら：

> `MyClass` is not defined yet when Python wants to bind the default
> arguments, but `x` and `y` are already defined in the classes' scope.
[code]

>     class MyClass:
>         x = 100
>         y = 200
>  
>         @staticmethod
>         def foo(x=x, y=y):
>             return x*y
>  
[/code]

それから、そういう動作による注意事項もあるようです。

> Note that `foo` will not recognize reassignments to `MyCLass.x` and
> `MyClass.y` because the default arguments are bound once, when the function
> is created.

おそらくスクリプトの最初の実行時に、クラスやメソッドの解析を行っている時点では、まだクラスの定義が完了していなくて、該当のクラス(上記記事では`MyClass`、質問では`Sample`)が完全な形では存在しないから、クラスの属性としての`MyCLass.x`とか`Sample.var`を指定することが出来ないのでしょう。

一方メソッドの入り口を解析している時点から見た変数のスコープとして、`x`,`y`や`var`は既に定義されて存在するので指定することが出来るのだと考えられます。

* * *

そして参照記事回答の注意事項では、初回解析時点の変数の値が引数のデフォルト値として設定されるため、その後にクラス変数の値を書き変えても、引数のデフォルト値は変わらないということなのでしょう。

とはいえこんな記事もあって、変数の属性(や使い方?)によっては書き換えられると変わることもあるようですね。ただこの記事は微妙にずれている気もしますが。  
[Pythonの変数スコープの話](https://qiita.com/msssgur/items/12992fc816e6adf32cff)  
の記事の[クラスで定義する変数](https://qiita.com/msssgur/items/12992fc816e6adf32cff#%E3%82%AF%E3%83%A9%E3%82%B9%E3%81%A7%E5%AE%9A%E7%BE%A9%E3%81%99%E3%82%8B%E5%A4%89%E6%95%B0)の2つ目のコードブロック


CC BY-SA 4.0
2022-06-24T10:35:36.817
89579
2022-06-24T10:49:44.277
2022-06-24T10:49:44.277
26370
26370
89577
answer


クラス名が名前空間に束縛されるのは（=質問の例で言うと変数Sampleが作成されるのは）class文が実行された時の最後のタイミングです。  
クラス文の本体（スイート）が実行される時には、まだクラス名は変数として参照できません。

クラス変数が、クラスのオブジェクト（typeクラスのインスタンス）の属性として束縛されるのも、クラス文の本体（スイート）が実行された後です。

class文が実行される時に起きることの順番は、公式ドキュメントで以下の様に明記されています。

<https://docs.python.org/ja/3/reference/compound_stmts.html#class-definitions>

> 次にクラスのスイートが、新たな実行フレーム (名前づけと束縛 (naming and binding) を参照してください)
> 内で、新たに作られたローカル名前空間と元々のグローバル名前空間を使って実行されます
> (通常、このスイートには主に関数定義が含まれます)。クラスのスイートが実行し終えると、実行フレームは破棄されますが、ローカルな名前空間は保存されます。次に、継承リストを基底クラスに、保存されたローカル名前空間を属性値辞書に、それぞれ使ってクラスオブジェクトが生成されます。最後に、もとのローカル名前空間において、クラス名がこのクラスオブジェクトに束縛されます。

それと、デフォルト値が評価されるのは関数呼び出し時ではなくて、関数定義時（つまりdef文が実行された時）の1回だけだからです。

<https://docs.python.org/ja/3/faq/programming.html#why-are-default-values-
shared-between-objects>

>
> 関数の呼び出しによって、デフォルトの値に対する新しいオブジェクトが作られるのだと予想しがちです。実はそうなりません。デフォルト値は、関数が定義されたときに一度だけ生成されます。

* * *
[code]

    var = 10
    
[/code]

で（class文の実行中の）ローカルな名前空間に束縛された名前varは、

[code]

        def func(self, arg=var):
            ...
    
[/code]

でdef文が実行された時に1回だけ評価されます。

このタイミングでローカル変数のvarは参照可能ですが、グローバル変数Sampleは参照できません。


CC BY-SA 4.0
2022-06-24T14:44:13.583
89581
2022-06-24T14:56:57.623
2022-06-24T14:56:57.623
12274
12274
89577
answer