Raspberry Pi 日記

長嶋 洋一


2013年6月8日(土)

昨日は山口までの新幹線の中で十分にお勉強したので、湯田温泉では気持ちよく、行きつけのカラオケスナック「かもん」に行って17曲ほど熱唱した。 そしていよいよ、時間学会の初日である。 朝になってホテルで確認のためにプレゼンのKeynoteを起動してみると、何度やっても止まる(^_^;)というトラブルがあったが、どうやら研究室のパソコンで作ったKeynoteはこのMacBookAirでは走らないのであった。 多量のムービーを取り込んだのが敗因だったようだが、起動しないのでテキスト部分をレスキューする事も出来ず、どうせ用意したムービーはあるので、予稿の1ページPDFを表示するだけのプレゼン、と腹を括った(^_^;)。

そして今は、無事に好評のうちに午前のセッションで発表を終えて、山口大学の正門前にあるココイチで昼食を済ませて会場に戻ったところである。 時間学会の大会は初日の午後は一般公開のシンポジウムなので、その開始まで2時間近くあり、ちょっとだけでも昨日の続きでPythonをお勉強しておこう(そうすれば晩はまた「かもん」に行ける(^_^;))、という計画だ。 1画面しかないので、MacBookAirの画面は以下のように窮屈だが、まぁ仕方ない。

さて「5.1.3. List Comprehensions」であるが、これは配列を簡単に作り出せるものだという。 以下の例のように、最初に空白の配列を定義して、for文のループで再帰的にappendしている。

nagasm-3:Desktop nagasm$ cat test.py
#! /usr/bin/env python3.3
squares = []
for x in range(10):
	squares.append(x**2)
print(squares)

nagasm-3:Desktop nagasm$ Python test.py
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

nagasm-3:Desktop nagasm$ 
ただしこれは、以下のようにしても同様だという。 なんか凄い、これは半変態的である。
nagasm-3:Desktop nagasm$ cat test.py
#! /usr/bin/env python3.3
squares = [x**2 for x in range(10)]
print(squares)

nagasm-3:Desktop nagasm$ Python test.py
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

nagasm-3:Desktop nagasm$ 
上の「squares = [x**2 for x in range(10)]」というのは、「squares = list(map(lambda x: x**2, range(10)))」とやっても同じだが、より判りやすいだろう、と言っている。 まぁ、変態の自画自賛である(^_^;)。 そして、このかつての「Unixスクリプトオタク」の世界は、以下の例でもテキメンである。 以下の、上の方が論理を追いやすいが、これは以下の下の方でも出来る、という事らしい。
nagasm-3:Desktop nagasm$ cat test.py
#! /usr/bin/env python3.3
combs = []
for x in [1,2,3]:
	for y in [3,1,4]:
		if x != y:
			combs.append((x, y))
print(combs)
print([(x, y) for x in [1,2,3] for y in [3,1,4] if x != y])

nagasm-3:Desktop nagasm$ Python test.py
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

nagasm-3:Desktop nagasm$ 
なんだか、ツイッターになぞらえてトリッキーなスクリプトで複雑なサウンドを生成するSuperColliderのオタクを彷彿とさせる例であるが、ここもあまり近づかずに行きたい(^_^;)。 さらに、以下のような色々なテクニックも紹介されていた。
>>> vec = [-4, -2, 0, 2, 4]
>>> # create a new list with the values doubled
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]

>>> # filter the list to exclude negative numbers
>>> [x for x in vec if x >= 0]
[0, 2, 4]

>>> # apply a function to all the elements
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]

>>> # call a method on each element
>>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']

>>> # create a list of 2-tuples like (number, square)
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]

>>> # flatten a list using a listcomp with two 'for'
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
以下の例は、πの小数点以下の精度を再帰的に増やしたものである。 あまりにトリッキーだが、これで出来るというのは素晴らしい。 (結果が長いので手作業で改行していることに注意)
nagasm-3:Desktop nagasm$ cat test.py
#! /usr/bin/env python3.3
from math import pi
print([str(round(pi, i)) for i in range(1, 13)])
nagasm-3:Desktop nagasm$ Python test.py
['3.1', '3.14', '3.142', '3.1416', '3.14159', '3.141593', '3.1415927', '3.14159265', 
	'3.141592654', '3.1415926536', '3.14159265359', '3.14159265359']

nagasm-3:Desktop nagasm$ 
そして次は「5.1.4. Nested List Comprehensions」ということで、多次元の配列、あるいは配列のネスティングである。 Maxのjitterは64次元配列なので、あまり驚くことはないのだが、完結にまとめる記述法の変態度はアップしている。 以下の2つは同じだという。
nagasm-3:Desktop nagasm$ cat test.py
#! /usr/bin/env python3.3
matrix = [
	[1, 2, 3, 4],
	[5, 6, 7, 8],
	[9, 10, 11, 12],
]
print(matrix)
print([[row[i] for row in matrix] for i in range(4)])

nagasm-3:Desktop nagasm$ Python test.py
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

nagasm-3:Desktop nagasm$ 
そして最後の例として、以下の3つは全て同等だという。 同じことを色々に表現できるのがプログラミングなのだが、これはちょっとやり過ぎではないのか(^_^;)。
nagasm-3:Desktop nagasm$ cat test.py
#! /usr/bin/env python3.3
matrix = [
	[1, 2, 3, 4],
	[5, 6, 7, 8],
	[9, 10, 11, 12],
]

transposed1 = []
for i in range(4):
	transposed1.append([row[i] for row in matrix])
print(transposed1)

transposed2 = []
for i in range(4):
	transposed_row = []
	for row in matrix:
		transposed_row.append(row[i])
	transposed2.append(transposed_row)
print(transposed2)

print(list(zip(*matrix)))

nagasm-3:Desktop nagasm$ Python test.py
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

nagasm-3:Desktop nagasm$ 
ようやく配列シリーズが終わり、次は「5.2. The del statement」である。 リストから特定の要素をdeleteすると、以下のようにちゃんとリストは縮んでくれる、という事のようである。
>>> a = [-1, 1, 66.25, 333, 333, 1234.5]
>>> del a[0]
>>> a
[1, 66.25, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.25, 1234.5]
>>> del a[:]
>>> a
[]
また、「del a」とすれば、変数「a」そのものも抹消してくれるという。 この次の「5.3. Tuples and Sequences」は、リファレンスとして「Sequence Types ― list, tuple, range」を引け、という膨大なものだったので、以下の例をコピペするのみでパスである。「Tuples」というのは、数値とテキストとをまとめて一つの塊に扱うというようなものらしい。
>>> t = 12345, 54321, 'hello!'
>>> t[0]
12345
>>> t
(12345, 54321, 'hello!')
>>> # Tuples may be nested:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
>>> # Tuples are immutable:
... t[0] = 88888
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'tuple' object does not support item assignment
>>> # but they can contain mutable objects:
... v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])
そして次は「5.4. Sets」、集合である。 なんとPythonでは、以下のように集合の要素の確認だけでなく、要素間の引き算(取り除く)などの演算も出来るらしい。
>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # show that duplicates have been removed
{'orange', 'banana', 'pear', 'apple'}
>>> 'orange' in basket                 # fast membership testing
True
>>> 'crabgrass' in basket
False

>>> # Demonstrate set operations on unique letters from two words
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  # unique letters in a
{'a', 'r', 'b', 'c', 'd'}
>>> a - b                              # letters in a but not in b
{'r', 'd', 'b'}
>>> a | b                              # letters in either a or b
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>> a & b                              # letters in both a and b
{'a', 'c'}
>>> a ^ b                              # letters in a or b but not both
{'r', 'd', 'b', 'm', 'z', 'l'}
「list comprehensions」にあったように、以下のようなことも出来るという。 シェルでやったらエラーが出たのが謎だが(^_^;)、Pythonインタプリタで出来るので、まぁいいか。
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}
次は「5.5. Dictionaries」である。 これは、要素ごとにインデックスを振った配列のようなものらしいが、まぁLinuxのプロセスだって同様にIDで管理しているわけで、よくあるものだし、以下の例を眺めていると、色々と使えそうである。
>>> tel = {'jack': 4098, 'sape': 4139}
>>> tel['guido'] = 4127
>>> tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>> tel['jack']
4098
>>> del tel['sape']
>>> tel['irv'] = 4127
>>> tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>>> list(tel.keys())
['irv', 'guido', 'jack']
>>> sorted(tel.keys())
['guido', 'irv', 'jack']
>>> 'guido' in tel
True
>>> 'jack' not in tel
False
「dict()」というコンストラクタを使って、以下のように直接に辞書を作ることもできるらしい。
>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
このdictの、「キーと値」のペア、という概念は以下のようにPythonで適用されている。
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}

>>> dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'jack': 4098, 'guido': 4127}
次は「5.6. Looping Techniques」であり、「item()」メソッドを使って、上述の辞書の全体にわたって再帰的にループを回せる。 とりあえず以下のような例を並べるだけで次に行こう。
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
...     print(k, v)
...
gallahad the pure
robin the brave

>>> for i, v in enumerate(['tic', 'tac', 'toe']):
...     print(i, v)
...
0 tic
1 tac
2 toe

>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
...     print('What is your {0}?  It is {1}.'.format(q, a))
...
What is your name?  It is lancelot.
What is your quest?  It is the holy grail.
What is your favorite color?  It is blue.

>>> for i in reversed(range(1, 10, 2)):
...     print(i)
...
9
7
5
3
1

>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
>>> for f in sorted(set(basket)):
...     print(f)
...
apple
banana
orange
pear

>>> words = ['cat', 'window', 'defenestrate']
>>> for w in words[:]:  # Loop over a slice copy of the entire list.
...     if len(w) > 6:
...         words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
あとトピックが2つ、と先が見えてきた。 「5.7. More on Conditions」では、以下の例だけを見てもまったく不明であるが(^_^;)。説明が長いのでパスである。
>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>>> non_null = string1 or string2 or string3
>>> non_null
'Trondheim'
そしてこの章の最後の「5.8. Comparing Sequences and Other Types」は、まさにPythonならではの変態的概念である。 配列同士を比較できる、と思い込むそのアイデアには脱帽である(^_^;)。 「 'C' < 'Pascal' < 'Python'」というのは面白いが。
(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)
(1, 2, 3)             == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)
ここまで来たところで、ぼちぼちシンポジウムの会場に移動することにした。 そこそこ、Pythonについての整理、という意味では進んだ、ということにしよう。

「Raspberry Pi日記」トップに戻る