Python基本文法note（3）

#初めに
Pythonを勉強しています。
メモとして作成しましたので、多少の誤字脱字があるかもしれません。

#オブジェクトとクラス
クラスは設計図で、インスタンスはその設計図を実体化したもの

オブジェクト指向とは、オブジェクト同士の相互作用として、システムの動作をとらえた考え方。

オブジェクト指向によって、考えられたのが、クラスやインスタンス。

##クラスの定義

~~~python
class Person(object):
    def say_something(self):
        print('hello')

#クラスを呼び出してオブジェクトを生成する
person = Person()
person.say_something()

>>>hello
~~~

##クラスの初期化とクラス変数

~~~python

class Person(object):
    #初期化と初期設定のイメージ
    def __init__(self):
        print('First')

    def say_something(self):
        print('hello')

person = Person()

>>>First

#selfがないと自分自身に値を保持させれない
class Person(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def say_something(self):
        print('hello')

person = Person('Mike')
>>>Mike

#関数内で呼び出す
class Person(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def say_something(self):
        print('I am {}. hello'.format(self.name))

person = Person('Mike')
person.say_something()

>>>Mike
>>>I am Mike. hello
~~~

##コンストラクタとデストラクタ
初期化して最初に呼ばれるオブジェクトがコンストラクタ
最後に呼ばれるオブジェクト

~~~python

class Person(object):
    def __init__(self, name):
        self.name = name
        print(self.name)

    def say_something(self):
        print('I am {}. hello'.format(self.name))

    def __del__(self):
        print('good bye')

person = Person('Mike')
person.say_something()

>>>Mike
>>>I am Mike. hello
>>>good bye
~~~

##クラスの継承
継承をしてコードを綺麗に書く

~~~python
class Car(object):
    def run(self):
        print('run')
#passは何もしないと言う意味
class ToyotaCar(Car):
    pass

class TeslaCar(Car):
    def auto_run(self):
        print('auto_run')
car = Car()
car.run()

toyota_car = ToyotaCar()
toyota_car.run()
print('##################')
tesla_car = TeslaCar()
#Carクラスを継承しているので実行できる
tesla_car.run()
tesla_car.auto_run()

>>>run
>>>run
>>>##################
>>>run
>>>auto_run

~~~

##クラスの継承メッソドのオーバーライドとsuperによる親のメソッドの呼びだし

~~~python

class Car(object):
    def __init__(self, model=None):
        self.model = model

    def run(self):
        print('run')

class ToyotaCar(Car):
    print('fast')

class TeslaCar(Car):
    def __init__(self, model='Model S', enable_auto_run=False):

        super().__init__(model)
        self.enable_auto_run = enable_auto_run

    def run(self):
        print('super fast')

    def auto_run(self):
        print('auto_run')

car = Car()
car.run()

toyota_car = ToyotaCar('Lexus')
toyota_car.run()
print('##################')
tesla_car = TeslaCar('Model S')
tesla_car.run()
tesla_car.auto_run()

>>>fast
>>>run
>>>run
>>>##################
>>>super fast
>>>auto_run
~~~


##プロパティーを使った属性の設定
プロパティーを使う場合はある条件の時に書き換えても良い場合

~~~python
class Car(object):
    def __init__(self, model=None):
        self.model = model

    def run(self):
        print('run')

class ToyotaCar(Car):
    print('fast')

class TeslaCar(Car):
    def __init__(self, model='Model S', enable_auto_run=False):

        super().__init__(model)
        self._enable_auto_run = enable_auto_run
#書き換えを行えない記述
    @property
    def enable_auto_run(self):
        return self._enable_auto_run 

    def run(self):
        print('super fast')

    def auto_run(self):
        print('auto_run')


teslaCar = TeslaCar('Model S')
print(tesla_Car.enable_auto_run)

>>>False

#k書き換えてもいい場合の記述
class Car(object):
    def __init__(self, model=None):
        self.model = model

    def run(self):
        print('run')

class ToyotaCar(Car):
    print('fast')

class TeslaCar(Car):
    def __init__(self, model='Model S', enable_auto_run=False):

        super().__init__(model)
        self._enable_auto_run = enable_auto_run

    @property
    def enable_auto_run(self):
        return self._enable_auto_run 

    @enable_auto_run.setter
    def enable_auto_run(self, is_enable):
        self._enable_auto_run = is_enable

    def run(self):
        print('super fast')
    def auto_run(self):
        print('auto_run')


tesla_Car = TeslaCar('Model S')
#先にTrueを入れる
tesla_Car.enable_auto_run = True
print(TeslaCar.enable_auto_run)

>>>True

~~~


##クラスを構造体として扱う時の注意点

・クラスを生成して後から値を入れる場合はクラスの中身を確認しないとバグにつながる

##ダックタイピング

~~~python

class Person(object):
    def __init__(self, age=1):
        self.age = age

    def drive(self):
        if self.age >= 18:
            print('ok')
        else:
            raise Exception('No drive')

class Baby(Person):
    def __init__(self, age=1):
        if age < 18:
            super().__init__(age)
        else:
            raise ValueError

class Adult(Person):
    def __init__(self, age=18):
        if age >= 18:
            super().__init__(age)
        else:
            raise ValueError

baby = Baby()
adult = Adult()

class Car(object):
    def __init__(self, model=None):
        self.model = model
    def run(self):
        print('run')
    def ride(self, person):
        person.drive()

car = Car()
car.ride(adult)

>>>ok

~~~

##抽象クラス

~~~python
import abc

class Person(metaclass=abc.ABCMeta): 
    def __init__(self, age=1):
        self.age = age

    @abc.abstractclassmethod
    def drive(self):
        pass


class Baby(Person):
    def __init__(self, age=1):
        if age < 18:
            super().__init__(age)
        else:
            raise ValueError
    def drive(self):
        raise Exception('No drive')

class Adult(Person):
    def __init__(self, age=18):
        if age >= 18:
            super().__init__(age)
        else:
            raise ValueError

    def drive(self):
        print('ok')


baby = Baby()
adult = Adult()

>>>ok
~~~

##多重継承

~~~python
class Person(object):
    def talk(self):
        print('talk')
    def run(self):
        print('parson run')


class Car(object):
    def run(self):
        print('car run')
#左側に入れた引数が先に実行する
class PersonCarRobot(Car, Person):
    def fly(self):
        print('fly')

parson_car_robot = PersonCarRobot()
parson_car_robot.talk()
parson_car_robot.run()
parson_car_robot.fly()

>>>talk
>>>car run
>>>fly

~~~

##クラス変数
全てのオブジェクトで共有される

~~~python
class Person(object):

    kind = 'human'

    def __init__(self, name):
        self.name = name

    def who_are_you(self):
        print(self.name, self.kind)

a = Person('A')
a.who_are_you()
b = Person('B')
b.who_are_you()

>>>A human
>>>B human
~~~

##クラスメソッドとスタティックメソッド
オブジェクトではなくてもクラスメソッドを呼び出すことができる


~~~python

class Person(object):

    kind = 'human'

    def __init__(self):
        self.x = 100

    @classmethod
    def what_is_your_kind(cls):
        return cls.kind

    @staticmethod
    def about(year):
        print('about human {}'.format(year))

a = Person()
print(a.what_is_your_kind())

b = Person()
print(b.what_is_your_kind())

Person.about(1998)

>>>human
>>>human
>>>about human 1998

~~~

##特殊メソッド

~~~python
class Word(object):

    def __init__(self, text):
        self.text = text

    def __str__(self):
        return 'Word!!!!!!!!!!!'

    def __len__(self):
        return len(self.text)

    def __add__(self, word):
        return self.text.lower() + word.text.lower()

    def __eq__(self, word):
        return self.text.lower() == word.text.lower()

w = Word('text')
w2 = Word('text')

print(w == w2)

~~~