70

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

def func(items=[]):
    print items

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

4

4 に答える 4

104

Noneデフォルト値として使用:

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

変更可能なデフォルト引数の問題は、関数のすべての呼び出し間で共有されることです。Python チュートリアル の関連セクションの「重要な警告」を参照してください。

于 2012-03-02T00:43:46.750 に答える
8

初めてこれに遭遇したばかりで、すぐに考えたのは、「まあ、とにかくリストを変更したくないので、本当に欲しいのは不変リストをデフォルトにすることです。そうすれば、誤ってPythonがエラーを出します変異させます。」不変リストは単なるタプルです。そう:

  def func(items=()):
      プリントアイテム

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

于 2013-09-17T17:20:59.173 に答える
3

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

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

すべての呼び出しが同じオブジェクトを共有している場合でも、それは不変であり、したがってそのプロパティは同じままであるため、問題ではない可換オブジェクトの場合。

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

于 2012-03-02T02:10:27.433 に答える
1

さらに、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]
于 2012-03-02T02:34:53.660 に答える