2013
04
26
04
26
Python, Boo: クロージャを使う
Demo
自分の使っている言語でクロージャを確認したかったので、上のものをPythonとBooで作ってみる。GUIはWPFで作ることにするので、PythonはIronPythonを使う。
まずIronPythonでは以下のように。ラムダでも書けるが、手順の多い処理を書くときにかなり読みにくいものになりそうだ。おとなしく通常の関数定義で書く。
C#やJavaScriptでは、匿名メソッドや匿名関数は匿名のままクロージャとして扱いやすかった。Pythonはここが弱いと思う。少し手順を踏まなければならない処理はラムダで書けないので、関数を書かなければならない。関数を書くということは命名が必要となる。
Booはかなり予想外な挙動をした。不便なわけでなくむしろ便利だったけど、ここにおいてはPythonでもC#でもないようなことがあった。
下にあるスクリプトで動く。
・C#、Python、JavaScriptで必要だったxCloneという変数にxの値をループの下のスコープでうつすという手順、これがいらない。C#、Python、JavaScriptから見たらおかしな書き方で問題が発生しない。
・C#と同様にループブロックのそとからxを使うことはできない。
->xがループ内のそれぞれのブロックで独立したものになっているということ?
・PythonやJavaScriptのように、ループ内で定義した変数、たとえばbuttonをループの外から使える。(ex. print(button) )
->スコープがifやforのブロックの範囲で適用されるわけではない。"for x in range(10):"という形でループを作ったとき、インクリメントされるxが特殊な変数になるようだ。
Booはforやifのブロックにまでスコープが適用される言語ではない。だけどforループを使う場合、forループでインクリメントされる変数が、ループで実行される各ブロックそれぞれの中でしか有効でない変数になっている。C#の場合は、このインクリメントされる変数は、ループを通して共通で扱う変数だ。だからC#の場合、xCloneを作った。BooではxCloneが必要なかった。
自分の使っている言語でクロージャを確認したかったので、上のものをPythonとBooで作ってみる。GUIはWPFで作ることにするので、PythonはIronPythonを使う。
まずIronPythonでは以下のように。ラムダでも書けるが、手順の多い処理を書くときにかなり読みにくいものになりそうだ。おとなしく通常の関数定義で書く。
C#やJavaScriptでは、匿名メソッドや匿名関数は匿名のままクロージャとして扱いやすかった。Pythonはここが弱いと思う。少し手順を踏まなければならない処理はラムダで書けないので、関数を書かなければならない。関数を書くということは命名が必要となる。
import wpf
from System import Console
from System.Windows import Application
from System.Windows import Window
from System.Windows.Controls import *
class Window1 (Window):
def __init__(self):
self.Width = 300
self.Height = 300
stackPanel = StackPanel()
self.Content = stackPanel
for x in range(6):
button = Button()
button.Content = "button" + x.ToString()
button.Height = 23
def OuterClosure():
xClone = x
def innerClosure(sender, e):
Console.WriteLine(xClone)
return innerClosure
button.Click += OuterClosure()
# button.Click += (lambda xClone:
# lambda sender, e:
# Console.WriteLine(xClone))(x)
stackPanel.Children.Add(button)
self.Show()
window = Window1()
app = Application()
app.Run(window)
Booはかなり予想外な挙動をした。不便なわけでなくむしろ便利だったけど、ここにおいてはPythonでもC#でもないようなことがあった。
下にあるスクリプトで動く。
・C#、Python、JavaScriptで必要だったxCloneという変数にxの値をループの下のスコープでうつすという手順、これがいらない。C#、Python、JavaScriptから見たらおかしな書き方で問題が発生しない。
・C#と同様にループブロックのそとからxを使うことはできない。
->xがループ内のそれぞれのブロックで独立したものになっているということ?
・PythonやJavaScriptのように、ループ内で定義した変数、たとえばbuttonをループの外から使える。(ex. print(button) )
->スコープがifやforのブロックの範囲で適用されるわけではない。"for x in range(10):"という形でループを作ったとき、インクリメントされるxが特殊な変数になるようだ。
Booはforやifのブロックにまでスコープが適用される言語ではない。だけどforループを使う場合、forループでインクリメントされる変数が、ループで実行される各ブロックそれぞれの中でしか有効でない変数になっている。C#の場合は、このインクリメントされる変数は、ループを通して共通で扱う変数だ。だからC#の場合、xCloneを作った。BooではxCloneが必要なかった。
namespace BooClosure
import System
import System.Windows
import System.Windows.Controls
partial class Window1(Window):
def constructor():
Width = 300
Height = 300
stackPanel as StackPanel = StackPanel()
Content = stackPanel
for x in range(6):
button as Button = Button()
button.Content = "button" + x.ToString()
button.Height = 23
button.Click += def(sender as object, e as RoutedEventArgs):
Console.WriteLine(x)
stackPanel.Children.Add(button)
//Console.WriteLine(x) // Unknown identifier: 'x'.
//Console.WriteLine(button) // can output
Show()
[STAThread]
def Main():
app = Application()
Window1()
app.Run()
スポンサーサイト