今さらPython3 (39) - Classを作る
第6章に入ります。
- 作者: Bill Lubanovic,斎藤康毅,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
classの定義
本に倣って、ステップ・バイ・ステップで行きますか。
>>> class Person(): ... pass ... >>> someone = Person() >>> someone <__main__.Person object at 0x1020894a8> >>>
この本でも、空っぽの例外クラスを作ったので、全く初めてではないよね。
>>> class Person(): ... def __init__(self): ... pass ... >>> someone = Person()
__init__は初期化用のメソッドで、selfが第1引数に来るのはお約束。
>>> class Person(): ... def __init__(self, name): ... self.name = name ... >>> someone = Person() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: __init__() missing 1 required positional argument: 'name' >>>
nameといパラメータを追加したものがこれ。わざと引数を渡さずに呼んでみたら怒られた。当たり前だね。
>>> hunter = Person('Elmer Fudd') >>> hunter.name 'Elmer Fudd'
今度は名前を受け渡して、きちんとインスタンス化されましたとな。めでたしめでたし。
>>> print('The mighty hunter: ', hunter.name) The mighty hunter: Elmer Fudd >>>
__init__を持つことは必須ではないけど、他のインスタンスと区別するためのロジックを放り込む場と考えれば難しい話じゃない。普通インスタンス化する事を前提に考えれば、ほぼ必要だと思って間違いない。
継承
お父さん(お母さん)から引き継いで、必要なところだけ付け加えたり書き換えたりするのが継承の考え方。
>>> class Car(): ... pass ... >>> class Yugo(Car): ... pass ... >>> give_me_a_car = Car() >>> give_me_a_yugo = Yugo() >>>
昔、初めてオブジェクトの概念を学習したときに、どうしていつも車の例なんだろうと不思議に思ったんだけど、この例でも早速出てきましたね。Yugo is Car, but Car is not Yugoという関係が成り立ちますみたいなのも定番の説明。
継承して、親の属性をそのまま使って見ましょうと。
>>> give_me_a_yugo = Yugo() >>> give_me_a_yugo.exclaim() I'm a Car! >>> give_me_a_car = Car() >>> give_me_a_car.exclaim() I'm a Car! >>>
本の順番と逆に試したのは、子どもを先にインスタンス化しても問題なく使えることを念のため確認したかったから。class Yugoの中にはexclaim()は定義されていないけど、class Carから継承しているので普通に使えるよね。
オーバーライド
親から引き継いだモノを自分のモノにしちゃうと言うのがオーバーライド。
>>> class Car(): ... def exclaim(self): ... print("I'm a Car!") ... >>> class Yugo(Car): ... def exclaim(self): ... print("I'm Yugo! Much like a Car, but more Yugo-ish.") ... >>> give_me_a_car = Car() >>> give_me_a_yugo = Yugo() >>> give_me_a_car.exclaim() I'm a Car! >>> give_me_a_yugo.exclaim() I'm Yugo! Much like a Car, but more Yugo-ish. >>>
同じ関数で違う処理を書いているからオーバーライド。
>>> class Yugo(Car): ... def exclaim(self): ... super(Yugo, self).exclaim() ... print("To tell the truth, I am Yugo!") ... >>> give_me_a_yugo = Yugo() >>> give_me_a_yugo.exclaim() I'm a Car! To tell the truth, I am Yugo! >>>
確か親クラスのロジックを実行してからさらに追加するみたいなオーバーライドも出来るなと思い出してやってみたのが上のやつ。
話が逸れたので、本のサンプルに戻る。
>>> class Person(): ... def __init__(self, name): ... self.name = name ... >>> class MDPerson(): ... def __init__(self, name): ... self.name = 'Doctor ' + name ... >>> class JDPerson(): ... def __init__(self, name): ... self.name = name + ", Esquire" ... >>> person = Person('Fudd') >>> doctor = MDPerson('Fudd') >>> lawyer = JDPerson('Fudd') >>> print(person.name) Fudd >>> print(doctor.name) Doctor Fudd >>> print(lawyer.name) Fudd, Esquire >> >
メソッドの追加
オーバーライドだけじゃなくて、子クラスにメソッドの追加もできるという確認。
>>> class Car(): ... def exclaim(self): ... print("I'm a Car!") ... >>> class Yugo(Car): ... def exclaim(self): ... print("I'm a Yugo! Much like a Car, but more Yugo-ish.") ... def need_a_push(self): ... print("A littel help here?") ... >>> give_me_a_car = Car() >>> give_me_a_yugo = Yugo() >>> give_me_a_yugo.need_a_push() A littel help here? >>> give_me_a_car.need_a_push() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Car' object has no attribute 'need_a_push' >>>
親からはneed_a_pushを呼べない。そりゃそうだ。
ここで来たのかsuperよ
あと先を見ずにsuperを試しちゃったけど、ここでもう1回確認。
>>> class Person(): ... def __init__(self, name): ... self.name = name ... >>> class EmailPerson(Person): ... def __init__(self, name, email): ... super().__init__(name) ... self.email = email ... >>>
こっちの方が、それらしいサンプルだね。さっき、superを使ったときに自分の名前をしてして微妙な感じがしていたけど、super()と引数なしでやれば良かった。
>>> bob = EmailPerson('Bob Frapples', 'bob@frapples.com') >>> bob.name 'Bob Frapples' >>> bob.email 'bob@frapples.com' >>>