最近気になってるUnityという組み込みC向けのテストフレームワーク。組み込みはハードウェア依存があるからTDDしにくいと思ってたけど、凡ミスでもmakeが通ってしまい組み込んでからミスに気づいてたら当たり前だけど開発サイクルは良くない。これはCIツールと組み合わせて使いたい。
今回は Python/JavaScript(ECMAScript) のイテレータとクロージャの基礎について。
Iterator
イテレータ(Iterator)はデータの各要素にアクセスを抽象化した仕組みです。
Python
もっとも簡単なのが、iter()を使う方法。そうすることでIteratableなオブジェクトとなる。
i = iter([1,2,3])
print i.next()# 1
for num in i:
print num #2,3
__iter__()はイテレータ自身を返し、next()は次の要素を返す。
ary = [1,2,3,4,5,6,6,7,8,8,9,9,0]
# 外部イテレータとして
it = iter(ary)
while 1:
try:
print it.next()
except StopIteration:
# next()はStopIteration例外を発生させる
break
# 内部イテレータとして
for element in ary:
print element
どちらも結果は同様。独自で実装している例もあります。
JavaScript
jsもイテレータオブジェクトは作成されると、next() かfor…in および for each でアクセスしていくことができます。
Object.prototypeが持っているプロパティを参照しないのでその辺を気にしなくて良いメリットがあります。
var ary = { name: 'mameroot', birthYear: 1987, work: "engineer"};
var it = Iterator(ary);
try {
while (true) {
console.log(it.next());
}
} catch (err if err instanceof StopIteration) {
console.log("end");
} catch (err) {
console.log("err: " + err.description);
}
nextメソッドで次の配列要素に切り替えていきます。
hasNext()が使えませんでしたので catch (err if err instanceof StopIteration) で例外キャッチする方法にしました。
Closure
クロージャ(Closure,閉包,関数オブジェクト)の実装も言語によって異なります。
Python
クロージャはpythonではlambda式になります。
下の例だとdefに比べ多少記述が短くなりますが、あまりlambdaのメリットを感じないと思いますが複雑に関数を組み合わせる時とか便利です。
def add(x, y):
return x + y
print add(1, 2)# 3
lam = lambda x,y : x+y
print lam(1,2)# 3
上がdef宣言、同じ意味の式がlam。
()で括ることで複数行で記述できますし、配列にlambda式を入れることもできます。
bda = (lambda x,y: x+y)
print bda(1,2)# 3
ary = [(lambda x: x+3), (lambda x: x**3), (lambda x: x/2)]
print ary[1](2) # 8
JavaScript
JavaScriptでは関数もオブジェクトです。
クロージャは生成された部分におけるローカル変数を参照できます。
function counter() {
var i = 0;
return function() { // 無名関数
return i += 1;
}
}
cnt = counter();
console.log(cnt()); // 1
console.log(cnt()); // 2 *ローカル変数(jsは関数スコープ)は保持
console.log(i); // もちろんダメ
上記例をカスタムしてcounterに引数を用意して this.getID = function() {return id} とかすればアクセサ指定子がないjsでもプライベート的な使い方ができるということです。
ちなみに名前空間で重複してもエラーが起きないので注意が必要が必要です。
Reminder
会社では月末に仕事で使った交通費や雑費の申請をしているのだけど忘れることが多いので、月末になると会社にReminderを送信するスクリプト。
実装は良くない。
# -*- coding: utf-8 -*-
# msg create
def create_message(from_addr, to_addr, subject, body):
encoding = 'utf-8'
msg = MIMEText(body.encode(encoding), 'plain', encoding)
msg['Subject'] = subject
msg['From'] = from_addr
msg['To'] = to_addr
msg['Date'] = formatdate()
return msg
# send by gmail
def send_via_gmail(from_addr, to_addr, msg):
s = smtplib.SMTP('smtp.gmail.com', 587)
s.ehlo()
s.starttls()
s.ehlo()
s.login('******@gmail.com', '*****')
s.sendmail(from_addr, [to_addr], msg.as_string())
s.close()
def sending_mail():
from_addr = '****@gmail.com'
to_addr = '*****'
msg = create_message(from_addr, to_addr, 'Auto Send by ****','交通費/雑費申請を忘れずに.')
send_via_gmail(from_addr, to_addr, msg)
print('[Info] sent msg')
def main():
time = datetime.datetime.today()
if time.day > 25:
# text_read&write_mode
f = open('schedule_log.txt','r+')
line = f.readline()
b = False
chk = '%s-%s\n' % (time.year,time.month)
while line:
print line
line = f.readline()
if line == chk:
b = True
if b == False:
print '[Info] today is %s' % time.day
sending_mail()
f.write(chk)
else:
print '[Info] Already sent'
f.close
if __name__ == "__main__":
main()