web-dev-qa-db-ja.com

Pythonのリストになるはずのパラメーターのデフォルト値を設定するためのベストプラクティスですか?

パラメーターとしてリストを受け取るPython関数があります。パラメーターのデフォルト値を次のように空のリストに設定すると、

def func(items=[]):
    print items

Pylintは「引数として危険なデフォルト値[]」と教えてくれます。だから私はここでのベストプラクティスは何ですか?

63
Jack Z

Noneをデフォルト値として使用します。

def func(items=None):
    if items is None:
        items = []
    print items

可変デフォルト引数の問題は、関数のすべての呼び出し間で共有されることです。 「Pythonチュートリアル =。

85
Sven Marnach

私はこれに初めて会ったばかりで、すぐに考えたのは「まあ、とにかくリストを変更したくないので、本当に欲しいのは不変リストにデフォルト設定することですPython =誤って変更するとエラーが発生します。」不変リストは単なるタプルです。

 def func(items =()):
 print items 

確かに、本当にリストを必要とするもの(isinstance(items、list)など)に渡すと、問題が発生します。しかし、それはとにかくコードの匂いです。

8
sfink

関数とメソッドの宣言のデフォルトパラメータとしての可変オブジェクトの問題は、評価と作成がまったく同じ瞬間に行われることです。 python-parserはfunction-headを読み取り、同時に評価します。

ほとんどの初心者は、呼び出しごとに新しいオブジェクトが作成されると想定していますが、それは正しくありません! 1つのオブジェクト(この例ではリスト)は宣言の瞬間に作成され、メソッドを呼び出しているときにオンデマンドではありません。

すべての呼び出しが同じオブジェクトを共有している場合でも、問題はありません。

慣例として、デフォルトのNoneオブジェクトを使用して、デフォルトの初期化の使用を示します。これは、呼び出し時に自然に評価されるfunction-bodyで実行できるようになりました。

3
Don Question

さらに、pythonが何であるかをよりよく理解するために、ここに私の小さなテーマのスニペット:

from functools import wraps
def defaultFactories(func):
    'wraps function to use factories instead of values for defaults in call'
    defaults = func.func_defaults
    @wraps(func)
    def wrapped(*args,**kwargs):
        func.func_defaults = Tuple(default() for default in defaults)
        return func(*args,**kwargs)
    return wrapped

def f1(n,b = []):
    b.append(n)
    if n == 1: return b
    else: return f1(n-1) + b

@defaultFactories
def f2(n,b = list):
    b.append(n)
    if n == 1: return b
    else: return f2(n-1) + b

>>> f1(6)
[6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1]
>>> f2(6)
[1, 2, 3, 4, 5, 6]
1
Odomontois