関数型プログラミング
不明な睡眠Liは、これは科学技術の非常に暗い概念だと思うとき、私たちは多かれ少なかれ聞いたことがあるかもしれ関数型プログラミングの概念は、ただ聞きました。しかし、実際にはその意味は非常に単純ですが、多くの豊かな使用法を拡張します。
初期のプログラミング言語ではなく、多くの時間では、私たちよへの言語 の低レベル言語と高級言語 。アセンブリ言語のような、低レベルの言語、ほぼすべてのパッケージも、我々は手動でコールレジスタに代入演算子を必要とするんです。そして、プロセス指向やオブジェクトの賛成で自分自身をextricatesこれらのマシン指向の高水準言語命令から。言い換えれば、私たちはそれらのいくつかのコードを記述したコンピュータ計算またはオブジェクトから抽象化です。あなたが研究している場合は、オブジェクト指向、そしてあなたは、抽象化のプロセス指向、オブジェクト指向の高いいくつかのレベルと比較して、より完全なパッケージを作ったことがわかります。
オブジェクト指向のそれの後、我々はそれのカプセル化と抽象化を行うことができますか?関数型プログラミングのこのターン。
機能私たちは皆知っているが、その入力と出力が決定され、私たちが定義するプログラムです。私たちは、どこからでも呼び出すことができるいくつかの関数を記述します。非常に使いやすい機能するので、あなたができる 機能も可変のパラメータを返すように置くとパス 、それを?
OK、これは最も直感的かつ機能的なプログラミング機能です。換言すれば、我々はいくつかの機能はまた、変数として使用することができ、書き込みの両方が転送を使用することもできる、割り当てるために使用することができ、かつ戻すことができます。その結果、大幅に我々のコードを容易にしたが、これは善のためではなく、逆に、それは多くの問題をもたらし、最も直感的な問題は、関数のパラメータが原因であることができ、他の関数にも渡すことができ 機能につながります計算はとても不確かになって 何が起こるかの我々の期待を超えた多くの、。
だから、関数型プログラミングの利点と欠点の両方であり、それは本当に多くの問題を簡素化し、多くの新しい問題を作成している、我々は使用されるプロセスに注意する必要があります。
着信リターン機能
私たちは、フィルタを導入する前に、マップ、削減し、実際に私たちは関数型プログラミングの概念を使用しているときにカスタム、ソート。
我々はオブジェクトの配列を渡す場合、我々は、フィールドの並べ替えに基づいて開発されていることを願っています、のソートソートを呼び出すときに、例えば、この時間は、私たちはしばしば渡す必要が 匿名関数 フィールドの並べ替えを開発するために使用し、。実際には、入ってくる無名関数は、実際には、最も直感的な関数型プログラミングが反映されています:
sorted(kids, key=lambda x: x['score'])
加えて、我々はまた、例えば、私たちは例を見て、機能を返すことができます。
def delay_sum(nums):
def sum():
s = 0
for i in nums:
s += i
return s
return sum
我々はdelay_sumを呼び出し、この時間は、数字の文字列を渡す場合、我々は何を得るのですか?
答えは関数であり、私たちは、この印刷の情報から見た出力を、指示することができます:
>>> delay_sum([1, 3, 4, 2])
<function delay_sum.<locals>.sum at 0x1018659e0>
我々はそれを行う方法である必要があり、操作の結果を取得したいですか?そして、あなたは、この新しい変数を実行することができ、我々はそれを受け取るために、変数を使用し、また、非常に簡単です:
>>> f = delay_sum([1, 3, 4, 2])
>>> f()
10
これは、私たちができるという利点がある 計算を遅らせるを 関数型プログラミングを使用しない場合は、結果を計算するdelay_sumこの関数を呼び出すときに我々が必要、、。この操作は幸いにも非常に小さい場合、この操作は十分に大きい場合、それはオーバーヘッドが発生します。、おそらく夜遅くまで、我々は結果を計算する際に使用されますが、結果はすぐに使用することはできません。ケースということを、私たちは本当の必要性は、それによって操作を遅らせ、後でもう一度結果を使用する代わりに、操作の機能に戻ります。これはまた、のような枠組みを計算する一般的なアイデア、多くのある スパーク 。
クロージャ
私達はちょうど引用している例で見てみましょうは、sum関数を実現する社内の間だけdelay_sum機能では、我々は、この機能する渡さdelay_sum関数のパラメータを呼び出します。この種の 外側のスコープの 変数は、内部と呼ばれる関数によって参照されている 閉鎖 。
私たちは、ソースコードを表示しない限り、発信者のために、この内部関数の呼び出しデータは、完全にブラックボックス、閉じられているので、実際には、この概念は、そうでなければ、我々はデータのうち、それのソースを知らない、イメージです。ソースを知らないことに加えて、それはより重要なことは、それがノートオン変数は動的であるため、それは、機能外部参照変数であることです。我々は、 いくつかの外部変数の値を変更することで、操作の閉鎖の効果を変更することができます 。
これは、簡単な例を見て、発音には少し難しいです。Pythonで実際に計算する力であるmath.powと呼ばれる機能を有しています。例えば、我々はXの二乗を計算したい、我々は書く必要があります。
math.pow(x, 2)
現在のシナリオは、我々は唯一の正方形を計算する必要がある場合でも、毎回私たちはパスを持っているし、その後、我々はクロージャを使用して、この時間は、操作を簡素化することができる非常に面倒になります余分な2を渡します。
def mypow(num):
def pw(x):
return math.pow(x, num)
return pw
pow2 = mypow(2)
print(pow2(10))
閉鎖することにより、我々は 固定に2つ目の変数を置く POW2 math.pow(X、2)の機能を達成することができ、我々は唯一のオリジナルを使用する必要があります。私たちは3または4電力の電力を計算需要急に変更する必要がある場合は、我々は唯一のコードを変更することなく、できるMYPOW入ってくるパラメータを変更する必要があります。
実際には、これは使用シナリオの最大の閉鎖で、私たちはすることができます いくつかの非常に柔軟な機能を実現閉鎖を介し 、だけでなく、機能の一部が死んでコードを記述する必要なく、設定によって運営さの変更します。業界のために、コード行は、このようなパッケージストア間でアップルストアやアンドロイドなど、特にクライアント、変更することができませんでし知るためには、手動で更新するだけで、ユーザーが引っ張ってきます。問題は、ユーザーを変更するには、ほとんどない道を発生した場合は、手動での更新のみを待つことができます。したがって、通常の動作は、いくつかの同様の可撓性クロージャ関数を使用することで 、コンフィギュレーションモードを変更することにより、コードのロジックを変更します 。
また、使用することができますクロージャがあり 、一時的な変数やランタイム環境を 。
例えば、我々は以下のコードを見て:
def step(x=0):
x += 5
return x
これは、クロージャの使用の関数ではない、私たちが呼ぶ回数に関係なく、答えは、X + = 5の後に結果を5で実行され、関数が戻るとき保存されません、この値は、ステージング放棄さになります。私があれば 結果は最後の呼び出しに基づいていますたびに呼びたい 、我々は行動を変更するたびに保存された、というよりも、それを破棄することができることを意味し、?
今度は、クロージャを使用する必要があります。
def test(x=0):
def step():
nonlocal x
x += 5
return x
return step
t = test()
t()
>>> 5
t()
>>> 10
私たちのxの値がアップ格納されていること、 各修正は累積的になる のではなく、廃棄されました。私たちが新しいキーワードが呼ばれる使用していることに注意すべき ローカル以外の Pythonインタプリタは、このグローバル変数を見つけるためにそれらに行きますので、ローカル変数の現在の変数xを宣言するために使用されるのpython3のキーワードの中で一意ではないされており、 X、その結果、パラメータxに渡すことができ、関連する試験方法。Python2当局はお勧めしません、更新していません。
Pythonのすべてが、我々があれば、あるオブジェクトであるので、 外層の閉鎖がクラスであるとして機能する 場合は、実際の閉鎖で、クラス差は大きくないが、我々はそうであっても、相関関数の閉鎖機能にパッケージを返すことができますのほとんどのオブジェクト。例を見てください:
def student():
name = 'xiaoming'
def stu():
return name
def set_name(value):
nonlocal name
name = value
stu.set_name = set_name
return stu
stu = student()
stu.set_name('xiaohong')
print(stu())
我々はSET_NAME変更に閉鎖外の値を呼び出すので、最後の操作は、xiaohongです。だから、それはあってもよいが、通常の状況下では、我々はそれを使用することはありません。そして、の閉鎖によって比較したクラスの書き込み 動作速度が速くなります。もっと微妙な理由、理由は自己ポインタ閉鎖のいずれも、このようにいくつかのより高速の計算ので、アクセスおよび操作変数の多くを節約できます。疑似オブジェクトがあるうちに。しかし、クロージャが係合 使用の継承にない、派生 我々はこのような方法は現実にすることができ、使用しないであることがわかっているので、ほかの曲や通常の使用のうち、方法を。
ピット閉鎖
使いやすい閉鎖ではなく、慎重に、それはピットに非常に簡単なステップにではあるが、ここではいくつかの共通のピットです。
クロージャは、直接外部変数にアクセスすることはできません
これは、我々はすでに言及している何か、私たちはその閉鎖され 、直接外部変数にアクセスすることはできません 非ローカルキーワードでラベル付けされなければならないが、それ以外の場合は文句を言うでしょうです。
def test():
n = 0
def t():
n += 5
return n
return t
例えば、このような場合は、エラーになります。
使用することはできません閉鎖ループ変数
クロージャは大きな問題がある持っている あなたはループ変数を使用することはできません 論理的な観点からのコードが見つからないことであるという理由だけで、隠された深い穴、。これは、実行は、我々は根本的な原則の深い理解を見つけることができる持っている必要があることを、私たちの驚きに傾向があるとき、例えば、私たちは例を見て、論理的には問題のコードではありません。
def test(x):
fs = []
for i in range(3):
def f():
return x + i
fs.append(f)
return fs
fs = test(3)
for f in fs:
print(f())
それら上記の例では、我々は3つのFS店の閉鎖やリターンを使用し、3つのクロージャを作成するために、forループを使用します。私たちは、次の3つのクロージャを取得するには、テストを呼び出し、その後、私たちは呼ばれていました。
このロジックは理由によると、これら三つの閉鎖は、forループで作成され、その中で私たちは、閉鎖ループ変数iを使用し、問題ではないようです。私たちの考えによると、最終出力の結果は[3、4、5]する必要があることが、残念ながら、我々は最終的に取得する 結果は[5、5、5]です 。
それは奇妙に見える、とするので、驚くべきことではなかったこと 、彼は良いを設定すると、ループ変数iが閉鎖の作成ではありません 。我々はクロージャを実行するとき、私たちは私の対応する値を探して行く我々はクロージャを実行したときしかし、明らかに、サイクルは、私が2で停止し、この時間を超える実行されています。したがって、これら三つの閉鎖の結果は、2 + 3は5です。ピットは、論理私たちの書き込みの実行の閉鎖につながったロジック用のPythonインタプリタが正しいですが、それは注意する必要がありますので、あなたが忘れてしまった場合、それはあなたが合格したい、、、私たちの論理に従っていませんデバッグが困難になりますして下さい。
概要
表面上がそこにいくつかの問題やピットの閉鎖はあるが、それはまだ私達のある 一般的に使用されるPythonの高度な機能 、そしてそれはまた、他の多くの使用率が高いの基礎となっています。私たちが理解することを学ぶとクロージャは非常に必要であるので、値しありません。
実際には、だけではなく、閉鎖、機能の多くは、多かれ少なかれ非常に抽象的で、このような問題を抱えています。我々は、我々はもちろん、コードを抽象簡素化する場合ので、柔軟性が増加したが、同時に、我々はまた、作る 学習曲線が急になる より多くの私たちが理解し、内容を覚えておく必要がありもたらし、。これは、使いやすい使いやすい、給与に必要なコードの性質に備えており、多くの場合、より剛性の柔軟性のないことを意味、また、トレードオフです。この問題のために、私たちは、とき一目で心の状態が、良いニュースを維持する必要があります