【Python】クラスの基本(メモ)

【オブジェクトとは】
データと命令(メソッド)が一緒になっているもの
命令型プログラミングではデータはデータ、命令は命令というように別々に扱うがデータと命令を一緒にしてしまおうという考えを「オブジェクト指向」という。
【クラスとは】
オブジェクトがどのような性質を持っていてどのようなふるまいをするかということをコードにかく。
クラスからオブジェクトを作るには関数みたいにクラスを呼び出すときに引数を与える必要がある。
クラスから作ったオブジェクトは「インスタンス」と呼ばれる。


【組み込み型のオブジェクトとクラスインスタンス比較】

組み込み型にはデータの性質によって数値型や文字型などの「型」がある。
⇒
クラスの場合はクラスの名前がこの「型」に対応する
<font color="red">【訂正】</font>
組み込み型もクラスであるのでこの比較は不適切でした。


組み込み型はどのような型であるかによってオブジェクトに対して実行できる操作やメソッドの種類が異なっていた。
⇒
インスタンスの場合はどのクラスのインスタンスによって、メソッドや処理の種類が変わってくる。


組み込み型の型やクラスはプログラムで使う「設計図」のようなものととらえることができる。
設計図をもとにプログラムを組み立てるために作る「部品」がオブジェクトやインスタンスである。

【アトリビュートについて】
インスタンスにデータを持たせたいときアトリビュートを用いる。
オブジェクトの代入を行うことで変数を定義するようにアトリビュートも代入を行うことで定義する。
インスタンスからドット(.)で区切ってアトリビュート名を記述する。組み込み型オブジェクトのメソッドを呼び出すときに似ている。
例
i.value=5
(valueというアトリビュートに5(数値)を代入

変数にはどのようなオブジェクトが代入できたようにアトリビュートにもすべてのオブジェクトを代入することができる
アトリビュートはインスタンスが持つことができる変数のようなもの。

【初期化メソッド__init__()について】
クラスでのインスタンスの持つべきデータはインスタンスが作られた時にあらかじめ代入(初期化)するメソッドを定義することができる
インスタンスごとにアトリビュートを代入する必要はなくなる。


【具体的なプログラムの書き方】
クラスにメソッドを定義するときはdef文を記述する

```python
class #クラス名:
    def #メソッド名(selfを含む引数):
        #メソッドのコード
```
メソッドを呼び出したときにselfにはインスタンス自体が渡される
(例)

```python
class Myclass:
    def __init__(self):#初期化メソッド定義
        self.value=0#インスタンスにアトリビュートを追加
        print("This is __init__() method!")
```
上で作成したMyclassクラスを使うとき

```python
i=Myclass()#変数にインスタンスを代入(インスタンスを作る)
i.value#インスタンスのアトリビュートを表示
```
(例2)

```python

class Volume:
    def __init__(self,width,height,depth):#初期化メソッドを定義
        self.width=width
        self.height=height
        self.depth=depth#アトリビュートを追加(selfにアトリビュートする)
    def content(self)
        return self.width*self*self.height*self.depth
```
上で作成したVolumeクラスを使うとき

```python

v=Volume(10,20,30)#インスタンスを作る
v.content()#インスタンスのメソッドを呼び出して体積を計算
```
メソッドの呼び出しにはselfに代入するインスタンスを指定していない
インスタンスからメソッドを呼び出すときは自動的に引数selfにはインスタンスをが代入され呼び出される。

インスタンスからアトリビュートを取り出すとき

```python
v.width
v.height
v.depth
v.width=20
# v.widthはself.widthと書いてある式と同じであることが確認できる
#インスタンスvはメソッド(defで定義されたもの)の中ではselfとして扱われる
#アトリビュートを書き換えることも可能
```
このようにアトリビュートを外部から書き換えることができたりクラスに定義されたメソッドも外部から利用することができてしまう

しかし外部からの不適切な利用によって思わぬ不具合を招くことがある。
こうした場合は外部から利用できなくすることも可能でありこのことを「カプセル化」という

【カプセル化の方法】
・アトリビュート名やメソッド名の先頭にアンダースコア_を1個つける
Pythonでは名前の先頭にアンダースコア_が1つ付いたアトリビュートやメソッドはク＋の内部だけでりようするためにあるというルールがある。

・アトリビュート名やメソッド名の先頭にアンダースコア_を2個つける
より厳しくアトリビュートやメソッドへの外部からのアクセスを制御したい場合アンダースコアを２つ付ける。するとクラスの外部からはアトリビュートにアクセスできなくなる。
しかし名前の前にアンダースコアを2つ付ける方法を使っても完全にアトリビュートやメソッドを隠すことはできない。
クラス内部で元の名前を使ってアトリビュートやメソッドを利用したとき内部で自動的に名前を変更してくれるがクラスの外部では自動的に名前を変更してくれない。
このようにして擬似的に外部からのアクセスを制御している。(名前の置き換えのルールを知っていればアトリビュートやメソッドにアクセスできてしまう)

【クラスの継承について】
継承とはすでにあるクラスをもとにして一部の機能だけを書き換えたり別のクラスを作成できる。
このとき元となるクラスをスーパークラス、それをもとにして作られたクラスをサブクラスという

【スーパークラスの指定の仕方】

```python
class クラス名(スーパークラス名1[,スーパークラス名2,...]):
```

【メソッドのオーバーライド】
クラスを継承するときスーパークラスのメソッドはサブクラスにそのまま受け継がれる。機能を変更したいメソッドだけ改めてサブクラスでメソッドを定義することを「メソッドのオーバーライド」という。
同名のメソッドをサブクラスで定義しなおすと上書きされる。未定義のメソッドはそのまま引き継がれる。

【組み込み関数super()を利用しスーパークラスの取得】
サブクラスにスーパークラスのメソッドを呼び出すことができる。
組み込み関数super()に引数を与えずに呼び出すと自動的にスーパークラスを呼び出せる。
引数を渡す場合は1つめにスーパークラスを調べたいサブクラスのクラス名,2つ目はインスタンス(self)を渡す。
⇒引数で指定したサブクラスのスーパークラス名を返す。

【スロットとプロパティ】
スロットはアトリビュートの追加を制限することができる

```python
class Limit:
    __slots__=['a','b']#a,bでしかアトリビュート作成することはできない
    def __init__(self):

i=Limit()
i.a=1
i.a
1
i.b=2
i.b
2
i.c
#error発生
```

インスタンスの持つデータ(アトリビュート)を直接操作するのを避けるためにインスタンスのデータ(アトリビュート)を変更したり参照したりするための専門のメソッドを作ることがある。
プロパティはデータ(アトリビュート)を設定するメソッドのセッター、データ(アトリビュート)を取り出すメソッドのゲッターを定義するための機能。アトリビュートにたいして代入や参照を行うとセッター、ゲッターに自動的に振り分けられるようになる。
プロパティの定義

```python
property([ゲッター[,セッター]])
```

【組み込み型を継承する】
組み込み型を継承して新しいクラスを作ることができる

（例）
ディクショナリ型を継承
ディクショナリ型のオブジェクトのキーにはいろいろなオブジェクトを利用することができるが文字列のみをキーとして設定できるディクショナリを作成する。
__setitem__()メソッドは引数として渡されたオブジェクトをキーとしてせっていする。ここでキーの方が文字列以外ならエラーが発生するようにする

```python

class StrDict(dict):#ディクショナリ型を継承してクラス作成
    def __init__(self):
        pass
    def __setitem__(self,key,value):#特殊メソッドをオーバーライド
        if not isinstance(key,str):
　　　　　#keyが文字列でない場合エラー　isinstance()関数を使って引数の型を制限
            raise ValueError("Key must be str or unicode")
        dict.__setitem__(self,key,value) #キーが文字列であるときスーパークラスの特殊メソッドを呼び出しkeyと値を設定

```
【参考文献】
・柴田敦『みんなのPython第4版』SB Creative