2013年1月24日木曜日

第一回 岡山Python勉強会の振り返り

先日、第一回 岡山Python勉強会を行いました。

まずは場所を提供してくださったシステムヨシイさん、ありがとうございました!!

そして主旨としては「Python初心者(主に自分)がPython使うようになる」ための勉強会です。
なので「Pythonすげーよ!みんな教えるから使ってよ!!」とか「Pythonでこんなことできるから誰か聞いて!」みたいな良くあるセミナー形式ではなく「俺、初心者だけどPython面白そうだから一緒に勉強しようよ!」ってスタイルで公式チュートリアルの第1章から第4章までのハンズオンを行いました。
(次回以降もこのスタイルの予定です)
なので参加者はバリバリのPythonistaな人からPython初めてな自分まで幅広く8人揃いました。
個人的にはマサカリをブンブン投げられて血まみれになるかと思っていましたが和気藹々と楽しく意見交換しながら進めることが出来ました。
今回特徴的だったのは

他の言語との言語仕様と比べることでよりPythonが際立って見えたこと

ですね。
例えばJavaだとこうだよねー、とかPHPはキーワードで関数の引数渡せないから不便、みたいな意見が出ることでPythonって言語仕様がより明確に見えた気がしました。
あと、Rubyはなんでも出来る実装だなと改めて思いましたw

というわけで今回やったチュートリアルのおさらい
今回、自分が気になったところだけ抽出して書きますがほぼ公式チュートリアルの写経です。
読んで気になるところは公式チュートリアルを見ながら是非ハンズオンしてみてください。

1. やる気を高めよう

・小宇宙(コスモ)高めるの大事
・後、英語力大事...(震え声

2. Python インタプリタを使う

・引数の受け渡しにはargvを使う
スクリプトで呼んだ際はargv[0]はフルパスが格納されてる
・実行権限のあるPythonファイルの先頭行に

#!Pythonへのpath

と記述するとPythonスクリプトをシェルスクリプトのように実行できる
#!/usr/bin/python

print 'test'

./test.py ←実行権限のあるtest.pyを実行

結果
test

3. 形式ばらない Python の紹介

・電卓を使うときはScalaやcalcを使わずPythonを使う
# 整数の除算は floor (実数の解を越えない最大の整数) を返す:
>>> 7/3
2
>>> 7/-3
-3
# 浮動小数点数を使った場合は浮動小数点数を返す:
>>> 3 * 3.75 / 1.5
7.5
# 型が統一されていない状態で浮動小数点数を使っていた場合は浮動小数点数を返す:
>>> 7.0 / 2
3.5
>>>x = y = z = 0  # x と y と z をゼロにする
>>> x
0
>>> y
0
>>> z
0
・複素数が計算できる
・\(バックスラッシュ)で終わる行は次の行が継続行として扱われる
・対になった三重クォート """ または ''' で文字列を囲むことでヒアドキュメントのような複数行にまたがった文字列が書ける
print """
だだだ
じじじ
ずずず
ででで   どーーーーーーーん
"""
結果
だだだ
じじじ
ずずず
ででで   どーーーーーーーん

・文字列は + 演算子で連結させる (くっつけて一つにする) ことができ、 * 演算子で反復させることができる
>>> word = 'Help' + 'A'
>>> word
'HelpA'
>>> '<' + word*5 + '>'
''

# 隣あった二つの文字列リテラルは自動的に連結されます: 
>>> 'str' 'ing'             #  <-  これは ok
'string'
>>> 'str'.strip() + 'ing'   #  <-  これは ok
'string'
>>> 'str'.strip() 'ing'     #  <-  これはダメ
  File "", line 1, in ?
    'str'.strip() 'ing'
                  ^
SyntaxError: invalid syntax
・文字列のインデクス表示
>>> word[4]
'A'
>>> word[0:2]
'He'
>>> word[2:4]
'lp'

>>> word[:2]    # 最初の 2 文字
'He'
>>> word[2:]    # 最初の 2 文字を除くすべて
'lpA'
# インデックス指定された文字列中のある位置に代入を行おうとするとエラー:
>>> word[0] = 'x'
Traceback (most recent call last):
  File "", line 1, in ?
TypeError: object does not support item assignment
>>> word[:1] = 'Splat'
Traceback (most recent call last):
  File "", line 1, in ?
TypeError: object does not support slice assignment

# 文字列同士の内容を組み合わせた新しい文字列の生成は、簡単で効率的:
>>> 'x' + word[1:]
'xelpA'
>>> 'Splat' + word[4]
'SplatA'
・インデクスを負の数にして、右から数えることできる
>>> word[-1]     # 末尾の文字
'A'
>>> word[-2]     # 末尾から 2 つめの文字
'p'
>>> word[-2:]    # 末尾の 2 文字
'pA'
>>> word[:-2]    # 末尾の 2 文字を除くすべて
'Hel'
・リストの使い方
>>> a = ['spam', 'eggs', 100, 1234]
>>> a
['spam', 'eggs', 100, 1234]
>>> a[0]
'spam'
>>> a[3]
1234
>>> a[-2]
100
>>> a[1:-1]
['eggs', 100]
>>> a[:2] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>>> 3*a[:3] + ['Boo!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!']
# リストは個々の要素を変更することができる:
>>> a
['spam', 'eggs', 100, 1234]
>>> a[2] = a[2] + 23
>>> a
['spam', 'eggs', 123, 1234]
>>> # いくつかの項目を置換する:
... a[0:2] = [1, 12]
>>> a
[1, 12, 123, 1234]
>>> # いくつかの項目を除去する:
... a[0:2] = []
>>> a
[123, 1234]
>>> # いくつかの項目を挿入する:
... a[1:1] = ['bletch', 'xyzzy']
>>> a
[123, 'bletch', 'xyzzy', 1234]
>>> # それ自身 (のコピー) を先頭に挿入する
>>> a[:0] = a
>>> a
[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]
>>> # リストをクリアする: 全てのアイテムを空のリストに置換する
>>> a[:] = []
>>> a
[]
# リストの入れ子(多次元)もできる
>>> q = [2, 3]
>>> p = [1, q, 4]
>>> len(p)
3
>>> p[1]
[2, 3]
>>> p[1][0]
2
>>> p[1].append('xtra')     # 5.1節を参照
>>> p
[1, [2, 3, 'xtra'], 4]
>>> q
[2, 3, 'xtra']
>>> # Fibonacci 級数:
... # 二つの要素の和が次の要素を定義する
... a, b = 0, 1
>>> while b < 10:
...     print b
...     a, b = b, a+b
4. その他の制御フローツール
#if文
>>> if x < 0:
...      x = 0
...      print 'Negative changed to zero'
... elif x == 0:
...      print 'Zero'
... elif x == 1:
...      print 'Single'
... else:
...      print 'More'
ちょっとelifは違和感・・・
>>> # いくつかの文字列の長さを測る:
... a = ['cat', 'window', 'defenestrate']
>>> for x in a:
...     print x, len(x)
cat 3
window 6
defenestrate 12
リストの数でループが回るのでforというよりはeachですね。 しかも文字列を与えた場合は文字数でループします。 intの場合はerrorです。 条件式でループさせたい場合はwhileになります。
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(5, 10)
[5, 6, 7, 8, 9]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]
range()は条件が矛盾(stepとendの正負が違って終了しないなど)してる場合は空を返す ・関数の定義
>>> def fib(n):    # n までのフィボナッチ級数を出力する
...     """Print a Fibonacci series up to n."""
...     a, b = 0, 1
...     while a < n:
...         print a,
...         a, b = b, a+b
...
>>> # 今しがた定義した関数を呼び出す:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
>>> def fib2(n): #  n までのフィボナッチ級数を返す
...     """Return a list containing the Fibonacci series up to n."""
...     result = []
...     a, b = 0, 1
...     while a < n:
...         result.append(a)    # 下記参照
...         a, b = b, a+b
...     return result
...
>>> f100 = fib2(100)    # 関数を呼び出す
>>> f100                # 結果を出力する
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

#デフォルトの引数値
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
    while True:
        ok = raw_input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise IOError('refusenik user')
        print complaint
●必須の引数のみ与える: ask_ok('Do you really want to quit?') ●一つのオプション引数を与える: ask_ok('OK to overwrte the file?', 2) ●全ての引数を与える: ask_ok('OK to overwrte the file?', 2, 'Come on, only yes or no!') ・関数を keyword = value という形式のキーワード引数を使って呼び出すこともできます
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print "-- This parrot wouldn't", action,
    print "if you put", voltage, "volts through it."
    print "-- Lovely plumage, the", type
    print "-- It's", state, "!"

# 以下のいずれの方法でも呼び出せます
parrot(1000)
parrot(action = 'VOOOOOM', voltage = 1000000)
parrot('a thousand', state = 'pushing up the daisies')
parrot('a million', 'bereft of life', 'jump')

# しかし、以下の呼び出しはすべて不正なものです
parrot()                     # 必要な引数がない
parrot(voltage=5.0, 'dead')  # キーワード引数の後に非キーワード引数がある
parrot(110, voltage=220)     # 引数に対して値が重複している
parrot(actor='John Cleese')  # 未知のキーワードを使用している
・キーワード引数が入った辞書を使った方法 これが一番気持ち悪いって好評だったw
def cheeseshop(kind, *arguments, **keywords):
    print "-- Do you have any", kind, "?"
    print "-- I'm sorry, we're all out of", kind
    for arg in arguments:
        print arg
    print "-" * 40
    keys = sorted(keywords.keys())
    for kw in keys:
        print kw, ":", keywords[kw]

# 呼び出し
cheeseshop(
           "Limburger",
           
           "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

# 結果
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
13行目は文字列 kind 15行目と16行目はリスト *arguments 18~20行目はkey=valueな辞書 **keywords となっています。 リストは必ず辞書よりも前にある状態でないと渡せないので混合して使う際は注意が必要です。 混合して使うやり方は慣れてない人には一見して判断出来ないので難しいかもですね。
>>> range(3, 6)             # 個別の引数を使った通常の呼び出し
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args)            # リストからアンパックされた引数での呼び出し
[3, 4, 5]

>>> def parrot(voltage, state='a stiff', action='voom'):
...     print "-- This parrot wouldn't", action,
...     print "if you put", voltage, "volts through it.",
...     print "E's", state, "!"
...
>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
>>> parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
こんな辞書の使い方ならわかりやすくていいと思います。
phpもこういう引数の渡し方が出来るようになって欲しいですね。
それと変数のスコープですが関数の内から外は参照できます(関数の外の変数も)
また関数がネストしてる場合も内から外は参照できます。
ですが外から内は別のスコープになるので関数内で利用してる変数は呼べません。
(補足ですが未定義の変数はPythonではerrorになります)
・ラムダ式
うーん、紹介されてる使い方はピンと来なかった。
無名関数を変数に格納する方が自分は使う気機会が多いからかな?

と気になったところを自分の復習も兼ねてまとめました。
当日はこんな感じをそれぞれの環境で実行しながら確認して、その場その場で質問や意見を交換してました。
これを最後を読んだ人は前回のハンズオンとほぼ同様なのでいきなり次回から来ても全然問題ありません!
ということで次回は同様にシステムヨシイさんで2月26日(火)19:30から予定してます。
多分5章をじっくりやることになると思います。
僕はこれだけあればFizzBuzzが書けるのでこの週末にでもPythonで書いてみようと思います。
ちょうど土曜にRuby勉強会が岡山であるから会場でPythonだな(問題発言
ということで次回も楽しみにしてます!!