Python "class" チートドキュメント

備忘録です。もっと書くことはありますが最低限の必要事項をまとめてみました。

# Class基本形
```python

#================
#基本形
#================
class Cat:
 def __init__(self, name,gender,age): # 初期化するメソッド
     self.name = name # インスタンス
     self.gender = gender # インスタンス
     self.age = age # インスタンス


a_cat = Cat("tama","M",2) # オブジェクトを生成
print(a_cat) # →object
print("cat name:",a_cat.name) # →tama

```

# カプセル化
2つの概念と目的がある
* オブジェクトによって複数の変数とメソッドをまとめること
* データをクラス内に保存して外から見えないようにする

### プライベート変数とパブリック変数
Pythonにはプライベート変数がありませんが、**アンダースコア`_`の個数で表現させることができます**

クラス内変数・メソッド | 役割 | 
--- | --- |
`self.hoge`・`def hoge()` | クラス外からもアクセス可能 | 
`self._hoge`・`def _hoge()` | クラス外からアクセス可能だが、アクセスしてほしくない |
`self.__hoge`・`def __hoge()`| クラス外からアクセス不可 |


:::note info
`self.__hoge`・`def __hoge()`にどうしてもアクセスしたい場合は
`_class__hoge`を追加することで参照することができます。
:::

実際のコード例
```python
class Cat:
 def __init__(self,name,gender,age):
     self.name = name # クラス外からもアクセス可能
     self._gender = gender # クラス外からアクセス可能だが、慣例的にアクセスしてほしくない
     self.__age = age # クラス外からアクセス不可
 
 def info_name(self): # クラス外からもアクセス可能
     print(f"この猫は名前は{self.name}です")
     return 0
 
 def _name_change(self,rename): # クラス外からアクセス可能だが、慣例的にアクセスしてほしくない
     self.name = rename
     print(f"この猫は名前は{self.name}です")
     return 0
 
 def __name_change2(self,rename): # クラス外からアクセス不可
     self.name = rename
     print(f"この猫は名前は{self.name}です")
     return 0
 

a_cat = Cat("tama","M",2) # オブジェクトを生成

# クラス内変数
print("cat name:",a_cat.name) # →cat name: tama
print("cat gender:",a_cat._gender) # →cat gender: M
print("cat age:",a_cat.__age) # →AttributeError: 'Cat' object has no attribute '__age'

# クラス内メソッド
a_cat.info_name() # →この猫は名前はtamaです
a_cat._name_change("pochi") # →この猫は名前はpochiです
a_cat.__name_change2("mike") # →AttributeError: 'Cat' object has no attribute '__name_change2'. Did you mean: '_name_change'?

#例外的に参照したい場合
print("cat age:",a_cat._Cat__age) # →cat age: 2
a_cat._Cat__name_change2("mike") # →この猫は名前はmikeです

```
(参考)アンダースコアの扱いのまとめ

https://mako-note.com/ja/python-underscore/

# 継承
Pythonにおいて、継承を利用することで新しいクラスを作成することができます。新しいクラスは親クラスの機能を引き継ぎつつ、独自の機能を追加することができます。

```python
class 子クラス名(親クラス名):
    # 以降、子クラスのコードを記述

```

### 親クラスからメソッドを呼び出し

```python
class Cat:
 "親クラス"
 def __init__(self,name,gender,age):
     self.name = name 
     self.gender = gender 
     self.age = age 
 
 def show_info(self):
        print(f"名前: {self.name}, 性別: {self.gender}, 年齢: {self.age}")

class Scottish_Fold(Cat): 
    "子クラス"
    def __init__(self, name, gender, age):
        # 親クラスの__init__メソッドを呼び出し
        super().__init__(name, gender, age)
        self.kinds = "スコティッシュホールド"

    

a_cat = Cat("tama","M",2)
a_cat.show_info() # 名前: tama, 性別: M, 年齢: 2

s_cat = Scottish_Fold("maruo","M",3)
s_cat.show_info() # →名前: maruo, 性別: M, 年齢: 3
print(s_cat.kinds) # →スコティッシュホールド
```

### オーバーライド
子クラスでは親クラスのメソッドをオーバーライド（上書き）することができます。これにより、親クラスのメソッドを改良することができます。`super()`を使うことで親クラスのメソッドを呼び出します。

```python
class Cat:
 "親クラス"
 def __init__(self,name,gender,age):
     self.name = name 
     self.gender = gender 
     self.age = age 
 
 def show_info(self):
        print(f"名前: {self.name}, 性別: {self.gender}, 年齢: {self.age}")

class Scottish_Fold(Cat): 
    
    def __init__(self, name, gender, age):
        # 親クラスの__init__メソッドを呼び出し
        super().__init__(name, gender, age)
        self.kinds = "スコティッシュホールド"
    
    #----親クラスのメソッドを書き換える----
    def show_info(self):
        # 親クラスのshow_infoメソッドを呼び出し
        super().show_info()
        print(f"猫の種類: {self.kinds}")
    

a_cat = Cat("tama","M",2)
a_cat.show_info() # 名前: tama, 性別: M, 年齢: 2

s_cat = Scottish_Fold("maruo","M",3)
s_cat.show_info() 
# →名前: maruo, 性別: M, 年齢: 3
# →猫の種類: スコティッシュホールド
```



# 用語

#### インスタンス変数
オブジェクトに属する変数

#### メソッド・スイート
classのスイート(状態)
```python

class Cat:
    #============
    #ここがスイート
    #============
    pass
        
```
#### `__int__`メソッド
インスタンス変数を最初に定義する特殊なメソッド

#### self
インスタンスの生成・参照に使う
`self.[変数名]=[値]`
`print(self.[変数名])`
など