基礎の振り返り
Pythonチュートリアルにて基礎の復習。
数値
整数はint型、小数点を伴う数はfloat型
>>> 2 + 2
4
>>> 50 - 5 * 6
20
>>> 8 / 5 #常に浮動小数点数を返す
1.6
>>> 17 // 3 #切り下げ除算は小数点以下を捨てる
5
>>> 17 % 3 #剰余を返す
2
>>> 5 ** 2 #5の自乗
25
>>> 2 ** 7 #2の7乗
128
# = で代入
>>> width = 20
>>> height = 5 * 9
>>> width * height
900
# 演算対象の方が混在していた場合、整数は浮動小数点数に変換される
>>> 4 * 3.75 - 1
14.0
文字列
引用符はシングルクォートorダブルクォートを使用できる。
バックスラッシュでクォート文字のエスケープができる。
>>> 'spam eggs' # シングルクォート
'spam eggs'
# シングルクォートは\でエスケープするかダブルクォートを使う
>>> 'doesn\'t'
"doesn't"
>>> "doesn't"
"doesn't"
# print()関数は全体を囲む引用符を除去し、エスケープ文字や特殊文字をプリントする
>>> s = 'FIrst line. \nSecond line.' # \nは改行の意味
>>> s # print()を使用しないと\nが出力される
'First line. /nSecond line.'
>>> print(s) # print()を使用すると。改行される
First line.
Second line.
# \ を全治した文字が特殊文字として解釈されたくないときはraw文字列(r)を使う
>>> print('C:\some\name') # \nは改行される
C:some
ame
>>> print(r'C:\some\name') # rを置く
C:\some\name
# 文字列リテラルを複数行書く
>>> print("""
aaa
bbb
ccc
""")
aaa
bbb
ccc
# + で連結、* で繰り返す
>>> 3 * 'un' + 'ium'
'unununium'
# 列挙された文字列リテラルは自動的に連結される(文字列リテラル同士のみ)
>>> 'Py' 'thon'
'Python'
# 変数とリテラルの連結、変数同士の連結は + を使う
>>>prefix = 'Py'
>>>prfix + 'thon'
'Python'
インデックスとスライス
インデックス指定→連番指定
スライス操作→切り取り
>>> word = 'Python'
>>> word[0] # 位置0
'P'
>>> word[5] # 位置5
'n'
# 負の数も使える
>>> word[-1] # 最後
'n'
>>> word[-6] # 最後から6番目
'P'
>>> word[0:2] # 位置0から(0を含み)2まで(2を含まない)の文字
'Py'
>>> word[2:5] # 位置2から(2を含み)5まで(5を含まない)の文字
'tho'
# スライスインデックスはデフォルト値がある(省略時)
# 第一引数は0、第二引数は文字列サイズがデフォルトとなっている
>>> word[:2]
'Py'
>>> word[4:]
'on'
>>> word[:]
'Python'
#文字列は改変できない
>>> word[0] = 'J'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
# 異なる文字が必要な時は新し文字列を作成する必要がある
>>> 'J' + rotd[1:]
'Jython'
# len()は文字列の長さを返す
>>> s = 'Python'
>>> len(s)
6
リスト
複合したデータのための型でほかの種類の値をまとめるのに使える。
[]の中にカンマ区切りの値を入れていくだけで書ける。異なる型を入れることも可能だが通常は同じ型を入れる。
>>> squares = [1, 4, 9, 16, 25]
>>> squqres
[1, 4, 9, 16, 25]
# 文字列同様インデックスやスライスが使用できる
>>> squares[0]
1
>>> squares[-1]
25
#スライス操作は常にシャローコピーを新しく作って返す(オブジェクトの複製を伴わない、ポインタのコピーのこと。)
>>> squares[:]
[1, 4, 9, 16, 25]
# リストは連結などの操作もできる
>>> squares + [36, 49, 64, 81, 100]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# リストは内容を変更することができる
>>> cubes = [1, 8, 27, 65, 125]
>>> cubes[3] = 64
>>> cubes
[1, 8, 27, 64, 125]
# リストの末尾にアイテムを追加する
>>> cubes.append(216)
>>> cubes.append(7 ** 3)
>>> cubes
[1, 8, 27, 64, 125, 216, 343]
# スライスへの代入も可能、リストの長さを変えたり、リストの内容すべてをクリアもできる
>>> letters = ['a' ,'b', 'c', 'd', 'e', 'f', 'g']
>>> letters
['a' ,'b', 'c', 'd', 'e', 'f', 'g']
# いくつかの値を置換
>>> letters[2:5] = ['C', 'D', 'E']
>>> letters
['a' ,'b', 'C', 'D', 'E', 'f', 'g']
# これらを削除
>>> letters[2:5] = []
>>> letters
['a', 'b', 'f', 'g']
# リストを空白のリストで置換
>>> letters[:] = []
>>> letters
[]
# len()も使える
>>> letters = ['a', 'b', 'c', 'd']
>>> len(letters)
4
# リストは入れ子にもできる
>>> a = ['a', 'b', 'c']
>>> n = [1, 2, 3]
>>> x = [a, n]
>>> x
[['a', 'b', 'c'],[1, 2, 3]]
>>> x[0]
['a', 'b', 'c']
>>> x[0][1]
'b'
フィボナッチ級数を求めるプログラム
フィボナッチ級数は2項の和により次項が定まる
>>> a, b = 0, 1
>>> while a < 10:
print(a)
a,b = b, a + b
0
1
1
2
3
5
8
多重代入aとbに0と1をそれぞれ代入した。
最後の行でも多重代入を行っている。代入が行われる前にまず右辺側にある式が評価される
whileループは条件が真である限り実行を繰り返す。今回は10以下である限り実行
ループのボディにはインデントがかかっている。Pythonではグルーピングにインデントを使う。
print()関数は与えられた引数の値(複数可)を表示する。
キーワード引数endを使えば出力末尾の改行の抑制や出力末尾をほかの文字列に変更することができる。
>>> a, b = 0, 1
>>> while a < 1000:
print(a, end=',')
a, b = b, a + b
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 619, 987,
if文
ゼロ個以上の elif 部を使うことができ、 else 部を付けることもできます。キーワード 'elif' は 'else if' を短くしたもので、過剰なインデントを避けるのに役立つ。一連の if ... elif ... elif ... は、他の言語における switch 文や case 文の代用になる。
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
x = 0
print('Negative changed to zero')
elif x == 0:
print('Zero')
elif x == 1:
print('Single')
else:
print('More')
for文
Python の for 文は、任意のシーケンス型 (リストまたは文字列) にわたって反復を行いう。反復の順番はシーケンス中に要素が現れる順番。
>>> # Measure some strings:
words = ['cat', 'window', 'defenestrate']
>>> for w in words:
print(w, len(w))
cat 3
window 6
defenestrate 12
反復対象のコレクションのコピーに反復をかけたり、新しくコレクションを作り直す
# コレクションの作成
users = {'Hans': 'active', 'Éléonore': 'inactive', '景太郎': 'active'}
# コピーに反復をかける
for user, status in users.copy().items():
if status == 'inactive':
del users[user]
# Strategy: 新しいコレクションを作る
active_users = {}
for user, status in users.items():
if status == 'active':
active_users[user] = status
range()関数
数字の連なりに反復をかけるときはビルドイン関数のrange()を使用。
等差級数を生成する。
>>> for i in range(5):
print(i)
0
1
2
3
4
与えられた終端地は入らない。range(10)が生成する10個は長さ10のシーケンスの各アイテムのインデックスとなる。0以外から始めることや、増分の指定(負数も使用できる)が可能。
>>> range(5, 10)
5, 6, 7, 8, 9
>>> range(0, 10, 3)
0, 3, 6, 9
>>> range(-10, -100, -30)
-10, -40, -70
シーケンスのインデックスで反復をかけたい場合
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a))
print(i, a[i])
0 Mary
1 had
2 a
3 little
4 lamb
break 文と continue 文とループの else 節
ループ文にはelse節を加えられる。else節は反復可能艇を使い果たしたり(for)、条件式がfalseになること(while)によって、ループが終了した場合に実行され、break文で終了した場合は実行されない。
>>> for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, 'equals', x, '*', n//x)
break
else:
# ループで約数を見つけられなかった場合
print(n, 'is a prime number')
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
elseがif文ではなくforループでグルーピングされているところに着眼する。
else節はbreakが起きなかった場合に実行される。
continue文はループの残りを飛ばして次回の反復にいく
>>> for num in range(2, 10):
if num % 2 == 0:
print("Found an even number", num)
continue
print("Found an odd number", num)
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9
pass文
pass文はなにもしない。構文が必要なのに、プログラム的には何もする必要がないときに使う。
>>> while True:
pass #キー割り込みでCtrl+Cを待つ
最小のクラスを生成するのにもつかわれる。
>>> class MyEmptyClass:
pass
関数の定義
フィボナッチ数列 (Fibonacci series) を任意の上限値まで書き出すような関数を作成する
>>> def fib(n): # フィボナッチ級数をnまで書き出す
"""nまでのフィボナッチ級数を表示する"""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
>>> # 関数の呼び出し
fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
引数のデフォルト値
引数にデフォルト値を設定することができる
def ask_ok(prompt, retries=4, reminder='Please try again!'):
while True:
ok = 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 ValueError('invalid user response')
print(reminder)
この関数はいくつかの方法で呼び出せます:
必須の引数のみ与える: ask_ok('Do you really want to quit?')
一つのオプション引数を与える: ask_ok('OK to overwrite the file?', 2)
全ての引数を与える: ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
この例では in キーワードが導入されています。このキーワードはシーケンスが特定の値を含んでいるかどうか調べるのに使われます。
デフォルト値は、関数が定義された時点で、関数を 定義している 側のスコープ (scope) で評価されるので
i = 5
def f(arg=i):
print(arg)
i = 6
f()
は5を出力する。デフォルト値の評価は一度しか起きない
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
以下を出力
[1]
[1, 2]
[1, 2, 3]
後続の関数呼び出しでデフォルト値を共有したくなければ、代わりに以下のように関数を書くことができます
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
キーワード引数
関数を kwarg=value という形式の キーワード引数 を使って呼び出すこともできます
def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.")
print("-- Lovely plumage, the", type)
print("-- It's", state, "!")
は、必須引数 (voltage) とオプション引数 (state、action、type) を受け付けます。この関数は以下のいずれかの方法で呼び出せます:
parrot(1000) # 1 positional argument
parrot(voltage=1000) # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump') # 3 positional arguments
parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
特殊なパラメータ
デフォルトでは、引数は位置またはキーワードによる明示で Python 関数に渡されます。 可読性とパフォーマンスのために、その引数が位置、位置またはキーワード、キーワードのどれで渡されるかを開発者が判定するのに関数定義だけを見ればよいように、引数の渡され方を制限することには意味があります。
関数定義は次のようになります:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
ここで、/ と * はオプションです。使用された場合、これらの記号は、引数が関数に渡される方法、すなわち、位置専用、位置またはキーワード、キーワード専用、といった引数の種類を示します。キーワード引数は、名前付き引数とも呼ばれます。
位置またはキーワード引数
関数定義に / も * もない場合は、引数は位置またはキーワードで関数に渡されます。
位置専用引数
これをもう少し詳しく見てみると、特定の引数を 位置専用 と印を付けられます。 位置専用 の場合、引数の順序が重要であり、キーワードで引数を渡せません。 位置専用引数は / (スラッシュ)の前に配置されます。 / は、位置専用引数を残りの引数から論理的に分離するために使用されます。 関数定義に / がない場合、位置専用引数はありません。
/ の後の引数は、 位置またはキーワード 、もしくは、 キーワード専用 です。
キーワード専用引数
引数をキーワード引数で渡す必要があることを示す キーワード専用 として引数をマークするには、引数リストの最初の キーワード専用 引数の直前に * を配置します。
任意引数リスト
最後に、最も使うことの少ない選択肢として、関数が任意の個数の引数で呼び出せるよう指定する方法があります。これらの引数はタプル (タプルとシーケンス を参照) に格納されます。可変個の引数の前に、ゼロ個かそれ以上の引数があっても構いません。
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))
引数リストのアンパック
引数がすでにリストやタプルになっていて、個別な位置引数を要求する関数呼び出しに渡すためにアンパックする必要がある場合には、逆の状況が起こります。例えば、組み込み関数 range() は引数 start と stop を別に与える必要があります。個別に引数を与えることができない場合、関数呼び出しを * 演算子を使って書き、リストやタプルから引数をアンパックします:
>>>
>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]
同じやりかたで、** オペレータを使って辞書でもキーワード引数を渡すことができます
>>>
>>> def parrot(voltage, state='a stiff', action='voom'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.", end=' ')
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 !
ラムダ式
キーワード lambda を使うと、名前のない小さな関数を生成できます。例えば lambda a, b: a+b は、二つの引数の和を返す関数です。ラムダ式の関数は、関数オブジェクトが要求されている場所にならどこでも使うことができます。ラムダ式は、構文上単一の式に制限されています。意味付け的には、ラムダ形式は単に通常の関数定義に構文的な糖衣をかぶせたものに過ぎません。入れ子構造になった関数定義と同様、ラムダ式もそれを取り囲むスコープから変数を参照することができます
>>> def make_incrementor(n):
return lambda x: x + n
>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)
43
上記の例は、関数を返すところでラムダ式を使っています。もう1つの例では、ちょっとした関数を引数として渡すのに使っています:
>>>
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
ドキュメンテーション文字列
ドキュメンテーション文字列については、その内容と書式に関する慣習をいくつか挙げます。
最初の行は、常に対象物の目的を短く簡潔にまとめたものでなくてはなりません。簡潔に書くために、対象物の名前や型を明示する必要はありません。名前や型は他の方法でも得られるからです (名前がたまたま関数の演算内容を記述する動詞である場合は例外です)。最初の行は大文字で始まり、ピリオドで終わっていなければなりません。
ドキュメンテーション文字列中にさらに記述すべき行がある場合、二行目は空行にし、まとめの行と残りの記述部分を視覚的に分離します。つづく行は一つまたはそれ以上の段落で、対象物の呼び出し規約や副作用について記述します。
Python のパーザは複数行にわたる Python 文字列リテラルからインデントを剥ぎ取らないので、ドキュメントを処理するツールでは必要に応じてインデントを剥ぎ取らなければなりません。この処理は以下の規約に従って行います。最初の行の 後にある 空行でない最初の行が、ドキュメント全体のインデントの量を決めます。(最初の行は通常、文字列を開始するクオートに隣り合っているので、インデントが文字列リテラル中に現れないためです。) このインデント量と "等価な" 空白が、文字列のすべての行頭から剥ぎ取られます。インデントの量が少ない行を書いてはならないのですが、もしそういう行があると、先頭の空白すべてが剥ぎ取られます。インデントの空白の大きさが等しいかどうかは、タブ文字を (通常は 8 文字のスペースとして) 展開した後に調べられます。
>>> def my_function():
"""Do nothing, but document it.
No, really, it doesn't do anything.
"""
pass
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
関数のアノテーション
関数アノテーション はユーザ定義関数で使用される型についての完全にオプションなメタデータ情報です
アノテーション は関数の annotations 属性に辞書として格納され、関数の他の部分には何も影響を与えません。パラメータアノテーションは、パラメータ名の後にコロンを続けることによって定義され、その後にアノテーションの値として評価される式が置かれます。戻り値アノテーションは、パラメータリストと def 文の終わりを表すコロンの間に置かれたリテラル -> によって定義され、その後に式が続きます。次の例は必須の引数とオプション引数、そして戻り値のアノテーションを持っています
>>>
>>> def f(ham: str, eggs: str = 'eggs') -> str:
print("Annotations:", f.__annotations__)
print("Arguments:", ham, eggs)
return ham + ' and ' + eggs
>>> f('spam')
Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>}
Arguments: spam eggs
'spam and eggs'
コーディングスタイル
インデントには空白 4 つを使い、タブは使わないこと。
空白 4 つは (深くネストできる) 小さいインデントと (読み易い) 大きいインデントのちょうど中間に当たります。タブは混乱させるので、使わずにおくのが良いです。
ソースコードの幅が 79 文字を越えないように行を折り返すこと。
こうすることで小さいディスプレイを使っているユーザも読み易くなり、大きなディスプレイではソースコードファイルを並べることもできるようになります。
関数やクラスや関数内の大きめのコードブロックの区切りに空行を使うこと。
可能なら、コメントは行に独立で書くこと。
docstring を使うこと。
演算子の前後とコンマの後には空白を入れ、括弧類のすぐ内側には空白を入れないこと: a = f(1, 2) + g(3, 4)。
クラスや関数に一貫性のある名前を付けること。慣習では UpperCamelCase をクラス名に使い、 lowercase_with_underscores を関数名やメソッド名に使います。常に self をメソッドの第 1 引数の名前 (クラスやメソッドについては クラス初見 を見よ) として使うこと。
あなたのコードを世界中で使ってもらうつもりなら、風変りなエンコーディングは使わないこと。どんな場合でも、Python のデフォルト UTF-8 またはプレーン ASCII が最も上手くいきます。
同様に、ほんの少しでも他の言語を話す人がコードを読んだりメンテナンスする可能性があるのであれば、非 ASCII 文字も識別子に使うべきではありません。
まとめ
Pythonチュートリアルの3章4章の内容でした。