Python初心者が「Python文法詳解」を読んだメモ #2

# バックナンバー
- [Python初心者が「Python文法詳解」を読んだメモ #1](https://qiita.com/usayomo/items/7024c619c5f72462cb10) 

# 第3章 式とデータ型
- 論理演算の結果を表す`` bool`` 型も数値型のオブジェクト。
- Pythonのデータはそれぞれ固有の型を持っているが、全て`` object`` 型から派生している。
- どんなオブジェクトであれ`` object`` 型のインスタンスであり、全ての型は、`` type`` という型のオブジェクトである。

```py:オブジェクト属性に関連する組み込み関数
>>> setattr(obj, 'ham', 100)  # obj.ham = 100  と同じ

>>> getattr(obj, 'ham', 999)  # try:
100                           #     return obj.ham
                              # except AttributeError:
                              #     return 999
                              # と同じ（デフォルト値は省略可）

>>> delattr(obj, 'ham')  # del obj.ham  と同じ
>>> hasattr(obj, 'ham')  # objに属性nameが存在すればTrueを返す
False
```

## Noneオブジェクト
- 「値が指定されていない」ことを示す時に使う
- C言語の`` NULL`` とかJavaの`` null`` みたいなもの
- `` NoneType`` 型のシングルトンオブジェクト（この型唯一のオブジェクト）

```py:シングルトンオブジェクトのチェック処理

# ==よりもisの方が高速、その上==演算子は比較対象のオブジェクトで独自に実装できる（判定結果を保証できない）
# （「比較対象のオブジェクトで独自に実装できる」がちょっとよくわかってない）
>>> spam = 1
>>> spam == None  # こうじゃなくて
False
>>> spam is None  # こう
False
```

## Ellipsisオブジェクト
- `` ellipsis`` 型のシングルトンオブジェクト。
- "ellipsis" = 省略 という意味らしい。（知らなかったので調べた）
- 元々は多次元配列などを扱うサードパーティ製ライブラリなどでの利用を想定。
- 特に利用方法や利用目的は決まっていない。

```py:Ellipsisオブジェクトの利用例
>>> ...  # Python3からはこのリテラルで記述可能になった
Ellipsis

# サンプルコードの省略部分を表したり
def spam():
    ...

# 値を明確に指定しないということを表したりすると良いかもしれない
ham = ...
egg = (1, 2, ...)
```


## 関数の呼び出し
```py:引数の渡し方いろいろ
spam(0, 1, 2, 3, 4)     # これは
args = [0, 1, 2, 3, 4]  # イテラブルオブジェクトに格納しておいて
spam(*args)             # こう書ける


spam(a = bacon, b = sausage)  # こっちは
kwargs = {
    "a":bacon,
    "b":sausage
}               # マッピングオブジェクトに格納しておくと
spam(**kwargs)  # このように書ける
```


- Pythonでは、関数・メソッド・クラスなども整数や文字列などと同じ単なるオブジェクトの一種
- `` ()`` も単なる演算子なので、関数呼び出し = 「オブジェクトに`` ()`` 演算子を適用する」に過ぎない
- 関数オブジェクトと整数オブジェクトの違いは、`` ()``演算子の動作を定義しているか、そうでないかという__だけ__
- `` ()``演算子の動作を定義しているオブジェクトを__呼び出し可能オブジェクト__という
- 型オブジェクトも呼び出されるとその型のオブジェクトを作成する呼び出し可能オブジェクトの一つ

```py:オブジェクトのメソッドも呼び出し可能オブジェクトなので...
>>> spam.ham(egg)      # spamオブジェクトのhamメソッド呼び出し

>>> method = spam.ham  # spamオブジェクトのham属性を取得して
>>> method(egg)        # こう書くとメソッドが呼び出せる（すごい）
```

## 変数と参照
```py:変数への代入とは、オブジェクトを変数名で参照できるようにすること
>>> spam = [1, 2, 3, 4]  # 変数spamがリストオブジェクトを参照するように設定
>>> ham = spam           # 別の変数hamに代入すると、hamも同じオブジェクトを参照する
>>> ham
[1, 2, 3, 4]

>>> spam.append('five')  # リストオブジェクトに要素追加すると
>>> spam                 # spamもhamも同じオブジェクトを参照しているので、
[1, 2, 3, 4, 'five']
>>> ham                  # 表示される結果は同じ
[1, 2, 3, 4, 'five']
```

```py:新しいオブジェクトが作成される場合はこうなる
>>> egg = bacon = 1
>>> egg = egg + 1   # egg + 1 は新しいオブジェクトを返す
>>> egg
2
>>> bacon
1
```

## 要素の分解
```py:まとめて代入あれこれ
>>> spam = [1, 2, 3]
>>> first, second, third = spam
>>> first, second, third  # イテラブルオブジェクトの要素を分解して代入してくれる
(1, 2, 3)

>>> (a, [b, c], d) = (1, (2, 3), 4)  # 左辺は[]か()で囲んでさらに分解可能
>>> a, b, c, d
(1, 2, 3, 4)
```
```py:左辺の変数より右辺の要素数が多い場合
# *付きの変数があれば、いい感じにリストオブジェクトにまとめて代入してくれる
>>> spam, ham, *egg = 1, 2, 3, 4, 5
>>> spam, ham, egg
(1, 2, [3, 4, 5])

>>> spam, *ham, egg = 1, 2, 3, 4, 5
>>> spam, ham, egg
(1, [2, 3, 4], 5)

>>> *spam, ham, egg = 1, 2, 3, 4, 5
>>> spam, ham, egg
([1, 2, 3], 4, 5)
```
```py:左辺の変数より右辺の要素数が少ない場合
# *付きの変数は要素数0の空リストになる
>>> spam, ham, *egg = 1, 2
>>> spam, ham, egg
(1, 2, [])
```