SML (Python の前に学んだ関数型プログラミング言語) では、次のことができます。
val x = 3;
fun f() = x;
f();
>>> 3
val x = 7;
f();
>>> 3
ただし、Python では、最初の呼び出しで 3 が返され、2 回目の呼び出しで 7 が返されます。
x = 3
def f(): return x
f()
>>> 3
x = 7
f()
>>> 7
Python で変数の値を関数にバインドするにはどうすればよいですか?
キーワード引数を使用できます。
x = 3
def f( x=x ):
return x
x = 7
f() # 3
キーワード引数は、関数の作成時に割り当てられます。関数が実行されると、関数のスコープ内で他の変数が検索されます。(それらが関数のスコープで見つからない場合、python は関数を含むスコープ内で変数を探します)。
あなたがすることができます:
x = 3
f = lambda y=x: y
f()
>>> 3
x = 7
f()
>>> 3
mgilson と Neal のように、これを行う最も簡単な方法は、 を定義するときにデフォルトの引数を使用することですf
。
より大きな問題は、ここでの哲学的な不一致です。Python はクロージャーを実行しますが、SML (私はあまり詳しくありません) や Haskell や Clojure など (どちらも私がよく知っている) とは異なる動作をします。これは、Python がクロージャーを処理する方法によるものですが、無名関数を異なる方法で定義し、副作用を許容する方法によるものでもあります。
通常、関数型アプローチがうまく機能しない場合、Python ではクラスを使用します。この場合、x の値を取得します。
class F(object):
def __init__(self, x):
self.x = x
def __call__(self):
return self.x
x = 3
f = F(x)
f()
# 3
x = 7
f()
# 3
これは、この例ではやり過ぎであり、明らかにここではお勧めしません。しかし、多くの場合、Python ではクラスを使用することが答えです。(これは大げさな言い方です。私の脳は例外を入力するよりも速く生成します。しかし、あなたが関数型のバックグラウンドを持っている場合、Python で問題にアプローチすることを学んでいるので、このステートメントは優れたヒューリスティックだと思います。 . )
余談ですが、これにより、関数の引数定義で変数をキャプチャすることで暗黙的に行われることが明確になることも興味深いですx
。つまり、オブジェクトが作成された時点での値にぶら下がる関数オブジェクトが作成されます。
この質問は、クロージャが作成されたときに外部変数の値(への参照ではない)をキャプチャする方法に関するもののようです。その意味で、通常の答えはデフォルトの引数を使用することです。
def f(x=x):
return x
# or
f = lambda x=x: x
(ただし、可変数の引数を取る関数が必要な場合、これは機能しません)。または、より一般的には(可変引数の場合でも機能します)、すぐに実行される明示的なラッピング関数を使用すると、あまりきれいではありません。
f = (lambda x: lambda: x)(x)
ただし、質問の前提が無効であることを指摘したいと思います。SMLでは、変数に割り当てることはできません(たとえば、次のような可変データ構造の変更については話していませんref
。割り当てについて話しているのです。変数へ); これを行うための言語の構文すらありません。
SMLコードで行っているのは、新しいスコープを作成し、新しいスコープで同じ名前の別の変数を定義することです。x
これにより、前のスコープが非表示になりx
ます。その2番目の変数の名前をいつでも別の名前に変更するだけで、プログラムに影響を与えることはありません。現在、Pythonには関数スコープがあり、関数内のコードブロックの内部スコープはありません。ただし、同じ解決策を適用できます。2番目の変数の名前を別の名前に変更するだけで、この問題は発生しません。