Pythonのビルトインオブジェクト

# 概要
[はじめてのPython第3版](https://www.oreilly.co.jp/books/9784873113937/)の勉強メモ

# アジェンダ
- ビルトインオブジェクト
- 数値
- 文字列
- リスト
- ディクショナリ
- タプル
- ファイル
- その他の型
- まとめ

# ビルトインオブジェクト
## ビルトインオブジェクトを使うメリット
- プログラムが簡単に作れる
- ビルトインオブジェクトを基に独自オブジェクトも作れる
- ビルトインオブジェクトはカスタムオブジェクトよりもパフォーマンスが高いことが多い
  - PythonのビルトインオブジェクトはC言語で書かれていて、パフォーマンスが高くなるよう予め最適化されている
- ビルトインオブジェクトは標準
  - 特性、機能が変わることがない

## ビルトインオブジェクトの型
| オブジェクトの型 | リテラルの例 |
|:--|:--|
| 数値 | 1234<br>3.1425<br>999L<br>3+4j |
| 文字列 | 'spam'<br>"guido7s" |
| リスト | [1, [2, 'three'], 4] |
| ディクショナリ | {'food': 'spam', 'taste': 'yum'} |
| タプル | (1, 'spam', 4, 'U') |
| ファイル | myfile = open('eggs', 'r') |
| その他 | set<br>type<br>None<br>bool |

# 数値
## 数学演算
### 加算なら `+` 記号、乗算なら `*` を使い、累乗を求めるなら `**` 記号を使う
```pycon
# 整数の足し算
>>> 123 + 222
345

# 浮動小数点数の乗算
>>> 1.5 * 4
6.0

# 2の100乗
# Python では、精度を上げる必要が生じると、自動的に「長整数」への変換が行われる
>>> 2 ** 100
1267650600228229401496703205376L
```

### 以下の違いは、repr、strという2 つのビルトイン関数の間の違い
```pycon
# repr：演算結果をそのまま表示(最大限の精度での出力)
>>> 3.1415 * 2
6.2830000000000004

# str：見やすい形式に変換して表示(人間にとって見やすいかたちでの表示)
>>> print 3.1415 * 2
6.283
```

### mathモジュール
- mathモジュールには、数値に関する高度な処理に使えるツールが関数のかたちで用意されている


```pycon
>>> import math
>>> math.pi
3.1415926535897931
>>> math.sqrt(85)
9.2195444572928871
```

### randomモジュール
- randomモジュールには、乱数発生の機能、あるいは無作為選択の機能などが用意されている

```pycon
>>> import random
>>> random.random()
0.59268735266273953
>>> random.choice([1, 2, 3, 4])
1
```

# 文字列
## シーケンス
- 文字列はシーケンスと呼ばれるオブジェクトの一種
- シーケンスというのは、オブジェクトを一定の順序に並べたもの
- シーケンスでは、要素となるオブジェクトの順序が常に変わらない

## シーケンスの操作
- インデックスは左端からいくつ目の要素であるかを表す数字
- 最初の要素のインデックスは“0”で、2 番目が“1”となる
- 負の数を使うことで、右端から逆の順に要素を指定することができる
- 角カッコの中には、数字を指定する以外に、式を書くこともできる
- より応用範囲の広いスライシングという操作にも対応
- スライシングは文字列の特定部分を切り取る、内容を調べる処理
- `+` 記号を使うことで連結できる
- `*` 記号を使うことで、繰り返し処理ができる

```pycon
>>> S = 'Spam'

# 長さの確認
>>> len(S)
4

# インデックス“0”を指定すると、先頭の要素を抽出できる
>>> S[0]
'S'

# 左から2番目の要素を抽出
>>> S[1]
'p'

# Sの右端の要素
>>> S[-1]
'm'

# Sの右端から2番目の要素
>>> S[-2]
'a'

# Sの末尾の要素
>>> S[-1]
'm'

# 同じ意味だが、こちらの方が難しい
>>> S[len(S)-1]
'm'

# 1、2の要素（3は含まれない）をスライシングにより抽出
>>> S[1:3]
'pa'

# インデックス1より後の要素をすべて抽出（1:len(S)と同じ）
>>> S[1:]
'pam'

# 上記の処理の後もS自体に変化はない
>>> S
'Spam'

# 末尾以外の要素をすべて抽出
>>> S[0:3]
'Spa'

# S[0:3]と同じ
>>> S[:3]
'Spa'

# これも同じ（0:-1とも書けるがこちらの方が簡単）
>>> S[:-1]
'Spa'

# Sの全要素を抽出（0:len(S)と同じ）
>>> S[:]
'Spam'

# 連結
>>> S + 'xyz'
'Spamxyz'

# 元のSは変化しない
>>> S
'Spam'

# 繰り返し
>>> S * 8
'SpamSpamSpamSpamSpamSpamSpamSpam'
```

## 不変性
- 文字列を対象に何か処理をしても、元の文字列に変化は起きない

```pycon
>>> S
'Spam'

# 不変性を持つオブジェクトは上書きできない
>>> S[0] = 'z'
...エラーメッセージは省略...
TypeError: 'str' object does not support item assignment

# 新たな文字列を作成し、元の変数に代入
>>> S = 'z' + S[1:]
>>> S
'zpam'
```

## 文字列固有のメソッド 
```pycon
# 指定の文字列を探す
>>> S.find('pa')
1

>>> S
'Spam'

# 指定の文字列を置換
>>> S.replace('pa', 'XYZ')
'SXYZm'

>>> S
'Spam'

>>> line = 'aaa,bbb,ccccc,dd'

# 区切り文字で分割しリストにする
>>> line.split(',')
['aaa', 'bbb', 'ccccc', 'dd']

>>> S = 'spam'

# 大文字小文字の変換
>>> S.upper()
'SPAM'

# 内容の確認（isalpha、isdigitなど）
>>> S.isalpha()
True

>>> line = 'aaa,bbb,ccccc,dd\n'

# 右端の空白文字を削除
>>> line = line.rstrip()
>>> line
'aaa,bbb,ccccc,dd'
```

## 文字列の作り方のバリエーション
### エスケープシーケンス
```pycon
# \nは行末、\tはタブ
>>> S = 'A\nB\tC'

# どちらも1文字として扱われる
>>> len(S)
5

# \nは、ASCIIコード10に対応する
>>> ord('\n')
10

# \0はNULLを表す。文字列の終了ではない
>>> S = 'A\0B\0C'
>>> len(S)
5
```

### シングル、ダブル、トリプルクォーテーション
- トリプルクォーテーションで囲むと、複数行がひとまとまりのものとして扱われるようになる
  - HTMLやXMLのコードをPythonのプログラムに埋め込む際などには便利
- 文字列の先頭のクォーテーションの前に“r”を付ければ、エスケープシーケンスのバックスラッシュは単なる文字として解釈されるようになり、これを「raw文字列」と呼ぶ
- クォーテーションの前に“u”を付けることで、中の文字列をUnicode 文字列として解釈させることもできる

```pycon
>>> msg = """
aaaaaaaaaaaaa
bbb'''bbbbbbbbbb""bbbbbbb'bbbb
cccccccccccccc"""
>>> msg
'\naaaaaaaaaaaaa\nbbb\'\'\'bbbbbbbbbb""bbbbbbb\'bbbb\ncccccccccccccc'
```

## パターンマッチング
- reというモジュールを使う

```pycon
>>> import re
>>> match = re.match('Hello[ \t]*(.*)world', 'Hello Python world')
>>> match.group(1)
'Python '

>>> match = re.match('/(.*)/(.*)/(.*)', '/usr/home/lumberjack')
>>> match.groups()
('usr', 'home', 'lumberjack')
```

# リスト
## リストの特徴
- 特定の型に縛られない
- サイズが固定されない

## シーケンス操作
- 文字列同様の操作が可能
- インデクシングやスライシングも可能

```pycon
# 3つの要素からなるリスト。型はすべて異なる
>>> L = [123, 'spam', 1.23]

# リストの要素の数
>>> len(L)
3

# インデクシング
>>> L[0]
123

# スライシング（結果として新しいリストが戻される）
>>> L[:-1]
[123, 'spam']

# 連結でも新たなリストが作られる
>>> L + [4, 5, 6]
[123, 'spam', 1.23, 4, 5, 6]

# 元のリストは変更されていない
>>> L
[123, 'spam', 1.23]
```

## リスト固有のメソッド
- `append`:末尾に要素を追加
- `pop`:途中の要素を削除
- `insert`:指定の位置に要素を挿入
- `remove`:指定の要素を削除
- `sort`:リストの要素を昇順にする（上書きする）
- `reverse`:要素を逆順にする（上書きする）

```pycon
# 末尾に要素を追加してリストを長くする
>>> L.append('NI')
>>> L
[123, 'spam', 1.23, 'NI']

# 途中の要素を削除してリストを短くする
>>> L.pop(2)
1.23

# “del L[2]”でも要素の削除ができる
>>> L
[123, 'spam', 'NI']

>>> M = ['bb', 'aa', 'cc']
>>> M.sort()
>>> M
['aa', 'bb', 'cc']

>>> M.reverse()
>>> M
['cc', 'bb', 'aa']
```

## 要素の存在チェック
### 実際に存在しない要素を参照することは
```pycon
>>> L
[123, 'spam', 'NI']

>>> L[99]
...エラーメッセージは省略...
IndexError: list index out of range

>>> L[99] = 1
...エラーメッセージは省略...
IndexError: list assignment index out of range
```

## ネスト
### ネストの応用例
- マトリクス（行列）
- 多次元配列

```pycon
# 3×3のマトリクスをリストのネストで作ったもの
>>> M = [[1, 2, 3], 
         [4, 5, 6],
         [7, 8, 9]]
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# 行2にアクセス
>>> M[1]
[4, 5, 6]

# 行2にアクセスした後、その行の3番目の要素を取得
>>> M[1][2]
6
```

## リスト内包表記
- リスト内包表記は、集合論の表記法を基に考案されたもの
- 演算は左から右に1 つずつ順に行われる
- 処理速度の面で有利

```pycon
# 2列目の要素を取り出す
>>> col2 = [row[1] for row in M]
>>> col2
[2, 5, 8]

# 元のマトリクスは変更されない
>>> M
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# 列2の各要素に1を加える
>>> [row[1] + 1 for row in M]
[3, 6, 9]

# 奇数の要素を取り除く
>>> [row[1] for row in M if row[1] % 2 == 0]
[2, 8]

# 対角線上の要素を取り出す
>>> diag = [M[i][i] for i in [0, 1, 2]]
>>> diag
[1, 5, 9]

# 文字列中の文字を繰り返す
>>> doubles = [c * 2 for c in 'spam']
>>> doubles
['ss', 'pp', 'aa', 'mm']
```

# ディクショナリ
## 写像
- ディクショナリは、「シーケンス」ではなく、写像というカテゴリに属す
- 要素が並ぶ順序は一定ではない
- Pythonの主要なオブジェクトの中で、写像のカテゴリに属するのはディクショナリだけ
- 上書き可能な「可変性」のオブジェクト
- 検索処理にはディクショナリを使うのが速度という面では最も有利

## 写像の操作
```pycon
>>> D = {'food': 'Spam', 'quantity': 4, 'color': 'pink'}

# キー'food'を指定
>>> D['food']
'Spam'

# 'quantity'に対応する値に1を加える
>>> D['quantity'] += 1
>>> D
{'food': 'Spam', 'color': 'pink', 'quantity': 5}

>>> D = {}

# 存在しないキーを指定して値を代入
>>> D['name'] = 'Bob'
>>> D['job'] = 'dev'
>>> D['age'] = 40
>>> D
{'age': 40, 'job': 'dev', 'name': 'Bob'}
>>> print D['name']
Bob
```

## ネスト
```pycon
>>> rec = {'name': {'first': 'Bob', 'last': 'Smith'},
           'job': ['dev', 'mgr'],
           'age': 40.5}

# 'Name'にはネストされたディクショナリが対応
>>> rec['name']
{'last': 'Smith', 'first': 'Bob'}

# ネストされたディクショナリのキーを指定
>>> rec['name']['last']
'Smith'

# 'job'にはネストされたリストが対応
>>> rec['job']
['dev', 'mgr']

# ネストされたリストのインデックスを指定
>>> rec['job'][-1]
'mgr'

# 'job'に対応するリストを拡張し上書き
>>> rec['job'].append('janitor')
>>> rec
{'age': 40.5,'job': ['dev', 'mgr', 'janitor'], 'name': {'last': 'Smith', 'first':'Bob'}}
```

## キーのソート：forループ
```pycon
# キーのリストを取得（順不同）
>>> Ks = D.keys()
>>> Ks
['a', 'c', 'b']

# キーのリストをソート
>>> Ks.sort()
>>> Ks
['a', 'b', 'c']

# リスト中のキーと、それに対応する値を順に出力
>>> for key in Ks:
print key, '=>', D[key]
a => 1
b => 2
c => 3
```

### 上記の処理は以下のように書ける
```pycon
>>> D
{'a': 1, 'c': 3, 'b': 2}
>>> for key in sorted(D):
print key, '=>', D[key]
a => 1
b => 2
c => 3
```

### 文字列中の文字を順に大文字に変換して出力する、forループ
```pycon
>>> for c in 'spam':
print c.upper()
S
P
A
M
```

### 反復処理と最適化
- 以下の2つのコードは同等なのですが、リスト内包表記の方が一般に2倍程度処理が速くなります
- 簡潔で読みやすいことを重視し、処理速度はその後に考える方がよい
- 速度を確かめる必要がある場合には、time モジュール、timeit モジュール、profileモジュールといったツールが使える

```pycon:リスト内包表記
>>> squares = [x ** 2 for x in [1, 2, 3, 4, 5]]
>>> squares
[1, 4, 9, 16, 25]
```

```pycon:forループ
>>> squares = []
>>> for x in [1, 2, 3, 4, 5]:
squares.append(x ** 2)
>>> squares
[1, 4, 9, 16, 25]
```

## 存在しないキー：ifテスト
### 存在しないキーを手がかりに値にアクセスしようとするとエラーになる
```pycon
>>> D
{'a': 1, 'c': 3, 'b': 2}

# 新たなキーを指定するとディクショナリが拡張される
>>> D['e'] = 99
>>> D
{'a': 1, 'c': 3, 'b': 2, 'e': 99}

# 存在しないキーで値にアクセスしようとするとエラーに
>>> D['f']
...エラーメッセージは省略...
KeyError: 'f'
```

### キーが存在するかを事前に確かめる
- `has_key`メソッドでキーが存在するか確認

```pycon
>>> D.has_key('f')
False
>>> if not D.has_key('f'):
print 'missing'
missing
```

# タプル
## いったん作ると変更ができない
```pycon
>>> T = (1, 2, 3, 4) # 4つの要素を持つタプル
>>> len(T) # 長さ
4
>>> T + (5, 6) # 連結
(1, 2, 3, 4, 5, 6)
>>> T[0] # インデクシング、スライシングなど
1
タプルのリストとの最も大きな違いは、いったん作ると変更ができない、という点でしょう。
>>> T[0] = 2 # タプルは不変性
...エラーメッセージは省略...
TypeError: 'tuple' object does not support item assignment
```



# タプル
```pycon:タプル
# 4つの要素を持つタプル
>>> T = (1, 2, 3, 4)

# 長さ
>>> len(T)
4

# 連結
>>> T + (5, 6)
(1, 2, 3, 4, 5, 6)

# インデクシング、スライシングなど
>>> T[0]
1

# タプルのリストとの最も大きな違いは、いったん作ると変更ができないという点
>>> T[0] = 2
...エラーメッセージは省略...
TypeError: 'tuple' object does not support item assignment
```
## なぜタプルが必要なのか
- 整合性の確保のため
- 速度面


# ファイル
## 基本操作
```pycon:書き込み
# 出力モードで新規ファイル作成
>>> f = open('data.txt', 'w')

# 文字列を書き込み
>>> f.write('Hello\n')

>>> f.write('world\n')

# ファイルを閉じ、出力バッファをディスクにフラッシュ
>>> f.close()
```

```pycon:読み込み
# 'r'はデフォルトの処理モード
>>> f = open('data.txt')

# ファイル全体を読み込む
>>> bytes = f.read()
>>> bytes
'Hello\nworld\n'

# printが制御文字の意味を解釈
>>> print bytes
Hello
world

# ファイルの内容は常に文字列として扱われる
>>> bytes.split()
['Hello', 'world']
```

## ファイル関連ツール
### サポートされるツール
- パイプ
- FIFO
- キーアクセスファイル
- オブジェクトの永続化
- 記述子ファイル
- リレーショナルデータベース/オブジェクト指向データベース

# その他の型
## 集合オブジェクト
- `set`というビルトイン関数を使う
- 集合オブジェクトは数学でいう「集合演算」に対応できる

```pycon
>>> X = set('spam')

# シーケンスを基に2つの集合を作成
>>> Y = set(['h', 'a', 'm'])
>>> X, Y
(set(['a', 'p', 's', 'm']), set(['a', 'h', 'm']))

# 交差
>>> X & Y
set(['a', 'm'])

# 結合
>>> X | Y
set(['a', 'p', 's', 'h', 'm'])

# 差
>>> X - Y
set(['p', 's'])
```

## 固定精度の小数やブール型
```pycon
# 固定精度の小数
>>> import decimal
>>> d = decimal.Decimal('3.141')
>>> d + 1
Decimal("4.141")

# ブール型
>>> 1 > 2, 1 < 2
(False, True)
>>> bool('spam')
True

# None
>>> X = None
>>> print X
None

# 100のNoneからなるリストを作成
>>> L = [None] * 100
>>> L
[None, None, None, None, None, None, None, None, None, None, None, None, None,...100のNoneのリスト...]

# Types
>>> type(L)
<type 'list'>

# 型自体もオブジェクト
>>> type(type(L))
<type 'type'>
```

## 型のチェック
- Python では通常、型のチェックは行わない方がよい
- プログラムを書く際に注意すべきなのはオブジェクトのインタフェース

```pycon
# 型のチェック
>>> if type(L) == type([]):
print 'yes'
yes

# 型の名前を確認
>>> if type(L) == list:
print 'yes'
yes

# 「オブジェクト指向的」な確認方法
>>> if isinstance(L, list):
print 'yes'
yes
```

## ユーザの作るクラス
```py:Workerクラスの定義
class Worker:
  # 初期化
  def __init__(self, name, pay):
    # selfは新しいオブジェクトに対応
    self.name = name
    self.pay = pay
  def lastName(self):
    # 空白で文字列を分割
    return self.name.split()[-1]
  def giveRaise(self, percent):
    # 給与を上書き
    self.pay *= (1.0 + percent)
```

```pycon
# 2つのインスタンスを作成
>>> bob = Worker('Bob Smith', 50000)

# どちらもnameとpayを持つ
>>> sue = Worker('Sue Jones', 60000)

# メソッドの呼び出し。bobがselfとなる
>>> bob.lastName()
'Smith'

# sueがself
>>> sue.lastName()
'Jones'

# sueのpayを変更
>>> sue.giveRaise(.10)
>>> sue.pay
66000.0
```

# まとめ
## Pythonのビルトインオブジェクトにはどのようなものがあるか
- 数値
  - 整数
  - 長整数
  - 浮動
  - 小数点数
  - 固定精度の小数
- 文字列
  - 通常の文字列
  - Unicode 文字列
- リスト
- ディクショナリ
- タプル
- ファイル
- 集合
- 型オブジェクト
- None
- ブール型

## ビルトインオブジェクトと
- Pythonにあらかじめ用意されており、常に使用可能なオブジェクトのこと
- ビルトインオブジェクト以外のオブジェクトを使う場合は、モジュールをインポートし、その中の関数を呼び出す必要がある

## 不変性とは
- 一度作成したオブジェクトにその後、変更を加えられない、という性質のこと
- 数値、文字列、タプルなどが不変性オブジェクトに分類できる
- 不変性オブジェクトを操作する式では、実行結果として、オブジェクトの変更（上書き）は行われず、新たなオブジェクトが作成される

## シーケンスとは
- 1 つ以上のオブジェクトを一定の順序で並べたもののこと
- シーケンスに分類されるのは、文字列、リスト、タプルなど
- シーケンスに属するオブジェクトはいずれも、インデクシング、連結、スライシングといった操作に対応
- それぞれの型のメソッドを使うことで、型固有の操作も可能

## 写像とは
- オブジェクトの集合
- 要素が並ぶ順序は一定ではない
- 個々の要素に「キー」が付く
- ビルトインオブジェクトの中で写像に分類されるのは、ディクショナリだけ

## ポリモーフィズムとは
- 同じコードであっても、処理の対象となるオブジェクトの種類によって、その意味が変わる、という性質のこと
- Pythonでは、同じコードが対象オブジェクトによって自動的に機能を変える
- 1つのコードだけで何種類ものオブジェクトに対応することができる