#!/usr/bin/env python # coding: utf-8 # # Table of Contents #
# # ネイティブデータ型 # ## 飛ぶこむ # Pythonではすべての値がデータ型を持っているにもかかわらず、 # 変数のデータ型を宣言する必要はない。 # # これはどういう仕組みで動いているんだろう? # Python は、それぞれの変数について、 # もともとの代入がなされたときに何の型であるかを把握し、 # それを内部的に追跡している。 # Pythonは数多くのネイティブデータ型を持っている。 # 重要なものは以下。 # # - 「ブール値」 は、TrueまたはFalseのどちらかを表す。 # - 「数値」 は、整数(1や2)を表したり、浮動小数点数(1.1や1.2)を表したり、分数(1/2や2/3)を表したりできる。複素数さえも表せる。 # - 「文字列」 はUnicode文字のシーケンスだ。例: htmlドキュメント。 # - 「バイト列とバイト配列」。例: jpeg画像。 # - 「リスト」 は、値のシーケンスだ。要素は順序づけされる。 # - 「タプル」 は、値のイミュータブルなシーケンスだ。要素は順序づけされる。 # - 「集合」 は、値を詰めた袋だ。要素は順序づけされない。 # - 「辞書」 は、キーと値のペアを詰めた袋だ。要素は順序づけされない。 # Pythonではあらゆるものがオブジェクトなので、モジュール・関数・クラス・メソッド・ファイル、そしてコンパイルされたコードといった型すら存在する。 # # 「モジュール」は、名前を持つ( `.__name__` )、 # 関数は `.docstrings()` を持つ、 # # ## ブール値 # ブール値は真または偽のどちらかを表す。 # Pythonは、True, Falseと分かりやすく命名された2つの定数を持っており、これらはブール値を直接代入するために使える。 # # 式を評価した結果もブール値になりうる。 # 特定の箇所(たとえばif文)では、式を評価した結果がブール値になることが要求される場合もある。 # このような箇所は、 **ブール値のコンテクスト** と呼ばれる。 # そこでは事実上どんな式でも使うことができ、 # Python は、その式の真偽値を決定しようと試みる。 # 例として、 # 変数`size` は整数で、`0`も整数、 # そして`<` は数値演算子だ。 # 式`size < 0`の結果は常にブール値になる。 # In[1]: size = 1 size < 0 # In[2]: size = 0 size < 0 # In[3]: size = -1 size < 0 # Python 2から残されたいくつかの古い問題のために、ブール値を数値として扱うこともできる。 # # - Trueは1 # - Falseは0。 # In[4]: True + True # In[5]: True - False # In[6]: True * False # In[7]: True / False # ## 数値 # Pythonは、整数と浮動小数点数の両方をサポートしている。この2つを区別するための型宣言は存在せず、Pythonは小数点が存在するかしないかで両者を区別する。 # # 値や変数の型を調べるには`type()関数` が使える # In[8]: type(1) # 値や変数の型が特定の型かどうかを調べるには、 # `isinstane()関数` が使える。 # In[9]: isinstance(1, int) # In[10]: 1 + 1 # intをfloatに加えるとfloat になる。 # Pythonはintをfloatに型強制 (coercion) してから加算を行い、 # その結果としてfloatを返す。 # In[11]: 1 + 1.0 # In[12]: type(2.0) # ### 整数から浮動小数点数への型強制とその逆 # いくつかの演算子(加算など)は必要に応じて整数を浮動小数点数に型強制する。自分でこの型強制を行うことも可能。 # `float()関数` を呼び出すことで、明示的にintをfloat へ型強制できる。 # In[13]: float(2) # `int()関数` を呼び出すことで、明示的にfloatをintに型強制できる。 # In[14]: int(2.0) # `int()関数` は、切り捨てを行う。 # In[15]: int(2.5) # int()関数は、負数を0の方向へ向けて切り捨てる。 # これは正しい切り捨て関数で、床関数 (floor function) ではない。 # In[16]: int(-2.5) # 浮動小数点数は小数第15位まで正確。 # In[17]: 1.12345678901234567890 # In[18]: type(1000000000000000) # - Python 2はintとlongを区別していた。intデータ型が表現できる数はsys.maxintに制限されていて、この値はプラットフォームごとに異なるが通常は232-1だった。 # - Python 3はただ一つの整数型を持っており、これはPython2のlong型とほぼ同様に振る舞う。 # 詳細は[pep 237](http://www.python.org/dev/peps/pep-0237) # python3 では`sys.maxint` は`maxsize`に置き換えられている。 # In[19]: import sys sys.maxsize # ### 一般的な数値演算 # In[20]: 11 / 2 # 結果が正の数の場合は、整数への切り捨て(四捨五入ではない)とみなすことができるが、これについては注意が必要。 # In[21]: 11 // 2 # 負の数を整数除算する場合、//演算子は最も近い整数に繰り「上げる」。数学的に言えば、−6は−5より小さいので「繰り下げ」というべきだが、−5に切り捨てられることを期待していると足もとをすくわれる。 # In[22]: -11 // 2 # //演算子は常に整数を返すわけではない。 # 分子や分母のどちらか一方でもfloatの場合は、 # なお結果を最も近い整数に丸めてくれるのだが、 # 実際の戻り値はfloat で返される。 # In[23]: 11.0 // 2 # \*\*演算子は「べき乗」を意味する。 # つまり$11^2 = 121$。 # In[24]: 11 ** 2 # %演算子は整数除算の余りを返す。 # 11を2で割ると5余り1になるので、ここでの結果は1となる。 # In[25]: 11 % 2 # Python 3では、 # `/演算子` は常に浮動小数点数の除算を行う。 # 詳細は[pep 238](http://www.python.org/dev/peps/pep-0238/)。 # ### 分数 # 分数も扱える。 # 分数を使うために、fractionsモジュールをインポート。 # In[26]: import fractions fractions # 分数を定義するには、Fractionオブジェクトを作って分子と分母を渡す。 # In[27]: x = fractions.Fraction(1, 3) x # 分数をつかった普通の数学的演算ならなんでもできる。 # 演算結果は新しいFractionオブジェクトとして返される。 # # $$ # 2 * \frac{1}{3} = \frac{2}{3} # $$ # In[28]: x * 2 # Fractionオブジェクトは自動的に約分される。 # # $$ # \frac{6}{4} = \frac{3}{2} # $$ # In[29]: fractions.Fraction(6, 4) # Pythonは、分母がゼロの分数が作成されないようにうまくやってくれる。 # zero除算エラーが出る。 # In[30]: fractions.Fraction(0, 0) # ### 三角法 # Pythonでは基本的な三角法も行える。 # `math` は、円周率$\pi$ のために定数を用意している。 # In[31]: import math math # In[32]: math.pi # `math` には基本的な三角関数が全部入っている。 # 例えば$\sin()$, $\cos()$, $\tan()$ といったものや、 # $\arcsin()$ のような派生形も入っている。 # In[33]: math.sin(math.pi / 2) # Pythonは無限の精度を持たないことに注意。 # $\tan(\frac{\pi}{4})$ は、 # 1.0を返すべきなのに、0.99999999999999989が返ってきてしまう。 # In[34]: math.tan(math.pi / 4) # ### bool値のコンテキストでの数値 # 数値はif文のようなブール値のコンテクストで使うことができる。 # # - ゼロは偽であり、 # - ゼロではない数値は真。 # # In[35]: def is_it_true(anything): if anything: print("yes, it's true") else: print("no, it's false") # In[36]: is_it_true(1) # In[37]: is_it_true(-1) # In[38]: is_it_true(0) # ゼロでない浮動小数点数は真であり、0.0は偽。 # これには注意しなければならない。 # わずかな丸め誤差が発生した場合(前の節で見たように、これは起こりうる)、Pythonは0ではなく0.0000000000001を評価することになり、 # その結果Trueが返されてしまう。 # In[39]: is_it_true(0.1) # In[40]: is_it_true(0.0) # 分数もブール値のコンテクストで使うことができる。 # `Fraction(0, n)` はすべての n について偽になる。 # それ以外の分数は真。 # In[41]: is_it_true(fractions.Fraction(1, 2)) # In[42]: is_it_true(fractions.Fraction(0, 1)) # ## リスト # PythonのリストはJavaの配列を遙かに超えたもの。 # ArrayListクラスに似ている。 # これは任意のオブジェクトを格納できるし、 # 新しい要素を追加するとサイズが動的に拡張される。 # ### リストを作る # カンマで区切って並べた値を、角括弧で包む。 # 要素が元の順番を保持していることに注意。 # リストは順序づけられた要素の集合。 # In[43]: a_list = ['a', 'b', 'mpilgrim', 'z', 'example'] a_list # リストはインデックスが0から始まる配列のように扱うことができる。 # 空でないリストの先頭の要素は常にa_list[0] 。 # In[44]: a_list[0] # In[45]: a_list[4] # 負のインデックスは、配列の後ろ側から逆順に数えて要素にアクセスする。 # 空でないリストの最後の要素は常にa_list[-1]になる。 # In[46]: a_list[-1] # 負のインデックスが理解しにくいのなら: # `a_list[-n] == a_list[len(a_list) - n]`。 # つまりこのリストでは、`a_list[-3] == a_list[5 - 3] == a_list[2]` 。 # In[47]: a_list[-3] # ### リストをスライスする # リストを定義したら、そのリストの任意の一部分を新しいリストとして取得できる。これはリストのスライスという。 # In[48]: a_list # 戻り値は、 # 1. 1つ目のスライスインデックス(この例ではa_list[1])から、 # 2. 2つ目のスライスインデックス(この例ではa_list[3])の直前までを含む新しいリストで、順序も保持されている。 # In[49]: a_list[1:3] # スライスは、スライスインデックスの一方または両方が負の数でも動作する。 # これは次のように考えると良いかもしれない: # リストを左から右へ読み、 # 1. 1つ目のスライスインデックスで欲しい最初の要素を指定し、 # 2. 2つ目のスライスインデックスは欲しくない最初の要素を指定する。戻り値はその間に含まれるすべて。 # In[50]: a_list[1:-1] # In[51]: a_list[0:3] # 左側のスライスインデックスが0のときは、これを省略できる。 # つまり、`a_list[:3]` は、始点のインデックスが暗黙に0 とみなされるので、`a_list[0:3]` と同じ。 # In[52]: a_list[:3] # 右側のスライスインデックスがリストの長さと同じである場合は、これを省略できる。つまりa_list[3:]は、このリストが5つの要素から構成されているので、a_string[3:5]と同じになる # # この5つの要素を持つリストでは、 # `a_list[:3]` は最初の3要素を返し、 # `a_string[3:]`は最後の2要素を返す。 # 実際に、リストの長さにかかわらず、 # `a_list[:n]` は常に最初の n 個の要素を返し、 # `a_list[n:]` はその残りを返す。 # In[53]: a_list[3:] # 両方のスライスインデックスが省略された場合は、リストのすべての要素が含まれる。しかし、これは元の a_list 変数とは異なる。これは、たまたますべて同じ要素を持った新しいリストなのだ。だから、a_list[:]はリストの完全なコピーを作るための簡易な方法として使える。 # In[54]: a_list[:] # In[55]: a_list[:6] # ### 要素をリストに追加する # 要素をリストに追加する方法は4つある。 # In[56]: a_list = ['a'] a_list # +演算子はリストを結合して新たなリストを作る。 # # メモリの使用量が問題となるような場合には、このリストの結合によって新たなリストがメモリ上に作成されることに注意すること。 # この場合、その新しいリストはすぐに既存の変数a_listへ代入される。 # つまり、この行は実際には # # - 結合と # - 代入 # # という2つのステップから成り立っており、巨大なリストを扱うときには(一時的に)大量のメモリを消費する可能性がある。 # リストは任意のデータ型の要素を含むことができ、1つのリストの要素がすべて同じ型である必要はない。 # In[57]: a_list = a_list + [2.0, 3] a_list # append()メソッドはリストの末尾に要素を1つ追加。 # In[58]: a_list.append(True) a_list # `extend()`メソッドは1つの引数としてリストをとり、 # 引数として与えられたリストの各要素を元のリストへ追加する。 # In[59]: a_list.extend(['four', 'Ω']) a_list # `insert()`メソッドは、1つの要素をリストに挿入する。 # 1つ目の引数は、挿入によって「位置がずらされる最初の要素のインデックス」。 # In[60]: a_list.insert(0, 'Ω') a_list # append()とextend()の違い # In[61]: a_list = ['a', 'b', 'c'] a_list # `extend()`メソッドは、 # 単一の引数として常にリストを取り、そのリストの各要素をa_listへ追加する。 # In[62]: a_list.extend(['d', 'e', 'f']) a_list # In[63]: len(a_list) # In[64]: a_list[-1] # append()メソッドも引数を1つだけとるが、その引数はどんなデータ型でもいい。 # In[65]: a_list.append(['g', 'h', 'i']) a_list # 6つの要素を持つリストに対してリストを加える (append) と、 # 結果は…… 7つの要素を持つリストになる。 # In[66]: len(a_list) # なぜなら最後の要素(今加えたもの)はリスト自体のため。 # リストはどんなデータ型でも含むことができるので、リストが他のリストを含むこともできる。これは望む結果かもしれないし、そうでないかもしれない。 # In[67]: a_list[-1] # ### リストの値を検索する # In[68]: a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] a_list # `count()`メソッドは指定された値がリストの中に何回出現するかを数える。 # In[69]: a_list.count('new') # リストの中に特定の値があるかどうかを知りたいだけの場合は、 # `count()`メソッドよりもin演算子の方がわずかながら処理が早い。 # リスト中にその値が何回現われるのかは教えないため。 # in演算子は、常にTrueまたはFalseを返す。 # # In[70]: 'new' in a_list # In[71]: 'c' in a_list # 値がリストのどこにあるのかを知る必要がある場合は、 # `index()`メソッドを呼び出だす。 # デフォルトでは、このメソッドはリスト全体を検索するが、 # - 2番目の引数で検索を開始するインデックス(0を起点とする)を指定すること # - さらに3つ目の引数で検索を止めるインデックス(0を起点とする)を指定することもできる。 # In[72]: a_list.index('mpilgrim') # In[73]: a_list.index('new') # 値がリストから見つからない場合、 # `index()`メソッドは例外を送出する。 # In[74]: a_list.index('c') # index()メソッドは、値をリストから見つけ出せなかった場合に例外を送出する。 # これは他の多くの言語と際だって異なる点。 # 他の多くの言語はここで無効なインデックス(例えば-1)を返す場合が多い。 # こうすれば、後の方で密やかに奇妙な振る舞いを引き起こすのではなく、 # 問題の根源でクラッシュしてくれる。 # # Pythonでは、そもそも「-1」がリストの有効なインデックスになる。 # ### リストから要素を取り除く # リストから要素を取り除くのにもいくつかの方法がある。 # In[75]: a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] a_list[1] # 特定の要素をリストから削除するには、`del文`が使える。 # In[76]: del a_list[1] a_list # In[77]: a_list[1] # インデックスの位置が分からないときは、 # 代わりに**値を指定することで要素を取り除く**ことができる。 # `remove()`メソッドでもリストから要素を取り除ける。 # `remove()`メソッドは値を受け取り、それで最初に見つかったものをリストから取り除く。 # In[78]: a_list.remove('new') a_list # In[79]: a_list.remove('new') a_list # `remove()`メソッドは好きなだけ呼び出すことができるが、 # リストの中に存在しない値を取り除こうとすると、このメソッドは例外を出す。 # In[80]: a_list.remove('new') # ### リストから要素を取り除く: おまけ # `pop()`メソッドは、リストから要素を取り除くもう一つの方法。 # リストのpop()メソッドを引数なしに呼び出すと、 # リストの最後の要素が削除されて、削除された値が返される。 # In[81]: a_list = ['a', 'b', 'new', 'mpilgrim'] a_list.pop() # In[82]: a_list # 任意の要素をリストからpopできる。これにはインデックスをpop()メソッドに渡すだけ。 # In[83]: a_list.pop(1) # In[84]: a_list # In[85]: a_list.pop() # In[86]: a_list.pop() # 空リストのpop()メソッドを呼び出すと、例外が出される。 # In[87]: a_list.pop() # pushの代わりが`.append()` になる # ### ブール値のコンテクストでのリスト # リストはif文のような ブール値のコンテクストでも使うことができる。 # ブール値のコンテクストでは、空のリストは偽。 # In[88]: is_it_true([]) # 要素を1つでも持つリストは真。 # In[89]: is_it_true(['a']) # In[90]: is_it_true([False]) # ## タプル # タプルはイミュータブルなリスト。 # いったん作成されたタプルは、どんな手段によっても変更できない。 # タプルはリストと同じような方法で定義するが、 # 要素の集合の全体を角括弧ではなく丸括弧「()」で包む点が異なる。 # In[91]: a_tuple = ("a", "b", "mpilgrim", "z", "example") a_tuple # In[92]: a_tuple[0] # リストと同様に、負のインデックスはタプルの後ろ側から数えられる。 # In[93]: a_tuple[-1] # リストと同様に、スライスすることもできる。リストをスライスすると新しいリストが得られるように、タプルをスライスすると新しいタプルが得られる。 # In[94]: a_tuple[1:3] # タプルとリストの大きな違いは、タプルは変更ができないという点だ。専門用語ではこれを、タプルは ** イミュータブル (immutable) ** であると言う。 # # リストは`append(), extend(), insert(), remove(), pop()` などのメソッドを持っているが、タプルはこれらのメソッドを持っていない。 # In[95]: a_tuple # In[96]: a_tuple.append("new") # In[97]: a_tuple.remove("z") # タプル中の要素を検索することはできる。 # In[98]: a_tuple.index("example") # in演算子を使って、要素がタプルに含まれているかどうかを調べることもできる。 # In[99]: "z" in a_tuple # タプルの利点 # # - タプルはリストよりも高速。変更を加える予定のない集合を定めて、それをイテレートするだけのつもりなら、リストの代わりにタプルを使うとよい。 # # - 変更の必要がないデータを「書き込み保護」すれば、コードはもっと安全なものになる。タプルをリストの代わりに使うことは、データが不変であることを示す暗黙的なassert文があるようなものであり、それを上書きするには特別の意図(と特定の関数)が要求される。 # # - ある種のタプル(具体的に言えば、文字列とか数字とか他のタプルとかいったようなイミュータブルな値からなるタプル)は辞書のキーとして使える。**リストはイミュータブルではないので、辞書のキーとしては決して使うことができない**。 # タプルはリストに変換できるし、その逆もできる。 # - 組み込みのtuple()関数はリストを引数にとって、同じ要素を持ったタプルを返す。 # - `list()`関数はタプルを引数にとってリストを返す。 # # 実質的には、 # - tuple()はリストの凍結を行い、 # - list()はタプルの解凍 # # を行うと考えることができる。 # In[100]: a_tuple_list = list(a_tuple) a_tuple_list # In[101]: type(a_tuple_list) # In[102]: a_list_tuple = tuple(a_tuple_list) a_list_tuple # In[103]: type(a_list_tuple) # ### ブール値のコンテクストでのタプル # タプルはif文のようなブール値のコンテクストで使うことができる。 # ブール値のコンテクストでは、空のタプルは偽。 # In[104]: is_it_true(()) # 要素を1つでももつタプルは真。 # In[105]: is_it_true(('a', 'b')) # In[106]: is_it_true((False,)) # 1つの要素からなるタプルを作るには、 # **値の後にカンマ「,」を置かなくてはならない**。 # もしこのカンマがないと、Pythonは余分な括弧があるだけだと見なしてしまう。 # これはエラーにはならないが、タプルは作成されない。 # In[107]: type((False)) # In[108]: type((False,)) # ### 複数の値を一度に代入する # Pythonでは、タプルを使って複数の値を一度に代入できる。 # - v は3つの要素を持つタプル # - (x、y、z)は3つの変数を持つタプル。 # # 一方をもう一方へ代入すると、vの各々の値が、順番通りに各々の変数へ代入される。 # In[109]: v = ('a', 2, True) (x, y, z) = v x # In[110]: y # In[111]: z # これにはあらゆる使い道がある。 # 仮に、連続する数値に名前を付けたいとしよう。 # 組み込みの `range()`関数と多値代入を使うことで、連続する値を素早く代入することができる。 # 組み込みのrange()関数は、整数のシーケンスを構築する。 # # MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAYが、ここで定義している変数だ # In[112]: (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) MONDAY # In[113]: TUESDAY # In[114]: SUNDAY # 多値代入は、複数の戻り値を返す関数を作るためにも使える。 # これをするには単純に、すべての戻り値を含むタプルを返せばいい。 # 呼び出し元は、返されたタプルを1つのタプルとして扱うこともできるし、個別の変数に値を代入することもできる。 # # 多くのPythonの標準ライブラリがこれを行っている。 # ## 集合 # 集合は一意な値を詰めた「袋」であり、その要素は順序づけされない。 # 1つの集合の中には、イミュータブルなデータ型の値なら何でも含めることができる。 # # 2つの集合を作れば、それらを使って和集合・積集合・差集合といった標準的な集合演算を行うこともできる。 # ### 集合を作る # 1つの値を持った集合を作るには、その値を波括弧 ({}) の中に入れればいい。 # In[115]: a_set = {1} a_set # In[116]: type(a_set) # In[117]: a_set = {1, 2} a_set # リストから集合を作ることもできる。 # リストから集合を作るには、set()関数を使えばよい # In[118]: a_list = ['a', 'b', 'mpilgrim', True, False, 42] a_set = set(a_list) a_set # In[119]: a_list # 空の集合を作ることができる。 # 空の集合を作るには、set()を引数なしに呼び出せばいい。 # # 空の集合は少し変わった表現 `set()` で表示される。 # In[120]: a_set = set() a_set # In[121]: type(a_set) # この集合は要素を持たない。 # In[122]: len(a_set) # 二つの波括弧で空の集合を作ることはできない。これは実際には空の集合ではなく、「空の辞書」を作ってしまう。 # In[123]: not_sure = {} type(not_sure) # ### 集合を変更する # 集合に値を追加するには2つの異なる方法がある。 # - add()メソッド # - update()メソッド # add()メソッドは単一の引数(どんな型でもよい)をとり、与えられた値を集合に追加する。 # In[124]: a_set = {1, 2} a_set.add(4) a_set # In[125]: len(a_set) # 集合なので、既にその集合に含まれている値を追加しようとしても、何も起こらない。 # In[126]: a_set.add(1) a_set # In[127]: len(a_set) # In[128]: a_set = {1, 2, 3} a_set # update()メソッドは1つの引数として集合をとり、その集合のすべての要素を元の集合に追加する。 # In[129]: a_set.update({2, 4, 6}) a_set # 実際にはupdate()メソッドは任意の数の引数と共に呼び出すことができる。 # 2つの集合と共に呼び出すと、update()メソッドは各々の集合の各要素を元の集合に追加する。 # In[130]: a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) a_set # update()メソッドは、リストのようにいくつもの異なるデータ型から構成されるオブジェクトを受け取ることができる。リストと共に呼び出されると、update()メソッドはリストのすべての要素を元の集合に追加する。 # In[131]: a_set.update([10, 20, 30]) a_set # ### 集合から値を取り除く # 集合から値を取り除くには3つの異なる方法がある。 # 始めの2つは # - discard()メソッド # - remove()メソッド # In[132]: a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} a_set # `discard()`メソッドは引数として1つの値を受け取り、その値を集合から取り除く。 # In[133]: a_set.discard(10) a_set # 集合に存在しない値を引数として`discard()`メソッドを呼び出したときは、何も行われない。エラーも起きない。(差集合) # In[134]: a_set.discard(10) a_set # `remove()`メソッドも同じく引数として1つの値を受け取り、その値を集合から取り除く。 # In[135]: a_set.remove(21) a_set # 値が集合の中に存在しない場合は、remove()メソッドはKeyError例外を送出する。 # In[136]: a_set.remove(21) # リストのように、集合はpop()メソッドを持っている。 # pop()メソッドは1つの値を取り除いてその値を返す。 # ただし、集合の要素は順序付けされていないので、集合には「最後の」値というものはなく、したがって、どの値が取り除かれるのかを制御する方法はない。 # **どれが取り除かれるかは完全に不定だ。** # In[137]: a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} a_set.pop() # In[138]: a_set.pop() # In[139]: a_set.pop() # In[140]: a_set # `clear()`メソッドはすべての値を集合から削除し、空集合になる。 # In[141]: a_set.clear() a_set # 空の集合からpopしようとすると、KeyError例外が出される。 # In[142]: a_set.pop() # ### 一般的な集合演算 # Pythonのsetはいくつかの一般的な集合演算をサポートしている。 # ある値が集合に含まれているかを確認するには、in演算子を使えばよい。これはリストの場合と同様に機能する。 # In[143]: a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} 30 in a_set # In[144]: 31 in a_set # `union()`メソッドは、どちらかの集合に含まれるすべての要素を含んだ新しい集合を返す。(和集合) # In[145]: b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21} a_set.union(b_set) # `intersection()`メソッドは、両方の集合に含まれるすべての要素を含んだ新しい集合を返す。(積集合) # In[146]: a_set.intersection(b_set) # `difference()`メソッドは、a_setには含まれるがb_setには含まれていないすべての要素を含んだ新しい集合を返す。(差集合) # In[147]: a_set.difference(b_set) # `symmetric_difference()`メソッドは、どちらか一方だけの集合に含まれるすべての要素を含んだ新しい集合を返す。(対称差) # In[148]: a_set.symmetric_difference(b_set) # 以上のメソッドのうち、3つは対称的。 # b_setからa_setの対称差 (symmetric difference) は、a_setからb_setの対称差。 # In[149]: b_set.symmetric_difference(a_set) # In[150]: b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set) # 2つの集合の和集合 (union) も対称的。 # In[151]: b_set.union(a_set) == a_set.union(b_set) # 2つの集合の積集合 (intersection) も対称的。 # In[152]: b_set.intersection(a_set) == a_set.intersection(b_set) # 2つの集合の差 (difference) は対称的ではない。 # In[153]: b_set.difference(a_set) == a_set.difference(b_set) # 集合に尋ねることのできる事柄。 # a_setはb_setの部分集合 (subset) 。 # つまり a_set のすべての要素は set にも含まれている。 # In[154]: a_set = {1, 2, 3} b_set = {1, 2, 3, 4} a_set.issubset(b_set) # 逆の言い方をすると、a_setのすべての要素はb_setの要素でもあるので、 # 「b_setはa_setの上位集合 (superset)」。 # In[155]: b_set.issuperset(a_set) # b_set に含まれていない値をa_setに追加すると、たちまち両方の結果はFalseになる。 # In[156]: a_set.add(5) a_set.issubset(b_set) # In[157]: b_set.issuperset(a_set) # ### ブール値のコンテクストでの集合 # ブール値のコンテクストでは、空の集合は偽。 # In[158]: is_it_true(set()) # 要素を1つでも持つ集合は真。 # In[159]: is_it_true({'a'}) # In[160]: is_it_true({False}) # ## 辞書 # 辞書は、「キーと値のペアからなる順序付けされていない集合」。 # # 辞書にキーを追加するときは、そのキーに対応する値も同時に追加しなければならない(この値はあとでいつでも変更できる)。 # # Pythonの辞書は、既知のキーをもとに値を取得するのは効率的に行えるようになっているが、その逆方向はそうなっていない。 # ### 辞書を作る # 構文は集合に似ているが、値の代わりにキーと値のペアが必要になる。辞書を作ったあとは、キーを指定することで値を取り出せる。 # 各々の要素はキーと値のペアであり、要素の集合の全体は**波括弧「{}」**に包まれている。 # In[161]: a_dict = {'server': 'db.diveintopython3.org', 'database': 'mysql'} a_dict # 'server'はキーだ。このキーに関連づけられた値はa_dict['server']によって参照でき、その値は'db.diveintopython3.org'。 # In[162]: a_dict['server'] # In[163]: a_dict['database'] # 値はキーによって取得できるが、キーを値によって取得することはできない。 # つまり、a_dict['server']は'db.diveintopython3.org'になるが、'db.diveintopython3.org'はキーではないので、a_dict['db.diveintopython3.org']は例外を出す。 # In[164]: a_dict['db.diveintopython3.org'] # ### 辞書を変更する # 辞書には、事前に定められた上限サイズというものは一切ない。新しいキーと値のペアをいつでも辞書に追加できるし、既在のキーに対応する値もいつでも変更可能。 # In[165]: a_dict # 辞書に重複したキーを持たせることはできない。既存のキーに値を代入すると、古い値が追い出される。 # In[166]: a_dict['database'] = 'blog' a_dict # キーと値のペアはいつでも追加できる。 # この構文は既存の値を変更するときとまったく同じ。 # In[167]: a_dict['user'] = 'mark' a_dict # In[168]: a_dict['user'] = 'dora' a_dict # 辞書のキーについては大文字と小文字が区別されるので、この文は新たなキーと値のペアを作り、既存の値は書き換えない。 # In[169]: a_dict['User'] = 'mark' a_dict # ### 値が混在する辞書 # 辞書は文字列しか扱えないわけではない。 # 辞書の値はどんなデータ型でもよく、 # 例えば、整数型、ブール値、任意のオブジェクトを使うことができるし、他の辞書を値にすることもできる。 # # また1つの辞書において、全ての値が同じ型である必要はなく、必要に応じて様々な型を混ぜて使うことができる。 # 辞書のキーとして使える型は値よりも制限されているが、文字列や数値、その他いくつかの型を使うことができる。 # 辞書のキーも、一つの辞書の中で様々なデータ型を混ぜて使うことができる。 # リストや集合と同じように、len()関数は辞書に含まれるキーの数を教えてくれる。 # In[170]: SUFFIXES = { 1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] } len(SUFFIXES) # リストや集合と同様に、特定のキーが辞書に含まれているかどうかを調べるには、in演算子が使える。 # In[171]: 1000 in SUFFIXES # 1000は辞書SUFFIXESのキーであり、 # 対応する値は8つの要素(正確には8つの文字列)を持つリスト。 # In[172]: SUFFIXES[1000] # In[173]: SUFFIXES[1024] # SUFFIXES[1000]はリストなので、このリストの個々の要素を0から始まるインデックスで指定できる。 # In[174]: SUFFIXES[1000][3] # ### ブール値のコンテクストでの辞書 # 辞書はif文のようなブール値のコンテクストで使うことができる。 # ブール値のコンテクストでは、空の辞書は偽. # In[175]: is_it_true({}) # キーと値のペアを1つでも持っている辞書は真。 # In[176]: is_it_true({'a': 1}) # ## None # NoneはPythonの特別な定数で、これはnull値(無効値)である。 # **NoneはFalseではないし、0でもないし、空の文字列でもない。NoneをNone以外の値と比較すると、常にFalseが返る。** # # Noneは唯一のnull値であり、Noneは自身のデータ型 (NoneType) を持っている。Noneは任意の変数へ代入できるが、他のNoneTypeのオブジェクトを作ることはできない。Noneを値として持つすべての変数は互いに等しい。 # In[177]: type(None) # In[178]: None == False # In[179]: None == 0 # In[180]: None == '' # In[181]: None == None # In[182]: x = None x == None # In[183]: y = None x == y # ### ブール値のコンテクストでのNone # ブール値のコンテクストでは、 # - Noneは偽 # - not Noneは真。 # In[184]: is_it_true(None) # In[185]: is_it_true(not None) # ## 参考リンク # - http://diveintopython3-ja.rdy.jp/native-datatypes.html