Python入門(4.データ構造)です。
Python[完全]入門を参考に執筆しました。
Pythonは動的だからといって、型を意識する必要が全くないわけではない。
たとえば、文字列の中身を数値に変換して計算したり、入力したメッセージを数値に戻して演算し、その後に文字列と結合して出力したいような場合、必ず型変換が必要となる。
input_value = input('二乗にしたい数を入力してね: ') int_value = int(input_value) result = int_value ** 2 output_msg = input_value + 'の二乗は' + str(result) + 'だよ' print(output_msg)
後日注記:型変換を行う関数には、int(), float(), str()などがある。たとえば文字列を数値型や浮動小数点型に変換できる(逆も可能)。Pythonには他にも複素数型などがある。また、type()関数でその変数が何の型であるかを知ることができる。+のような演算子を使う場合、数値型の変数と文字列型の変数を加えるとエラーになる。必ず文字列型か数値型に変換すること。
型も参照のこと。
最近のPythonでは、特に汎用的にモジュールなどを作って人に使ってほしい時などに、型アノテーションをつけることができるようになった。これをタイプヒントと言う。
以下のように関数の引数や戻り値に型を明記できる。
def add(x: int, y: int) -> int: return (x + y)
ジェネリクスやUnion型(いくつかの型を同時に許容するようにすること)も記述できる。
しかしながら、Pythonではこうした型アノテーションをつけていても、実行時にはチェックされない。ただし、mypyというツールを使うことでチェックを行うことができる。
後日注記:タイプヒントは、型だけではなく、特定のリテラル値だけを許容するようにすることもできる。たとえば'犬'と'猫'は許容するが'豚'や'鳥'あるいはそのほかの値は許容しないなどとできる。タプルとともに使うと効果を発揮するだろう。
from typing import Literal Sex = Literal['male', 'female'] User = tuple[str, int, Sex, str] assy: User = ('Assy', 32, 'male', 'Japan')
リストとタプルは良く似ていて、どちらもC言語でいう配列のように使うことができる。さまざまなオブジェクトを混ぜて入れることが出来るのが特徴。
リストとタプルの違いは、記法が違い、タプルはイミュータブル(変更できない)という特性を持つ。
リストは[]を用いて記述するが、タプルは()を用いて(あるいはかっこをつけずに,だけで)記述する。
ls = ['hoge', 'fuga', 'foo', 'bar'] #リストの場合 tp = ('Assy', 32, 'male', 'Japan') #タプルの場合
値が変更できる変数のことを「ミュータブル」、変更できない変数のことを「イミュータブル」という。イミュータブルな変数束縛でも、値の参照自体は変えることが出来る。Rustや関数型言語などでも出てくる考え方なので注意しておこう。
後日注記:たとえばPythonでは文字列の一部を変更することはできない。
後日注記:タプルであっても、値の再代入はできる。たとえば以下のコードはイミュータブルなタプルであっても動作する。このような場合には、別々の新しいタプルが作成されている。
tp = ('Assy', 32, 'male', 'Japan') tp = ('Schwarz', 18, 'male', 'Japan')
配列とリストとハッシュも参照のこと。
リストは添え字を用いてlst[0]のようにアクセスできる。
lst = [10, 5, 0] lst[2] = lst[0] + lst[1]
一部をスライスとしてlst[1:4]のように取り出すこともできる。スライスは、添え字を範囲とする連続した要素による新しいリストを作成する。
lst = [0, 10, 5] lst2 = lst[1:3]
スライスは、リスト名[開始地点:終了地点]となる。省略した場合は最初・最後の地点となる。また終了地点は取り出されないので、ひとつ余分にインデックスを指定する必要がある。
リストは、単に代入するだけではコピーできない。別の変数に=を用いて代入した場合、同じリストを指す別名の変数となる。コピーしたい場合は
lst2 = lst.copy()
とする。あるいは、
lst2 = lst[:]
のようにスライスを使ってコピーすることもできる。
ストライドを使えば、ステップごとに間隔を空けてスライスを作ることもできる。
たとえば、文字列はリストと同様添え字を用いてアクセスできるため、以下のようにステップ数2のストライドでスライスを作ることができる。
lst = ':A:S:S:Y:' lst2 = lst[1::2]
ただし、文字列はイミュータブル(変更不可能)ということに注意。文字列を+=などで変更すると、新しいオブジェクトが作成されるため、何度も繰り返すと実行速度が極めて遅くなる。
詳しくは以下の書籍が参考になる。
リストへの追加は
lst = [1, 2, 3] lst.append(4)
あるいは
lst = [1, 2, 3] lst.extend([4, 5, 6])
となる。extend()に渡すのはリストのほかイテラブルなオブジェクト(文字列、リスト、辞書など)となる。
累算代入文(+=)でリストを追加したり、スライスを用いて追加することもできる。
削除は
del lst[0]
とする。
lst.remove(3)
とすれば、位置ではなく要素から要素を削除できる。
特定位置への挿入は
lst.insert(1, 1.5)
とする。
また
str = 'Assy:Schwarz:Zaidou' lst = str.split(':')
とすれば文字列を区切り文字で分割してリストにできる。逆にリストを文字列にしたい場合は
lst = ['Assy', 'Schwarz', 'Zaidou'] str = ':'.join(lst)
を使う。
len(lst)
でリストの要素数を取得できる。
またindex()メソッドにより、要素の位置(インデックス)を取得できる。もし複数含まれていれば最初の要素のインデックスを返す。
lst = ['Assy', 'Schwarz', 'Zaidou'] i = lst.index('Schwarz')
index()メソッドでは、開始地点や終了地点といった検索範囲を指定することもできる。
後日注記:list(), tuple(), set(), dict()の各関数を使うことで、それぞれのデータ構造を作成することもできる。またslice()関数でスライスを保持するsliceオブジェクト(開始値、終了値、ステップを指定できる)を作成できる。
詳しくは以下の書籍が参考になる。
リストではこのほか、pop()メソッドでスタックのポップの操作ができる。この場合append()メソッドがプッシュに相当する。
また、clear()メソッドで配列の全要素をクリアできる。
またsort()メソッドでソート、reverse()メソッドで逆順に並べ替えができる。
count()メソッドで、リストの中にどれだけ同じ値の要素が含まれているかを数えられる。
また、リストに対してmin()関数を使えば、最小の値が得られる。max()関数は最大の値を得られる。
詳しくは以下のページ・書籍が参考になる。
Pythonでは、リストをスタックとして利用できます。リストに対してappend()やpop()を使うことで、リストに要素を追加・取り出しできます。
リストをキューとして使う場合は、注意が必要です。リストをキューとして使うことはできますが、要素をひとつひとつずらす必要があるため、効率的な操作ができません。
そのため、Pythonでキューを使う場合は、両端に対して操作が効率的なcollections.dequeを使うことが推奨されています。
スタックとキューも参照のこと。
タプルは、変更されない代わり、高速かつ効率的にデータを操作できます。
たとえば、データベースのレコードのように、決められた規則に従った「データの組としてのデータ」があった時に、タプルを使うことで高速に操作できます。
ただし、データを単にひとつの箱に詰め込んで操作する場合は、リストを用います。
Pythonでは、キーと値から成るハッシュテーブルのことを辞書と呼ぶ。
animals = {'dog': '犬', 'cat': '猫'} print('dogは' + animals['dog'] + 'で、catは' + animals['cat'] + 'ですよ。')
以下のようにすれば、辞書をデータベース代わりに使うこともできる。
user = {'name': 'Assy', 'age': 32, 'sex': 'male', 'location': 'Japan'} print(user['name'] + "さんは" + user['age'] + "歳です。")
後日注記:リストはlist型、辞書はdict型となる。また、リストの中に辞書を入れたり、辞書の中にリストを入れることもできる。異なる型の要素をミックスして複数入れることもできる。
値が含まれているかどうかの判定には集合を使う。集合は、波括弧で作成する。
st = {1, 3, 4, 7}
値が存在しない場合はset()と書く。
値が含まれているかどうかは、inとnot inで判別できる。
3 in st 5 not in st
ほかにも集合に特有のさまざまな演算がある。たとえば、|、&、-、^、|=、&=、-=、^=などがある。
詳しくは以下の書籍が参考になる。
Pythonでリストを作る際に、ある式の結果の一覧となるようなリストを作りたい場合、内包表記を使うと便利。
たとえば、内包表記を使わずに、0から始まる2の倍数を10個(18まで)作りたい場合、以下のように書くことがあるかもしれない。
bi = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
これを、内包表記を使って書くと以下のように書ける。
bi = [x * 2 for x in range(10)]
if文を使ったテクニックを使うと、以下のようにも書ける。
bi = [x for x in range(20) if x % 2 == 0]
ただし、このように倍数を一覧にしたい場合は、range()に開始値、終了値、ステップ値(間隔)を指定することでも実現できる。これで作られるリストの最終値には、終了値と一致する値(以下の例では20)は含まれないことに注意。
bi = list(range(0, 20, 2))
range()関数はrange型のオブジェクトを返すため、list()でlist型に変換していることに注意。