見出し画像

Python資格取得への道のり 19日目

今日でクラス・オブジェクトを終わらせていきます。

・多重継承

class Person(object):
   def talk(self):
       print('talk')


class Car(object):
   def run(self):
       print('run')

class PersonCarRobot(Person, Car):
   def fly(self):
       print('fly')


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

#talk
#run
#fly

このようにPersonCarRobotクラスでは、PersonもCarも両方のクラスを継承したこととなる。

継承していないメソッドも使用できる。

class Person(object):
   def talk(self):
       print('talk')

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


class Car(object):
   def run(self):
       print('run')

class PersonCarRobot(Person, Car):
   def fly(self):
       print('fly')


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

#talk
#person_run
#fly

なぜこの出力結果になったのかというと、原因は多重継承。
「class PersonCarRobot(Person, Car):」引数が左にある方が優先されるためメソッド名が被ったら優先順位が発動する。

・クラス変数

class Person(object):

   def __init__(self, name):
       self.kind = 'human'
       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

Personの引数によって名前が変わりますが、種類で定義している「human」はどちらの変わりません。この「human」に関しては、def __init__で定義しなくても良いのです。

つまり、defの外で定義できるクラス変数になれます。

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()

kind(つまりクラス変数)に関しては、「A」「 B」といったオブジェクトに捉われずに、どのオブジェクトでも使えます。

他にもこのような例があります。

class T(object):

    word= []

    def add_word(self, word):
        self.word.append(word)

t = T()
t.add_word('one')
t.add_word('two')
print(t.word)

#['one', 'two']

wordをリストとしてアイテムを追加していくクラスがあります。

しかし、これにアイテムを追加していくと別々のオブジェクトなのにリストのアイテムは初期のものも取り込んでいってしまいます

class T(object):

    word= []

    def add_word(self, word):
        self.word.append(word)

t = T()
t.add_word('one')
t.add_word('two')

s = T()
s.add_word('three')
s.add_word('four')
print(s.word)

#['one', 'two', 'three', 'four']

こういう場合はクラス変数を定義せず、def __init__を使用してリストを初期化すると良い。

class T(object):

    def __init__(self):
        self.word = []

    def add_word(self, word):
        self.word.append(word)

t = T()
t.add_word('one')
t.add_word('two')
print(t.word)

s = T()
s.add_word('three')
s.add_word('four')
print(s.word)

#['one', 'two']
#['three', 'four']

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

・クラスメソッドとスタティックメソッド

class Person(object):

   kind = 'human'

   def __init__(self):
       self.x = 100

a = Person()
print(a.x)
b = Person
print(b.x)

#AttributeError: type object 'Person' has no attribute 'x'
#aはオブジェクトですが、bはオブジェクトではないためエラーが返ってくる。

しかし、「x」ではなく「kind」にするとどうなるのか。

class Person(object):

   kind = 'human'

   def __init__(self):
       self.x = 100

a = Person()
print(a.kind)
b = Person
print(b.kind)

#human
#human
#これはクラス変数が定義されているので出力される。

オブジェクトが生成されるとinitが実行される。

class Person(object):

   kind = 'human'

   def __init__(self):
       self.x = 100

   def what_is_your_kind(self):
       return self.kind

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

#エラー

これも同様にbはオブジェクトではないので、エラーが返ってくる。

では、bも同じようにhumanを表示するにはどうすればいいのか。

それは、「クラスメソッド」を使うこと

class Person(object):

   kind = 'human'

   def __init__(self):
       self.x = 100

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

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

#human
#human

このクラスメソッド(@classmethod)はPersonクラスのメソッドであることを定義するもの。

このクラスメソッドを利用してメソッドにアクセスすることができる。例えオブジェクトじゃなくても。。。

クラスメソッドはselfを使わないので注意。

またクラスメソッドではなく、スタティックメソッドもある。

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())

print(Person.kind)
print(Person.what_is_your_kind())

Person.about(100)

#human
#human
#human
#about human 100

スタテックメソッドの部分は下記であり、引数を与えている。

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

実はこのスタテックメソッドはクラス外に書いても全く問題ないが、関連性を関連性を加味したうえでPersonクラス内に記載している。

・特殊メソッド

クラス・オブジェクトの最後のレッスン

__(アンダースコア)が前後2個あるものが特殊メソッド。具体的には下記

class Word(object):

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

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

w =Word('test')
print(w)

#Word!!!!!

文字列としてwを扱った場合、__str__の内容が実行されるため「Word!!!!!!」となる。

他にも

class Word(object):

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

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

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

w =Word('test')
print(len(w))

#4

となるものがある。

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()

w = Word('test')
w2 = Word('super')

print(w + w2)

#testsuper

__add__を使い、2つのクラスを足すこともできる。
この特殊メソッドが呼ばれたトリガーは「print(w + w2)」であり、この中に「+」があるからだ。

他にも

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('test')
w2 = Word('super')

print(w == w2)

#False

このトリガーは「print(w == w2)」の「==」であり、__eq__を呼び出したこととなる。

ちなみに「def __eq__(self, word):」がない場合は、例え引数に同じものを入れたとしても、「True」にはならない。

それは「w」と「w2」が異なるオブジェクトだからである
(print(id(w))とprint(id(w2))をすれば数値が異なることが分かる)

特殊メソッドはたくさんあるが、よく使われるのは「__str__」なので覚えておくこと。

今日のまとめ

今日はここまで!

クラスまで終えるのに時間をかけ過ぎてしまいました。
記憶がない。。。
とりあえず、明日からは座学を詰め込んでいきます。
いったんはお疲れ様でした。

この記事が気に入ったらサポートをしてみませんか?