主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

Python, Boo: クロージャを使う

                
Demo
自分の使っている言語でクロージャを確認したかったので、上のものを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()
スポンサーサイト



プロフィール

h

Author:h

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon