Skip to content

Instantly share code, notes, and snippets.

@singletongue
Last active Feb 14, 2016
Embed
What would you like to do?
「言語処理100本ノック」に取り組むための Python 入門資料です。

100本ノックの前の Python クラッシュコース

対象

  • Python は初めて学ぶ
  • 大学の授業で C や Java を(とりあえずは)やった
  • 変数や関数、制御構造(条件分岐や繰り返し)とは何なのかは知っている

おことわり

  • Python 2.7 を対象としています。

Python プログラムの例

以下に Python プログラムの例を示す。これは、乱数によって今日なにを食べたら良いかを決めるプログラムである。

# -*- coding: utf-8 -*-

from random import randint

dice = randint(0, 3)

if dice == 0:
    print u'きょうはお肉!'
elif dice == 1:
    print u'きょうはお魚!'
else:
    print u'きょうはお野菜!'

このプログラムを実行すると、乱数によって、「きょうはお肉!」とか「きょうはお魚!」といった文字列が画面に出力される。

コメント

# で始まる行はコメントとなり、実行されない。

# この行はコメント

なお、先のプログラム例の1行目にあった

# -*- coding: utf-8 -*-

というのは「このファイルは文字コードが UTF-8 で書かれていますよ」ということを宣言するものである。 日本語の文字などユニコード文字を含むプログラムでは、これを1行目(または2行目)に書かないとエラーになるので、 「プログラムの1行目には必ずこれを書く」と決めてしまっても良い。

標準出力

print で変数の値などを出力できる。改行は自動で末尾に挿入される。

a = 'Python'
b = 2.7
print a     # Python と出力される
print b     # 2.7 と出力される
print a, b  # Python 2.7 と出力される

変数

Python では、C と異なり、変数の宣言時に型を指定する必要はない。

a = 42      # int(整数型)の「42」が代入される
b = 42.0    # float(浮動小数点型)の「42.0」が代入される
c = '42'    # str(文字列型)の「'42'」が代入される

変数を値の代入なしに宣言することは出来ない。

a  # エラー (NameError)

変数の型を確認するには、type() を用いる。

type(a)  #-> int
type(b)  #-> float
type(c)  #-> str

次のようなことも出来る。

a, b, c = 5, 7, 3  # 一度に複数の変数に代入
x = y = z = 0      # 一度に同じ値を代入
a, b = b, a        # スワップもこれでOK (a = 7, b = 5 となる)

変数の名前には、英字、数字、アンダーバーのみが使える。英字の大文字と小文字は区別される。最初の文字は数字であってはいけない。

var = 1  # OK
Var = 2  # OK (var とは別の変数)
v1 = 3   # OK
v_1 = 4  # OK
1v = 5   # エラー (SyntaxError)

変数名として、以下の語は使えない(Python の文法で使われている「予約語」である)。

and       del       from      not       while
as        elif      global    or        with
assert    else      if        pass      yield
break     except    import    print
class     exec      in        raise
continue  finally   is        return
def       for       lambda    try

また、strdict のような、データ型や関数の名前として使われている語を変数名として用いることは、エラーとはならないものの、予期しない動作を招くことがあるので、避けるべきである。

基本的なデータ型

Python で使われる基本的なデータ型には、以下のようなものがある。

型名(クラス名) 日本語での呼び名 リテラルの例
int 整数 42, 0, -1
float 浮動小数点 3.14, 0.0, -5.0
bool ブール値 True, False
str 文字列 'dog', 'd', '1'
unicode ユニコード文字列 u'あ', u'日本語'

整数、浮動小数点

数値の扱いは、ほとんど直感通りである。

5        #-> 5 (int)
-2       #-> -2 (int)
3.14     #-> 3.14 (float)
10.0     #-> 10.0 (float)

7 + 94   #-> 101
11 - 92  #-> -81
14 * 67  #-> 938
7 / 5    #-> 1  (int 同士の演算結果は int になる)
7 / 5.0  #-> 1.4 (演算に float が含まれると結果は float になる)
7 % 5    #-> 2 (剰余を求める)
2 ** 5   #-> 32 (累乗)
(2.0 + 3) * (4 - 5)  #-> -5.0

a = 5      # a は 5
a = a + 1  # a は 6
a += 1     # a は 7
a++        # このような書き方はできない (SyntaxError)

ブール値

ブール値は、値として TrueFalse しか持たない。真偽値を表すものとして、if 文の条件式として用いたり、論理演算などの結果として返される。

True   #-> True
False  #-> False

数値と比較演算

比較演算子を用いた以下のような演算は、すべてブール値を返す。

# 「より大きい」「より小さい」
3 < 5     #-> True
3 > 5     #-> False
# 「以上」「以下」
2 <= 4    #-> True
2 <= 2    #-> True
2 >= 4    #-> False
# 「等しい」
2 == 2    #-> True
2 == -2   #-> False
2 == 2.0  #-> True
# 「等しくない」
2 != -2   #-> True

文字列

文字列は、シングルクォートかダブルクォートで文字を囲んで作る。

'Python'          #-> 'Python'
"this is a pen."  #-> 'this is a pen.'
'He said, "Hi."'  #-> 'He said, "Hi."'  (ダブルクォートを含む文字列)
''                #-> '' (空文字列)

改行やタブ文字は以下のように表す。

'\n'  # 改行
'\t'  # タブ文字

3つのシングルクォートかダブルクォートで、改行を含む文字列をそのまま記述できる。

"""Hello,
world!
"""        #-> 'Hello,\nworld!\n'

文字列同士は + で連結でき、* で繰り返しが出来る。

city_name = 'Tokyo'
"At " + city_name + " now."  #-> 'At Tokyo now.'
city_name * 3                #-> 'TokyoTokyoTokyo'

インデックス、スライスによる切り出し

インデックスの指定によって、文字列の任意の位置の文字を切り出せる。最初の文字のインデックスは 0 である。

name = 'Hanako'
name[0]   #-> 'H'
name[1]   #-> 'a'
name[5]   #-> 'o'
name[-1]  #-> 'o' (マイナスで指定すると、文字列の末尾から数える)
name[-2]  #-> 'k'

name[6]   #-> 文字列の範囲外を指定するとエラー (IndexError)

ある範囲の文字列を切り出すには、スライスを用いる。

name = 'Kintaro'
name[0:3]  #-> 'Kin' (インデックスが0から3までの範囲)
name[3:5]  #-> 'ta'  (インデックスが3から5までの範囲)
name[3:]   #-> 'taro'  (インデックスが3以降の範囲)
name[:5]   #-> 'Kinta'  (インデックスが5以前の範囲)
name[:-1]  #-> 'Kintar'  (マイナスのインデックスを指定)

name[0:7:2]  #-> 'Knao' (インデックスが0から7までの範囲から、2文字ごとに文字を切り出す)
name[::2]    #-> 'Knao'
name[::-1]   #-> 'oratniK'

name[-99:99]  #-> 'Kintaro'  (スライスは元の文字列の範囲外を含んでいてもエラーにはならない)

インデックスは、以下の図のように、文字と文字の間を示すものと捉えると良い。

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

インデックスやスライスによって、元の文字列を変更することは出来ない。

name = 'Kintaro'
name[0] = 'G'     # エラー (TypeError)
name[0:2] = 'Ka'  # エラー (TypeError)

文字列の長さは、len()で取得できる。

len('Programming')  #-> 11
len('')             #-> 0
len('\n')           #-> 1

文字列のさまざまな操作

# 検索、置換
s = 'Hello, world!'

s.find(',')  #-> 5
s.find('l')  #-> 2 (最初に見つかった位置が返される)
s.find('a')  #-> -1 (見つからなかった場合)

s.replace('world', 'universe')  #-> 'Hello, universe!'
s  #-> 'Hello, world!' (元の文字列を書き換えているわけではない)
# 分割、結合
# (リスト(複数の値を格納するデータ構造)については後述)
tsv = '012345\tJohn\tUnited States\tMale'
tsv.split('\t')      #-> ['012345', 'John', 'United States', 'Male']

word_list = ['This', 'is', 'a', 'pen']
' '.join(word_list)  #-> 'This is a pen'
# 端からの文字の除去
header = '  -*- text -*-  \n'
header.strip()         #-> '-*- text -*-'
header.rstrip('\n')    #-> '  -*- text -*-  '
header.strip('-* \n')  #-> 'text' (文字列を除去するのではなく、引数中の文字をすべて除去する)
# 特定の文字で始まるか、終わるかのチェック
s = 'Computer science'
s.startswith('C') #-> True
s.startswith('c') #-> False
s.endswith('e')   #-> True

# 大文字化、小文字化
s.upper()  #->'COMPUTER SCIENCE'
s.lower()  #-> 'computer science'
# フォーマット (数値などを文字列に埋め込む)
'{} is {}'.format('Taro', 255)                #-> 'Taro is 255'
'{1} is {0}'.format('Taro', 255)              #-> '255 is Taro'
'{name} is {id}'.format(name='Taro', id=255)  #-> 'Taro is 255'
'{:.2f}'.format(0.5)                          #-> '0.50'
'{:.2%}'.format(0.5)                          #-> '50.00%'

ユニコード文字列の扱い

Python 2 では、日本語の文字をはじめとするユニコード文字列は、文字列リテラルの '' または "" の前に u をつけて表す。

iroha_u = u'いろは'
type(iroha_u)  #-> unicode
iroha_u        #-> u'\u3044\u308d\u306f'
iroha_u[2]     #-> u'\u306f' (printすると「は」)
len(iroha_u)   #-> 3

ユニコード文字列として指定しないと、ASCIIコードで解釈される。

iroha_a = 'いろは'
type(iroha_a)  #-> str
iroha_a         #-> '\xe3\x81\x84\xe3\x82\x8d\xe3\x81\xaf'
iroha_a[2]      #-> '\x84' (printすると「�」(文字化け))
len(iroha_a)    #-> 9

型変換

以下のように、異なるデータ型への変換が可能である。

float(100)       #-> 100.0
int(3.0)         #-> 3
int(3.9)         #-> 3
str(42.195)      #-> '42.195'
float('42.195')  #-> 42.195
int(True)        #-> 1
int(False)       #-> 0
bool(1)          #-> True
bool(0)          #-> False
bool(-1)         #-> True

基本的なデータ構造

Python で使われる基本的なデータ構造には、以下のようなものがある。

型名(クラス名) 日本語での呼び名 書き方の例 変更可能か
list リスト [42, 'Taro', True] Yes
tuple タプル (42, 'Taro', True) No
set 集合 {42, 'Taro', True} Yes
dict 辞書 {'id': 42, 'name': 'Taro', 'is_student': True} Yes

リスト

リストは、複数の要素を順序を保存して保持する。0個以上の要素をカンマで区切り、[] で囲んで作る。

animals = ['dog', 'cat', 'pig']
numbers = [3, 1, 4, 1, 5]  # 同じ値を複数含んでいても良い
empty_list = []            # 空のリスト
empty_list_2 = list()      # 空のリスト

range() を使うと、連続する数値のリストを作れる。

range(5)        #-> [0, 1, 2, 3, 4] (0以上5未満)
range(1, 5)     #-> [1, 2, 3, 4]    (1以上5未満)
range(0, 5, 2)  #-> [0, 2, 4]       (0以上5未満、ステップ数2)

文字列をリストに変換することもできる。

list('Python')  #-> ['P', 'y', 't', 'h', 'o', 'n']
list('')        #-> []

リストは文字列と同様に、インデックスやスライスで要素を切り出せる。

weekdays = ['Mon.', 'Tue.', 'Wed.', 'Thu.', 'Fri.']
weekdays[0]    #=> 'Mon.'
weekdays[-1]   #=> 'Fri.'
weekdays[0:2]  #=> ['Mon.', 'Tue.']
weekdays[0:1]  #=> ['Mon.']  (文字列ではなく、要素数1のリストとして切り出されていることに注意)
weekdays[::2]  #-> ['Mon.', 'Wed.', 'Fri.']

要素数の取得やリスト同士の連結も文字列と同様である。

seasons = ['spring', 'summer', 'autumn', 'winter']
len(seasons)  #-> 4

[1, 2] + [3, 4, 5]  #-> [1, 2, 3, 4, 5]
[0, 1] * 3          #-> [0, 1, 0, 1, 0, 1]

文字列と異なり、リストは要素の変更ができる。

seasons = ['spring', 'summer', 'autumn', 'winter']
seasons[2] = 'fall'
seasons  #-> ['spring', 'summer', 'fall', 'winter']

append()extend() でリストの末尾への要素の追加が出来る。 append() はデータをそのままリストの要素に追加する一方、 extend() は追加するリストの中身を展開して、リストの要素に追加する。

nums = [1, 2, 3]
nums.append(4)
nums  #-> [1, 2, 3, 4]
nums.extend([5, 6])
nums  #-> [1, 2, 3, 4, 5, 6]

insert() でリストの任意の位置に要素を挿入できる。

chars = ['a', 'b', 'd']
chars.insert(2, 'c')
chars  #-> ['a', 'b', 'c', 'd']

要素の削除には del 文もしくは remove() を用いる。 del 文では削除する要素の「位置」を指定するのに対し、 remove() では削除する要素の「値」を指定する。

fruits = ['apple', 'orange', 'banana']

del fruits[1]
fruits  #-> ['apple', 'banana']

fruits.remove('banana')
fruits  #-> ['apple']

リストが指定の値の要素を持つどうかは、in で調べられる。 リスト内の指定の値の要素の位置を調べるには、index() を使う。

cities = ['Rome', 'Paris', 'Madrid']

'Rome' in cities    #-> True
'London' in cities  #-> False

cities.index('Paris')   #-> 1
cities.index('Berlin')  #-> エラー (ValueError)

最小値、最大値の取得は min() および max() でそれぞれ行える。 また、sorted() はリストの値をソートしたものを返す。

heights = [170.0, 169.5, 173.0, 171.5]

min(heights)  #-> 169.5
max(heights)  #-> 173.0

sorted(heights)  #-> [169.5, 170.0, 171.5, 173.0]
sorted(heights, reverse=True)  #-> [173.0, 171.5, 170.0, 169.5] (逆順にソート)

タプル

タプルは0個以上の要素をカンマで区切り、() で囲んで作る。

Baltic_states = ('Estonia', 'Latvia', 'Lithuania')
members = ('Taro',)  # 要素が1個のタプルは、要素の末尾にカンマを付ける
empty_tuple = ()     # 空のタプル

tuple([1, 2, 3]) #-> (1, 2, 3)  (リストからタプルを作る)

タプルはほとんどリストと同じものであるが、一度作られると変更することが出来ない。

t = (1, 2, 3, 4, 5)
t[0] = 5     #-> エラー (TypeError)
t.append(6)  #-> エラー (AttributeError)
del t[2]     #-> エラー (TypeError)

辞書

辞書は、ある値(キー)からある値への対応を保持する。要素を加えた順序は保存されない。また、2つ以上の値が同じキーを持つことは出来ない。

# リスト
price_list = [480, 680, 980]
price_list[2]  #-> 980

# 辞書
price_dict = {'curry': 480, 'ramen': 680, 'pizza': 980}
price_dict['pizza']  #-> 980

辞書は、キー : 値 の0個以上のペアをカンマで区切って並べ、 {} で囲んで作る。

altitudes = {'Everest': 8848, 'Fuji': 3776, 'McKinley': 6190}  # 文字列がキーの辞書
id2name = {1: 'Daniel', 2: 'George', 3: 'Rebecca'}  # 数値がキーの辞書
empty_dict = {}        # 空の辞書
empty_dict_2 = dict()  # 空の辞書

辞書への要素の追加はキーを指定して行う。要素の変更、削除はリストと同様にできる。

ages = {'Taro': 22, 'Hanako': 18}

# 要素の追加
ages['Pochi'] = 5
ages  #-> {'Hanako': 18, 'Pochi': 5, 'Taro': 22}

# 要素の変更
ages['Hanako'] = 19
ages  #-> {'Hanako': 19, 'Pochi': 5, 'Taro': 22}

# 要素の削除
del ages['Taro']
ages  #-> {'Hanako': 19, 'Pochi': 5}

値の取得には、リストのようにキーを指定する方法と、get() を使う方法がある。 get() を使った場合は、指定したキーが辞書に存在しなかった場合にエラーにはならず、何も返さない。

heights = {'Taro': 173.0, 'Jiro': 168.5}

heights['Taro']             #-> 173.0
heights.get('Taro')         #-> 173.0
heights['Saburo']           # エラー (KeyError)
heights.get('Saburo')       #-> (何も返さない)
heights.get('Saburo', 0.0)  #-> 0.0 (キーがない場合に代わりに返す値を指定)

keys(), values(), items() によって、辞書が持つすべてのキー、値、それらのペアのタプルをそれぞれリストで取得できる。

student_ids = {'Naomi': 'A001', 'Ken': 'A002', 'Show': 'A003'}

student_ids.keys()    #-> ['Naomi', 'Show', 'Ken']
student_ids.values()  #-> ['A001', 'A003', 'A002']
student_ids.items()   #-> [('Naomi', 'A001'), ('Show', 'A003'), ('Ken', 'A002')]

辞書に対しての len()in は、キーに対して働く。

capital_cities = {'Japan': 'Tokyo', 'UK': 'London'}

len(capital_cities)        #-> 2
'Japan' in capital_cities  #-> True
'Tokyo' in capital_cities  #-> False
'Tokyo' in capital_cities.values()  #-> True

集合

集合は、値の重複を認めず、追加された順序を保持しないデータ構造である。 1個以上の要素をカンマで区切って並べ、 {} で囲んで作る。 空の集合を作るには、 set() を使う。

set_1 = {0, 1, 2, 3}
set_2 = {1}
empty_set = set()

numbers = {1, 1, 2, 2, 3}
numbers  #-> {1, 2, 3}

set(['A', 'B', 'B', 'C'])  #-> {'A', 'B', 'C'}

要素数や値の存在の確認は、リストなどと同様である。

medals = {'gold', 'silver', 'bronze'}

len(medals)  #-> 3
'steel' in medals  #-> False

add()update() で集合への要素の追加が出来る。 add() はデータをそのまま集合の要素に追加する一方、 update() は一度に複数の要素を集合の要素に追加する(和集合を求めることに相当)。

prime_numbers = {2, 3, 5}

prime_numbers.add(7)
prime_numbers  #-> {2, 3, 5, 7}

prime_numbers.update([11, 13])
prime_numbers  #-> {2, 3, 5, 7, 11, 13}

要素の削除は、 remove() で行う。

even_numbers = {0, 2, 3, 4, 6, 8}
even_numbers.remove(3)
even_numbers  #-> {0, 2, 4, 6, 8}

集合同士は、数学で習うような演算ができる。

men = {'Takashi', 'Ken', 'Ichiro'}
women = {'Emi', 'Lucy', 'Atsuko'}
students = {'Takashi', 'Ken', 'Emi', 'Lucy'}
teachers = {'Ichiro', 'Atsuko'}
americans = {'Lucy'}

# 積集合
men & students     #-> {'Ken', 'Takashi'}
women & americans  #-> {'Lucy'}

# 和集合
men | students     #-> {'Emi', 'Ichiro', 'Ken', 'Lucy', 'Takashi'}
women | americans  #-> {'Atsuko', 'Emi', 'Lucy'}

# 差集合
men - students     #-> {'Ichiro'}
women - americans  #-> {'Atsuko', 'Emi'}

# 排他的論理和
men ^ students     #-> {'Emi', 'Ichiro', 'Lucy'}
women ^ americans  #-> {'Atsuko', 'Emi'}

# 部分集合かどうか
americans <= women  #-> True
americans <= men    #-> False

基本的な制御構造

Python では、コードのブロックを {} などのカッコではなく、インデント(字下げ)で示す(インデントはふつう、半角スペース4つを単位とする)。

if による条件分岐

Python での条件分岐は、以下のように書く。

if 条件式1:
    条件式 が True の時の処理...
elif 条件式2:
    以前のすべての条件式が False かつ 条件式2True の時の処理...
else:
    以前のすべての条件式が False の時の処理...

elifelse のブロックは、必要がなければ省略できる。また、elif のブロックはいくつあっても良い。

例えば、変数 a の符号に応じて出力メッセージを変えるような処理は、以下のように書ける。

if a > 0:
    print 'a is positive.'
elif a < 0:
    print 'a is negative.'
else:
    print 'a is zero.'

はじめのうちは、以下の点に気をつけよう。

  • 条件式の直後の : を忘れない。
  • else if ではなく elif である。

条件式としては、ブール値のところで述べた、>=== といった比較演算子を用いたものや、 リストのところで説明した in を使ったものが使える。

条件式同士の組み合わせには、以下の論理演算子を使う。

# 論理積
a and b  #-> a と b の両方が True のときにのみ True、それ以外は False

# 論理和
a or b   #-> a または b の少なくともどちらかが True のとき True、それ以外は False

# 否定
not a    #-> a が True のとき False、a が False のとき True

while による繰り返し

Python での while による繰り返しは、C や Java のそれとほぼ同じである。

while 条件式:
    条件式が True のあいだ繰り返す処理

例えば、整数を1から100まで出力するプログラムは、以下のように書ける。

count = 1
while count <= 100:
    print count
    count += 1

ループから途中で抜けるには、break を使う。例えば、上のプログラムを、20を出力した時点でループを抜けるには、 以下のように書く。

count = 1
while count <= 100:
    print count
    if count == 20:
        break
    count += 1

for による繰り返し

Python の for 文の構造は、C や Java の for 文とはかなり異なる。

たとえば、1から10の整数を足し上げるというプログラムは、C ではこのように書いていた。

int i;
int total = 0;
for(i = 1; i <= 10; i++) {
    total = total + i;
}

i = 1 という初期化を施し、i <= 10 であるあいだ {} の内部の処理を繰り返す。 繰り返しの終了ごとに i++ を実行する」という、繰り返しの条件を () 内の3つの式で書いていた。

一方、Python では、同様の処理は次のように書ける。

total = 0
for i in range(1, 11):
    total = total + i

これは、「 range(1, 11) (すなわち 1 から 10 までの整数が入ったリスト)から 繰り返しのたびに1個ずつ値を順番に取っていき、それを変数 i に格納して、ブロック内の処理を行う。 range(1, 11) のすべての要素が使われたら繰り返しを終了する」という意味である。

すなわち、Python の for では、C のように「ブロック内の処理を条件に従って繰り返す」というのではなく「リストなどから値を順番に取ってきて、それを使ってブロック内の処理を行う」という考えに近い。

いくつか例を挙げる。

  • 単語のリストから、その単語の文字数を単語ごとに表示する

    words = ['This', 'is', 'a', 'pencil', '.']
    for word in words:
        print len(word)
    4
    2
    1
    6
    1
    
  • 辞書のキーを取ってきて、処理を行う

    student_ids = {'Naomi': 'A001', 'Ken': 'A002', 'Show': 'A003'}
    for student_name in student_ids:
        print "Hello, I'm {}!".format(student_name)
    Hello, I'm Naomi!
    Hello, I'm Show!
    Hello, I'm Ken!
    
  • 辞書の値を取ってきて、処理を行う

    student_ids = {'Naomi': 'A001', 'Ken': 'A002', 'Show': 'A003'}
    for student_id in student_ids.values():
        print "Hello, my ID is {}!".format(student_id)
    Hello, my ID is A001!
    Hello, my ID is A003!
    Hello, my ID is A002!
    
  • 辞書のキーと値を同時に取ってきて、処理を行う

    student_ids = {'Naomi': 'A001', 'Ken': 'A002', 'Show': 'A003'}
    for student_name, student_id in student_ids.items():
        print "{}'s ID is {}!".format(student_name, student_id)
    Naomi's ID is A001!
    Show's ID is A003!
    Ken's ID is A002!
    

enumerate() を使うと、要素と同時に、それが何番目に取ってきた値なのかを一緒に取得できる。

  • アルファベットで、p が何番目の文字かを調べる

    for index, char in enumerate('abcdefghijklmnopqrstuvwxyz'):
        if char == 'p':
            print index + 1
            break
    16
    

breakwhile 文と同様に使える。

  • 1から1000までの整数のうち、はじめて2乗が1000を超える数を出力する

    for i in range(1, 1001):
        if i**2 > 1000:
            print i
            break
    32
    

continue は、ループを抜けることなく、直ちに次の繰り返しの試行に移る。

  • 整数のリスト内の、0でない数値に対して逆数を求める

    for i in [3, 0, 4, 0, 5]:
        if i == 0:
            continue
        print 1.0 / i
    0.333333333333
    0.25
    0.2
    

ここで挙げたような、リストや辞書、文字列などの、「1つずつ要素を取り出して返すことが出来る」 データ(オブジェクト)を「イテラブル (iterable) オブジェクト」とよぶ。

関数

Python では、関数を以下のように定義できる。

def some_function(arg1, arg2):
    処理...
    return some_value  # 戻り値

arg1 , arg2 としたものは関数の引数であり、任意の数だけ取れる(もちろん0個でも良い)。戻り値も省略可能である。戻り値がある場合も、型を指定する必要はない。

定義した関数は、以下のようにして呼び出す。

# v1, v2 は何らかの値であるとする
some_function(v1, v2)

例として、「文字列を受け取り、それに含まれている英大文字の個数を返す関数」の定義と呼び出し方を示す。

def count_upper(some_str):
    n_upper = 0
    for char in some_str:
        if char.isupper():  # isupper() は、文字列が全て大文字からなる時のみ True を返す
            n_upper += 1
    return n_upper
count_upper('I bought iPhone and iPad at Apple Store.')  #-> 5

関数の定義において、引数にデフォルト値を設定することが出来る。デフォルト値を設定した引数は、 関数を呼び出すときに省略可能である。

def repeat_greetings(greeting, n_repeat=2):
    print greeting * n_repeat
repeat_greetings('Hello', 3)  # HelloHelloHello
repeat_greetings('Hello')     # HelloHello

関数の呼び出し時には、引数をキーワードで指定することも出来る(この場合、定義された順序どおりに引数を並べる必要はない)。

# 以下はどれも、HelloHelloHello を出力する
repeat_greetings('Hello', 3)
repeat_greetings('Hello', n_repeat=3)
repeat_greetings(greeting='Hello', n_repeat=3)
repeat_greetings(n_repeat=3, greeting='Hello')

モジュールの使用

Python の機能のいくつかは、モジュールとして提供されている。それらを使うためには、使う前にインポートする必要がある。

例えば、math モジュールで提供される関数である、対数を計算する関数 log() を 使うには、以下の3つのやり方がある。

  • モジュール全体をインポートする

    import math
    
    math.log(10)    #-> 2.302585092994046
    math.tanh(0.5)  #->0.46211715726000974
    • モジュールが提供するすべての機能が使えるが、関数を呼び出す時などはモジュール名を頭につける必要がある。
  • 必要な機能のみをインポートする

    from math import log  # math モジュールから関数 log のみをインポートする
    
    log(10)    #-> 2.302585092994046
    tanh(0.5)  # NameError (インポートしていないので使えない)
    • モジュール名をつけなくても、インポートした機能を呼び出せる。
  • モジュールのすべての機能をインポートする

    from math import *
    
    log(10)    #-> 2.302585092994046
    e  #-> 2.718281828459045  (名前が衝突しやすい)
    • モジュールが提供するすべての機能をモジュール名をつけることなしに使えるが、名前が衝突しやすくなるので推奨されない。例えばこの例では、自分で e という変数を別に定義していると、math モジュールの e との区別ができなくなってしまう。

便利なあれこれ

内包表記

ある条件に基づいたリストを作るとき、内包表記を用いると、シンプルに書けることがある。

例えば、単語が複数入ったリスト words から、それぞれの単語の文字数を格納したリスト lens を作りたいとする。

words = ['Boys', 'be', 'ambitious']
# 上の words から 以下のような lens をつくりたい
lens = [4, 2, 9]

内包表記を使わない場合は、 以下のように書くことになるだろう。

lens = []
for word in words:
    lens.append(len(word))

内包表記を用いると、これが1行で書ける。

lens = [len(word) for word in words]

これは、「words から 要素を1つずつ word として取ってきて、len(word) を 要素として設定していく」という意味である。

内包表記は初めは慣れが必要だが、上のようなかんたんな条件に基づくリストであれば、内包表記のほうがシンプルに書ける場合が多い。

組み込み関数とラムダ式

リストのすべての要素に関数を一括適用したり、関数の適用結果で要素をフィルタリングできる組み込み関数 map()filter() を紹介する。

def double(x):
    return x**2

def is_positive(x):
    return x > 0

l = [3, -1, 4, 1, -5]

map(double, l)          #-> [9, 1, 16, 1, 25] (各要素に関数を適用して返す)
filter(is_positive, l)  #-> [3, 4, 1] (各要素に関数を適用し、Trueを返す値のみからなるリストを返す)

sorted(l, key=double)   #-> [-1, 1, 3, 4, -5] (各要素に関数を適用した結果に従ってソート)

これらは、ラムダ式を使うとよりシンプルに書ける。ラムダ式では、関数の入力と、それに対する出力の形を直接記述する。

map(lambda x:x**2, l)         #-> [9, 1, 16, 1, 25]
filter(lambda x:x>0, l)       #-> [3, 4, 1]
sorted(l, key=lambda x:x**2)  #-> [-1, 1, 3, 4, -5]

ラムダ式によって、 double()is_positive() といった関数をわざわざ def で定義しなくても済むようになる。

参考資料

公式ドキュメント 英語 日本語

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment