Python基礎備忘録その3～オブジェクト指向について～

#記事概要
Pythonを少しでも読めるようになってみようと思い、[参考書](#参考文献)に沿って学習した備忘録になります。
Javaと比較して自身が気になった点、便利と感じた点をまとめております。
その1は[こちら](https://qiita.com/tk10/items/12a3c09b0c0f9a1499f7)
その2は[こちら](https://qiita.com/tk10/items/85fedb9d97c66be0c354)
<strong>※かなり基礎的な内容になります。</strong>

#クラス
クラスの概念自体はそこまで大きく違わない認識です。
クラス定義方法については、例を下記に記載してみます。

####例
```java:java
class SampleClass {
    //クラス処理
}
```

```python:python
class SampleClass:
    #クラス処理
```

#インスタンス化
クラスをインスタンス化する。
扱いはJavaとほとんど変わらない。~~はず~~

```java:java
SampleClass sClass = new SampleClass();
```

```python:python
sClass = SampleClass()
```

#アトリビュート
Javaで言うインスタンス変数のようなもの（？）。
インスタンスに対してアトリビュートを追加できる。

```python:python
sClass.attr = "あとりびゅーと"
print(sClass.attr)
>>あとりびゅーと
```

#クラスのメソッド定義
クラスメソッドに引数を追加する場合には、第一引数にselfを追加する。

>selfを使うとインスタンス自体を操作できる

####例
```java:java
class SampleClass {
    int counter = 0;
    
    int count(int a) {
        counter += a;
    }
}
```

```python:python
class SampleClass:
    counter = 0;

    def count(self, a):
        self.counter += a
```

#初期化メソッド
初期化メソッドは`__init__`(特殊メソッド)を使用する。

####例
```java:java
publiv class Human {
    String name;
    String birthday;

    public Human(String name, String birthday) {
        this.name = name;
        this.birthday = birthday;
    }
}
```

```python:python
class Human:    
    def __init__(self, name = None, birthday = None):
        self.__name = name
        self.__birthday = birthday
```

#カプセル化
カプセル化を行うにはメソッドやアトリビュートの前に`__`(アンダースコア2つ)をつける。
`__`を付けることで外部からのアクセスを禁止することが出来る。
メソッドやアトリビュートの前に`_`(アンダースコア1つ)を付けた場合には慣習として、
「クラス内部でのみ使用するので、外部からアクセスしないでね」といった意味を持つ(らしい)。

※調べていたらアンダースコアは色々意味があるそうです。参考文献に調べた際の記事などリンク載せています。

<strong>追記</strong>
~~Pythonではgetter,setterを定義しないらしいです。~~
Pythonではget〇〇,set〇〇といったメソッドを定義することは非推奨のようです。
(属性へのアクセス方法はまた別にまとめるかもしれません)
今回の記事ではJavaと比較して、自分が理解しやすくするために、上記のような書き方でgetter,setterを定義しています。
ご了承ください。
アンダースコアの付け方、getter,setterを定義しない場合については、別途学習してまとめようかと考えています。


####例
```java:java
publiv class Human {
    private String name;
    private String birthday;

    public Human(String name, String birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public getName() {
        return this.name;
    }

    public getBirthday() {
        return this.birthday;
    }

    public setName(String name) {
        this.name = name;
    }

    public setBirthday(String birthday) {
        this.birthday = birthday;
    }
}
```

```python:python
class Human:
    def __init__(self, name = None, birthday = None):
        self.__name = name
        self.__birthday = birthday
    
    def getName(self):
        return self.__name

    def getBirthday(self):
        return self.__birthday

    def setName(self, name):
        self.__name = name

    def setBirthday(self, birthday):
        self.__birthday = birthday    
```

#継承
Pythonは<strong>多重継承が可能</strong>。
多重継承する場合には、`,`で区切ってクラス名を指定する。

####例
```java:java
public class SuperMan extends Human {
    private String ability;

    public getAbility() {
        return this.age;
    }

    public setAbility(String ability) {
        this.ability = ability;
    }

```

```python:python
class SuperMan(Human): #多重継承の場合SuperMan(Human, Man)のような感じで定義する
    def getAbility(self):
        return self.__ability

    def setAbility(self, ability = None):
        self.__ability = ability
```

#スロット
アトリビュートの追加を制限することが出来る特殊メソッド
`__slots__ = [アトリビュート名1, アトリビュート名2, ...]`

>メモリの使用効率をよくする

```python:python
class Profile:
    __slots__ = ['height', 'weight', 'bloodType']

    def __init__(self, bloodType = None):
        self.bloodType = bloodType

a = Profile('A')
print(a.bloodType)
>>A

#slotsに定義されているアトリビュート
a.height = 170
a.weight = 60

a.constellation = 'Aries'
>>エラーが発生する
```

#プロパティ
getter,setterを簡単に定義するための組み込み関数。
非公開のアトリビュートへのアクセス制御を簡単に行う。
`property(getterメソッド名, [setterメソッド名])`

```python:python
class Human:
    def __init__(self, name = None):
        self.__name = name
    
    def getName(self):
        return self.__name

    def setName(self, name):
        self.__name = name

    propName = property(getName, setName)

#代入を行うと、propertyで設定したsetterが動作する
propName = 'takeshi'
#取り出しを行うと、propertyで設定したsetterが動作する
print(propName)
>>takeshi
```

#あとがき
Pythonのデメリットについて調べると、実行速度の遅さが出てきました。
今回まとめた`__slots__`はそのデメリットを改善するために必要なことだと感じました。
Pythonらしい機能を適切に使えるよう理解を進めていきたいと思います。


#参考文献
<strong>参考書</strong>
柴田淳(2016)「みんなのPython 第4版」SBクリエイティブ株式会社

<strong>公式リファレンス</strong>
[Python公式リファレンス](https://www.python.org/)

<strong>データ型について</strong>
[Pythonの組み込みデータ型の分類表（ミュータブル等）](https://gammasoft.jp/blog/python-built-in-types/)

<strong>アンダースコアについて</strong>
[初学者のためのPython講座　オブジェクト指向編7　カプセル化](https://qiita.com/kotakahe/items/2e17231868d78b35639f)
[Lesson 12　クラスの定義 ― Python基礎文法入門](https://www.atmarkit.co.jp/ait/articles/1908/21/news126.html)
[pythonのアンダーバーこれなんやねん](https://qiita.com/kiii142/items/6879cb065ad4c5f0b901)