【技術書】 独学プログラマー 第2部


はじめに
--
主にPythonのクラスについて。
他の言語をある程度知っている上で、覚えておきたいことを書いています。
([第1部](https://qiita.com/giwasuke/items/1789c82dd65d3cc48958)はこちら)


目次
--
1. 第12章 プログラミングパラダイム
2. 第13章 オブジェクト指向プログラミングの4大要素
3. 第14章 もっとオブジェクト指向プログラミング
4. 第15章 知識を1つにまとめる

第12章 プログラミングパラダイム
--

- プログラミングパラダイムとは、プログラミングのスタイル・手法のこと。
- プログラミングのプロとしてやっていくなら、オブジェクト指向か、関数型プログラミングのどちらかを学ぶ必要があるでしょう。
- それぞれの大きな違いの1つは、状態（ステート）の持ち方の違いだ。これは、プログラムが動いているときの変数の値のことである。<br><br>
- **手続き型プログラミング**のイメージは、「これをやって、次にあれをやって」といった連続した手続き。逐次的。途中途中でプログラムのステートを変えていく。<br>
小さなプログラムを書くには適しているが、状態の全てをグローバル変数に持たせ、関数でそのデータを操作する形を採るため、コードが長くなるとグローバル変数の読み書きでプログラムの維持が大変になる。
- **関数型プログラミング**は、グローバルステートに依存せず、渡された引数によってのみ動作を変える。つまり、現在の関数外のデータに依存せず、関数外に存在するデータを変更することがない。
ただ、グローバルステート（変数等）なしで設計すると難易度が上がることもある。<br><br>

- **オブジェクト指向プログラミング**も、グローバルステートを排除して手続き型の問題を解消しているが、関数型のように関数の引数に状態を渡すのではなく、オブジェクトに状態を持たせる。
「クラス」を複数作り、クラス間で相互作用するオブジェクトの集合を定義する。クラスは、表現したいオブジェクトを定義・分類する、プログラミングの仕組み。

```
class [クラス名]:
    [スイート]
```

- 全てのオブジェクトは、クラスのインスタンス。例えば、数値 4　はintクラスのインスタンス、"abc"はstrクラスのインスタンス。
- Pythonのクラス名は、大文字で始めよう。アンダースコアは使わず、LikeThisのようにする。
- クラスのスイート部には、単純文、もしくはメソッドと呼ばれる複合文を書く。クラスから作ったオブジェクトに対して呼び出せる関数である。

```class_method.py
# メソッドの制約(1): スイート部分に定義
# (2): 引数を少なくとも1つ定義する必要がある

class Orange:
    def __init__(self):    # 1つ目の必須な引数には慣習的にselfという名前を使う
        print("Created!")
```

- 通常、インスタンス変数は ``__init__`` という特別な関数ないで定義する。``self.[変数名] = [値]`` という構文になる。二重のアンダースコアで囲まれたメソッドは特殊メソッドと呼ぶ。

```instance_hensu.py
class Orange:
    def __init__(self, w, c):
        self.weight = w
        self.color = c
        print("Created!")

obj1 = Orange(5, "dark orange") # 初期値を引数で渡す
print(obj1.weight)
>> 5
```

- 次に示す長方形を表すクラスRectangleは、クラスとメソッドの理解に大いに役立つ：

```Rectangle.py
class Rectangle:
    def __init__(self, w, l):
        self.width = w
        self.len = l

    def area(self):
        return self.width * self.len
  
    def change_size(self, w, l):
        self.width = w
        self.len = l

rectangle = Rectangle(10, 20)
print(rectangle.area())
rectangle.change_size(20, 40)
print(rectangle.area())

>> 200
>> 800
```

- オブジェクト指向プログラミングによって、開発や保守の効率化につながる。
- 欠点は、プログラムを書く前の設計にコストがかかること。

第13章 オブジェクト指向プログラミングの4大要素
--

- カプセル化、抽象化、ポリモーフィズム、継承の4つ
- これらを提供している言語（PythonやJava、Rubyなど）こそ、オブジェクト指向プログラミング言語と言える。

- **カプセル化**は、2つの概念で成り立っている。
・1つ目は、「オブジェクトで複数の変数（状態）とメソッド（状態の変更・計算への利用）をまとめること」
・2つ目は、「データをクラス内に隠蔽して外から見えないようにすること」Pythonにプライベート変数はないが、変数やメソッドの名前がアンダースコアで始まっていたら、外部から触ってはいけないという暗黙のルールが存在する（自己責任で、使うことは可能）。

```public_private.py
class PublicPrivateExample:
    def __init__(self):
        self.public = "safe"
        self._unsafe = "unsafe"

    def public_method(self):
        # クライアントが使ってもよい
        pass

    def _unsafe_method(self):
        # クライアントは使うべきじゃない
        pass
```

- **抽象化**
・「対象から小さな特徴（そのクラスで扱いたい問題に関係ないもの）を除き、本質的で必要な特徴だけを集めた状態」にする手順のこと。

- **ポリモーフィズム**は、「同じ関数やメソッド（インターフェース）でありながら、複数のデータ型に合わせて異なる動作をする機能」を提供する。
・``print()`` は、文字列、整数、浮動少数点数のいずれのデータ型も引数に取れる。それぞれのデータ型に特化した関数やメソッドを作らなければならないとすれば、読むのも書くのも大変。

- 最後の1つが**継承**。遺伝的継承に似ていて、親クラスから子クラスにメソッドや変数を受け継ぐこと。
・子クラスを定義するときは、親クラスをパラメータに指定する：

```inheritance.py
class Shape:
    def __init__(self, w, l):
        self.width = w
        self.len = l

    def print_size(self):
        print("{} by {}".format(self.width, self.len))

class Square(Shape): # Shapeクラスを継承した子クラスSquare
    pass

# 親クラスの変数とメソッドが使える
a_square = Square(20, 20)
a_square.print_size()
>> 20 by 20
```

- 子クラスには、親クラスに影響しない変数やメソッドを定義できる。親クラスのメソッド名と同じメソッドを子クラスで定義して書き換えることをメソッドオーバーライドと呼ぶ。

- 「コンポジション」も重要なコンセプトなのでおまけに紹介している。「has-a」関係を表、あるクラスの変数に別クラスのオブジェクトを持たせることができる。

第14章 もっとオブジェクト指向プログラミング
--

- 前々節の復習から。
・すべてのオブジェクトはクラスのインスタンスである
・クラスから作られるオブジェクトをインスタンスと呼ぶ

- Pythonのすべてのクラスは、objectクラスを継承する。

- クラス変数とインスタンス変数の違いを、次のコードで理解しよう：

```class_instance.py
class Rectangle:
    recs = []

    def __init__(self, w, l):
        self.width = w
        self.len = l
        self.recs.append((self.width, self.len))

r1 = Rectangle(10, 24)
r2 = Rectangle(20, 40)
r3 = Rectangle(100, 200)

print(Rectangle.recs)
>> [(10, 24), (20, 40), (100, 200)]
```
インスタンス変数 width, len は、``__init__()``が呼ばれて作られる。インスタンスごとに固有の値を持つ。
それに対し、クラス変数 recs は、クラス間で共通した値を保持する。グローバル変数を使わずに、クラスのインスタンス間でデータの共有が可能になる。

- is キーワードは、前後にとったオペランドのオブジェクトが同一ならTrueを返す。また、ある変数がNoneかどうかを調べる時にも使う。``x is None`` ← TrueかFalseを返す。

第15章 知識を1つにまとめる
--

- クラスのまとめとして、「戦争（War）」という人気のカードゲームを作る。コードの掲載は省く。

感想
--
- 焦りすぎてもよくない。時にじっくり理解する必要がある。
- Pythonにはmain関数がない。

[第3部](https://qiita.com/giwasuke/items/e44d1f400bc205c90528)はこちら