空のリストであるデフォルトパラメータを回避するためのPython的な方法は何ですか?
-
21-08-2019 - |
質問
場合によっては、デフォルトのパラメーターが空のリストであることが自然に思えることがあります。まだ このような状況では Python が予期しない動作をします.
たとえば、次の関数があるとします。
def my_func(working_list = []):
working_list.append("a")
print(working_list)
初めて呼び出されたときはデフォルトが機能しますが、それ以降の呼び出しでは既存のリストが更新され (呼び出しごとに「a」が 1 つずつ)、更新されたバージョンが出力されます。
では、私が望む動作 (呼び出しごとに新しいリスト) を取得するための Python 的な方法は何でしょうか?
解決
def my_func(working_list=None):
if working_list is None:
working_list = []
working_list.append("a")
print(working_list)
None使用する必要があると言うのドキュメントrel="noreferrer">そのためのテストは、関数の本体にを。
他のヒント
既存の答えは、すでに直接解決策を提供してきました。しかし、これは新しいPythonプログラマのための非常に一般的な落とし穴があるため、それきれいに要約されているPythonがこのように動作理由の説明を追加する価値「の Pythonののへのヒッチハイカーズ・ガイド」「としての変更可能なデフォルト引数の ": http://docs.python-guide.org/en/latest/writing/落とし穴/ の
引用:「はPythonのデフォルト引数が一度だけ評価されている関数が定義されている場合(それはルビー、と言うであるように)、いないたびに関数が呼び出されるこれは変更可能なデフォルト引数を使用している場合突然変異していることを意味しそれは、あなたは意志と同様の機能への将来のすべての呼び出しのためにそのオブジェクトを変異しているの "
それを実装するためのサンプルコード:
def foo(element, to=None):
if to is None:
to = []
to.append(element)
return to
ない、それはこの場合には問題としていますが、なしをテストするために、オブジェクトIDを使用することができます:
if working_list is None: working_list = []
また、どのようにブール演算子の利点を取ることができるか、Pythonで定義されています:
working_list = working_list or []
呼び出し側はworking_listとしてあなたに(偽カウント)空のリストを与え、あなたの関数が、彼はそれを与えたリストを変更する予定であれば、これは予期しない動作をしますけれども。
関数の目的が次の場合 修正する として渡されるパラメータ working_list
, 、HenryR の回答を参照してください (=None、内部の None を確認してください)。
ただし、引数を変更するつもりがなく、それをリストの開始点として使用するだけの場合は、単純にコピーすることができます。
def myFunc(starting_list = []):
starting_list = list(starting_list)
starting_list.append("a")
print starting_list
(または、この単純なケースでは、 print starting_list + ["a"]
しかし、それは単なるおもちゃの例だったと思います)
一般に、引数を変更することは Python では悪いスタイルです。オブジェクトを変更することが完全に期待される関数は、オブジェクトのメソッドだけです。オプションの引数を変更することはさらにまれです。一部の呼び出しでのみ発生する副作用が本当に最適なインターフェイスなのでしょうか?
C の「出力引数」の習慣に従ってこれを行う場合、それはまったく不要です。いつでも複数の値をタプルとして返すことができます。
中間リストを作成せずに結果の長いリストを効率的に作成するためにこれを行う場合は、それをジェネレーターとして作成し、次を使用することを検討してください。
result_list.extend(myFunc())
電話をかけているとき。こうすることで、呼び出し規約が非常にクリーンな状態に保たれます。
オプションの引数を変更する 1 つのパターン は よく行われるのは、再帰関数の非表示の「メモ」引数です。
def depth_first_walk_graph(graph, node, _visited=None):
if _visited is None:
_visited = set() # create memo once in top-level call
if node in _visited:
return
_visited.add(node)
for neighbour in graph[node]:
depth_first_walk_graph(graph, neighbour, _visited)
私は、オフトピックであってもよいが、あなただけの可変数の引数を渡したい場合は、ニシキヘビの方法は、タプル*args
または辞書**kargs
を通過させることであることを覚えているでしょう。これらはオプションであり、構文myFunc([1, 2, 3])
よりも優れています。
あなたはタプルを渡したい場合は:
def myFunc(arg1, *args):
print args
w = []
w += args
print w
>>>myFunc(1, 2, 3, 4, 5, 6, 7)
(2, 3, 4, 5, 6, 7)
[2, 3, 4, 5, 6, 7]
あなたは辞書を渡したい場合は:
def myFunc(arg1, **kargs):
print kargs
>>>myFunc(1, option1=2, option2=3)
{'option2' : 2, 'option1' : 3}
すでに提供良いと正しい答えがありました。私はちょうどあなたがインスタンスのデフォルトの空のリストを持つクラスを作成したいとき、私はもっと美しく見つけた何をしたいかを書くために別の構文を与えたかっます:
class Node(object):
def __init__(self, _id, val, parents=None, children=None):
self.id = _id
self.val = val
self.parents = parents if parents is not None else []
self.children = children if children is not None else []
このスニペットは、もし他のオペレータの構文を使用します。それはコロンなしで小ぎれいなワンライナーだので、私は関与など、特にそれが好き、それはほぼ正常英語の文のように読み取ります。 :)
あなたのケースでは、あなたが書くことができます。
def myFunc(working_list=None):
working_list = [] if working_list is None else working_list
working_list.append("a")
print working_list
私は、UCSCの拡張クラスPython for programmer
を取った。
の真である:DEFキー(データ= []):
あなたのデータリストは、すべてのコールで空を開始するようにa)は良いアイデアです。
呼び出しの引数を提供していない機能に対するすべての呼び出しは、データとして、空のリストを取得するように、b)は良いアイデアです。
c)として長い間、あなたのデータは文字列のリストであると合理的な考えです。
デフォルトは[]データを蓄積し、デフォルト[]は後続の呼び出しによって変化するので、D)が悪い考えである。
答:
デフォルトは[]データを蓄積し、デフォルト[]は後続の呼び出しによって変化するので、D)が悪い考えである。