web-dev-qa-db-ja.com

Pythonの関数パラメーターのデフォルト値

可能性のある複製:
インスタンスメソッドの結果としてのパラメーターのデフォルト値

Pythonの関数パラメーターにデフォルト値を設定することは可能ですが、

def my_function(param_one='default')
    ...

現在のインスタンス(自己)にアクセスできないようです:

class MyClass(..):

    def my_function(self, param_one=self.one_of_the_vars):
        ...

私の質問:

  • これは、関数のデフォルトパラメータを設定するために現在のインスタンスにアクセスできないというのは本当ですか?
  • それが可能でない場合:理由は何ですか、これはPythonの将来のバージョンで可能になると想像できますか?
56
paweloque

次のように書かれています。

def my_function(self, param_one=None): # Or custom sentinel if None is vaild
    if param_one is None:
        param_one = self.one_of_the_vars

そして、selfは関数が開始するまで実際には存在しないという性質のため、Pythonでは決して起こらないと言っても安全だと思います...(参照することはできません。独自の定義-他のすべてと同様)

例:d = {'x': 3, 'y': d['x'] * 5}はできません

57
Jon Clements

あなたが思っている以上に多くのことがあります。デフォルトはstatic(=oneオブジェクトを指す定数参照) )および定義のどこかに保存されています。メソッド定義時に評価されます。インスタンスではなく、classの一部として。定数であるため、selfに依存できません。

以下に例を示します。それは直感に反しますが、実際には完全に理にかなっています:

def add(item, s=[]):
    s.append(item)
    print len(s)

add(1)     # 1
add(1)     # 2
add(1, []) # 1
add(1, []) # 1
add(1)     # 3

これは1 2 1 1 3を出力します。

と同じように機能するため

default_s=[]
def add(item, s=default_s):
    s.append(item)

明らかに、default_sを変更すると、これらの変更が保持されます。

以下を含むさまざまな回避策があります。

def add(item, s=None):
    if not s: s = []
    s.append(item)

または、これを行うことができます:

def add(self, item, s=None):
    if not s: s = self.makeDefaultS()
    s.append(item)

その後、メソッドmakeDefaultSselfにアクセスできます。

別のバリエーション:

import types
def add(item, s=lambda self:[]):
    if isinstance(s, types.FunctionType): s = s("example")
    s.append(item)

ここで、sのデフォルト値は工場出荷時の機能です。

これらすべての手法を組み合わせることができます。

class Foo:
    import types
    def add(self, item, s=Foo.defaultFactory):
        if isinstance(s, types.FunctionType): s = s(self)
        s.append(item)

    def defaultFactory(self):
        """ Can be overridden in a subclass, too!"""
        return []
22
Anony-Mousse

パラメータのデフォルト値は、「コンパイル」時に1回評価されます。したがって、明らかにselfにアクセスすることはできません。古典的な例は、listがデフォルトパラメータです。要素を追加すると、パラメーターのデフォルト値が変更されます!

回避策は、別のデフォルトパラメータ(通常はNone)を使用してから、変数をチェックして更新することです。

3
Karoly Horvath

ここで複数の誤った仮定があります。まず、関数はインスタンスではなくクラスに属します。つまり、実際の関数はクラスの2つのインスタンスで同じです。次に、デフォルトのパラメーターはコンパイル時に評価され、定数です(定数オブジェクト参照のように、パラメーターが可変オブジェクトの場合は変更できます)。したがって、デフォルトパラメータでselfにアクセスすることはできず、アクセスできなくなります。

2
l4mpi