それでは下記の記事の続きをやっていこう!
👇前回までは<モジュール編>ということでコードを読み書きする上で必要な知識や知っておいて欲しいことをまとめました。
今回は<オブジェクト指向編>になります。一緒に勉強していこう🤓
Contents
- 1 オブジェクト指向とは
- 2 クラス(class)
- 3 インスタンス変数とクラス変数(instance/class variable)
- 4 スタティックメソッド(static method)
- 5 クラスメソッド(class method)
- 6 名前修飾(name mangling)
- 7 getterとsetter
- 8 プロパティデコレータ(property decorator)
- 9 継承(inheritance)
- 10 継承時のコンストラクタ
- 11 オーバーライド(overriding)
- 12 Polymorphism(ポリモーフィズム)
- 13 DuckTyping(ダックタイピング)
- 14 Docstringの書き方
オブジェクト指向とは
✅オブジェクト指向: OOP(Object Oriented Programming)
✅Pythonはオブジェクト指向のプログラミング言語
✅データのまとまりや、機能を備えた関数をプログラミングする際の考え方や概念
クラス(class)
✔️classの定義はsnake_caseではなくCamelCaseをとる
✔️class Person: ↔︎class Person(object):は同義⇨これはobjectクラスの継承をしている
(objectはpythonにデフォルトで設置されているオブジェクトであり、書いても書かんででも良い)
✔️def __init__(self): にコンストラクタ(最初の設定)を書いていく
✔️classを呼び出すことをインスタンス化するといい、<変数>(⬅️インスタンス名) = <class名>(引数)の形をとる
✔️class内のコンストラクタを呼び出すには<インスタンス化した変数>.<呼び出したい変数>とする
ex.1)Personというクラスを作り、インスタンス化して属性とメソッドを呼び出す
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# <Personのクラスを作っていく> class Person: # __init__(__new__)のことをconstructorと呼ぶ # インスタンス化される時に呼ばれる関数 def __init__(self, name, age, gender): # クラス自身(self)の属性である名前(name)、年齢(age)、性別(gender)に # 引数で渡ってくる各々の値が格納されるイメージ self.name = name # 右辺がインスタンス化によって渡ってくるオブジェクト self.age = age self.gender = gender # methodを定義 def walk(self): print(f"{self.name} is walking.") def run(self): print(f"{self.name} is running.") # インスタンス化 hiroki = Person("Hiroki", 28, 'male') misako = Person("Misako", 28, 'female') ryuki = Person("Ryuki", 25, 'male') # インスタンスの属性(インスタンス変数)にアクセスできる # .(ドット)に続けてアクセス可能 print(hiroki.name) # Hiroki print(hiroki.age) # 28 print(hiroki.gender) # male # 定義したmethodにアクセス # インスタンスに紐づいたmethodをインスタンスメソッドという hiroki.walk() # Hiroki is walking. misako.walk() # Misako is walking. hiroki.run() # Hiroki is running. misako.run() # Misako is running. |
ex.2) Carクラス(参考)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# ex.) Carのクラスを作ってみる class Car(object): def __init__(self, model_name, mileage, manufacturer): self.model_name = model_name self.mileage = mileage self.manufacturer = manufacturer def gas(self): print(f"{self.manufacturer}の{self.model_name} (燃費:{self.mileage}) アクセルON") def brakes(self): print("{0.manufacturer}の{0.model_name} (燃費:{0.mileage}) ブレーキON".format(self)) if __name__ == "__main__": prius = Car("Prius", 20, "TOYOTA") land_cruiser = Car("Land Cruiser", 4, "TOYOTA") print(prius.mileage) # 20 print(land_cruiser.mileage) # 4 prius.gas() # TOYOTAのPrius (燃費:20) アクセルON prius.brakes() # TOYOTAのPrius (燃費:20) ブレーキON land_cruiser.gas() # TOYOTAのLand Cruiser (燃費:4) アクセルON land_cruiser.brakes() # TOYOTAのLand Cruiser (燃費:4) ブレーキON |
インスタンス変数とクラス変数(instance/class variable)
✔️インスタンス変数:インスタンスに紐付いている変数
・<インスタンス名>.<インスタンス変数>で変数にアクセスする
✔️クラス変数:クラスに紐付いている変数
・<インスタンス名>.<クラス変数>で変数にアクセスできる。しかし上書きしないように注意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# クラス変数について(num_legsを定義) class Person: num_legs = 2 def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender # クラス変数をメソッドで使うことができる(Person.numlegs) def walk(self): print(f"{self.name} is walking...with {Person.num_legs}legs!") def run(self): print(f"{self.name} is running...with {Person.num_legs}legs!") # インスタンス化 hiroki = Person("Hiroki", 28, 'male') misako = Person("Misako", 28, 'female') # クラス変数にアクセス print(hiroki.num_legs) # 2 print(misako.num_legs) # 2 print(Person.num_legs) # 2 print(hiroki.walk()) # Hiroki is walking...with 2legs! print(hiroki.run()) # Hiroki is running...with 2legs! |
ex.) クラス変数を使った例(銀行口座の名前、口座番号、預金額、預かり、引き出しができるシステム)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
class Account: # 口座番号の初期値設定(クラス変数) account_number = 0 def __init__(self, name, balance): self.name = name self.balance = balance #クラス変数の値をコンストラクタに定義 self.account_number = Account.account_number #インスタンス化される度にaccount_numberが更新される Account.account_number += 1 def withdrow(self, money): # 引出額<預金額の場合、引出額=預金額-引き出し額 if money < self.balance: self.balance -= money self.show_balance() # 引出額>預金額の場合は、プリント else: print("残高が不足しています。") def deposit(self, money): # 預金額=預金額+預かり額 self.balance += money self.show_balance() def show_balance(self): print(f"口座名:{self.name}、口座番号:{self.account_number}、残高:{self.balance}") my_account = Account(name="my_account", balance=1000) my_account.withdrow(900) # 口座名:my_account、口座番号:0、残高:100 my_account.deposit(1000) # 口座名:my_account、口座番号:0、残高:1100 |
スタティックメソッド(static method)
✔️インスタンスに紐づかないmethod
✔️@staticmethodデコレータを使う
✔️主にクラス内で便利関数のように使用
✔️引数にselfを取らない
✔️クラスからアクセスして呼び出す(<Class>.<staticmethod>())
✔️クラスの情報を使う時はクラスメソッドを使う
static methodの基本的な使い方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class MyClass: def mymethod(self): print("This is normal method") @staticmethod def mystaticmethod(): print("This is staticmethod") # 一般的なインスタンスメソッドの呼び出し方 myclass = MyClass() myclass.mymethod() # This is normal method # スタティックメソッドの呼び出し方 MyClass.mystaticmethod() # This is staticmethod |
ex.) static methodを使った例(先ほどの銀行口座の例に取引(trainsaction)を記録する仕組みを追加)
※取引(transaction)として保持する情報は下記としdictionaryとして保持、list型でインスタンス変数に保持させる。
・withdrow/depositの金額
・新しい残高
・日時(日時を作る関数はstaticmethodで作る)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
import time class Account: account_number = 0 def __init__(self, name, balance): self.name = name self.balance = balance self.account_number = Account.account_number Account.account_number += 1 # 取引情報の初期値を定義 self.transaction_history = [] def withdrow(self, money): if money < self.balance: self.balance -= money self.show_balance() # 取引額をtransaction_historyリストに追加 self.add_transaciton(-money) else: print("残高が不足しています。") def deposit(self, money): self.balance += money self.show_balance() # 取引額をtransaction_historyリストに追加 self.add_transaciton(money) def show_balance(self): print(f"口座名:{self.name}、口座番号:{self.account_number}、残高:{self.balance}") # ディクショナリー(transaction)に必要項目を格納し、transaction_historyリストにappendする def add_transaciton(self, money): transaction = { 'withdraw/deposit': money, 'new_balance': self.balance, # スタティックメソッドなので、クラスからアクセスし呼び出す 'time': Account.date() } self.transaction_history.append(transaction) #日時を返す関数をスタティックメソッドとして定義 @staticmethod # デコレータ def date(): current_time = time.localtime() return "{0.tm_year}年{0.tm_mon}月{0.tm_mday}日{0.tm_hour}時{0.tm_min}分".format(current_time) def show_transaction_history(self): for transaction in self.transaction_history: transaction_list = [] # transaction_str = ""とすることもできるが、immutableな型にfor文はNG for k, v in transaction.items(): transaction_list.append(f"{k}: {v}") print(", ".join(transaction_list)) my_account = Account(name="my_account", balance=1000) my_account.withdrow(300) # 口座名:my_account、口座番号:0、残高:100 my_account.deposit(500) # 口座名:my_account、口座番号:0、残高:1100 my_account.show_transaction_history() # withdraw/deposit: -300, new_balance: 700, time: 2021年6月28日22時22分 # withdraw/deposit: 500, new_balance: 1200, time: 2021年6月28日22時22分 |
クラスメソッド(class method)
✔️インスタンスに紐づかないmethod
✔️@classmethodデコレータで明示
✔️クラス内で便利関数のように使う
✔️第一引数に”cls“を取り、クラスの情報にアクセスすることが出来る
✔️クラスからアクセスしてcallする(<Class>.<classmethod>)
✔️クラスの情報を使わない場合はスタティックメソッドを使う
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
class MyClass: classmethod_count = 0 def mymethod(self): print("This is normal method") @staticmethod def mystaticmethod(): print("This is staticmethod") @classmethod def myclassmethod(cls): cls.classmethod_count += 1 print(f"This is classmethod, count is {cls.classmethod_count} now.") # 一般的なインスタンスメソッドの呼び出し方 myclass = MyClass() myclass.mymethod() # This is normal method # スタティックメソッドの呼び出し方 MyClass.mystaticmethod() # This is staticmethod # クラスメソッドの呼び出し方 MyClass.myclassmethod() # This is classmethod, count is 1 now. MyClass.myclassmethod() # This is classmethod, count is 2 now. |
ex.) class methodを使った例(生年月日を引数にクラスメソッドを実行すると年齢が返ってくる)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import time class Person: def __init__(self, name, age): self.name = name self.age = age # 引数に生年月日を入力すると年齢で返すクラスメソッドを作成する @classmethod def create_from_dob(cls, name, year, month, date): today = time.localtime() # タプルの比較演算() #(today.tm_mon, today.tm_mday) < (month, date)→ True:1, False:0 age = today.tm_year - year - ((today.tm_mon, today.tm_mday) < (month, date)) # clsはPerson,このようなメソッドをファクトリーメソッドという return cls(name=name, age=age) hiroki = Person('Hiroki', 20) misako = Person.create_from_dob('Misako', 1993, 11, 1) print(hiroki.name) # Hiroki print(misako.age) # 27 |
名前修飾(name mangling)
✔️private変数は、クラス外からアクセスできない変数(↔︎public変数)
✔️Pythonには”private変数”はない
✔️変数名の接頭辞に”_”(アンダースコア)を付けることでnon public風にすることが出来る(暗黙の了解であり強制力はない)
✔️”__“(アンダースコア2つ)を変数名に付けることで名前修飾する()
名前修飾された変数名は_<Class>__<atttribute>のような形を取る(ex. _Account__balance)
結果としてprivate変数のような役割を付けることが出来る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
class Account: def __init__(self, balance): # _balanceとすることで、この変数はアクセス不可を明示することが出来る # __balanceとすることで、名前修飾をした結果、private変数の振る舞いをする self.__balance = balance def deposit(self, money): self.__balance += money self.show_balance() def withdrow(self, money): if self.__balance < money: print("残高不足です") else: self.__balance -= money self.show_balance() def show_balance(self): print(f"残高は{self.__balance}円です") myaccount = Account(1000) myaccount.deposit(100) # 残高は1100円です myaccount.withdrow(600) # 残高は500円です # 変数__balanceを新しく作ってそこに格納している(そもそもやってはいけない) myaccount.__balance = -1000 print(myaccount.__balance) # -1000 #self.balanceで定義した名前修飾されている_Account__balanceを呼び出して確認 myaccount.show_balance() # 残高は500円です |
getterとsetter
✔️インスタンスからインスタンス変数にアクセスしたり、外部から値を代入するようなコードが走った時に制約をかけることが出来る(コードを確認して欲しいが、マイナスの値をageに代入するなど)
✔️propertyというビルドインファンクションにsetter,getter関数を引数に取ることでpropertyオブジェクトが生成される(<変数> = property(<setterの関数>, <getterの変数>))
✔️getterとsetterの引数となるインスタンス変数は必ず“_”(アンダースコア)を付け、non publicな変数とする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Person: def __init__(self, name, age): self.name = name self._age = age # getter def get_age(self): print("get_age called") return self._age # setter:インスタンスの宣言時にageにマイナスの値が入れられないような関数を定義する def set_age(self, age): print("set_age called") if age < 0: print("0以上の値を入れてください") else: self._age = age # propertyというビルトインファンクションにsetter,getter関数を引き数に取ると # propertyオブジェクトが生成される # インスタンスから年齢にアクセスしたり、誤った値を代入した時にget_age, set_ageが呼び出されて # 制御することが出来る age = property(get_age, set_age) hiroki = Person("Hiroki", 28) print(hiroki.age) # get_age called 28 hiroki.age = -10 # set_age called 0以上の値を入れてください |
プロパティデコレータ(property decorator)
✔️↑のsetter,getterの書き方よりもこちらの書き方が一般的(コメントに変更箇所の詳細を記入しているので確認してみて下さい。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
class Person: def __init__(self, name, age): self.name = name self._age = age # プロパティデコレータの宣言 @property #"set_age"⇨"age"とする def age(self): print("get_age called") return self._age # ageのsetterであることを宣言 @age.setter #"set_age"⇨"age"とする def age(self, age): print("set_age called") if age < 0: print("0以上の値を入れてください") else: self._age = age # ↓この書き方をする必要がなくなる # age = property(get_age, set_age) hiroki = Person("Hiroki", 28) print(hiroki.age) # get_age called 28 hiroki.age = -10 # set_age called 0以上の値を入れてください |
継承(inheritance)
✔️あるクラスを引数に新たなクラスを定義することで、そのクラスを継承して別のクラスを作ることが出来る
✔️super class(親クラス、基底クラス)の記述内容を引継ぎ、sub class(子クラス、派生クラス)として拡張することが出来る。
✔️継承は基本”is a”の関係になっている(ex. Carクラス、Priusクラス ⇨ Prius is a Car)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# Animalクラスにname属性とrunメソッドを定義 class Animal(object): def __init__(self, name): self.name = name print("Animal class is called") def run(self): print(f"{self.name} is running.") # Dogクラスには何も定義しない class Dog(Animal): pass # Catクラスには何も定義しない class Cat(Animal): pass muku = Dog("muku") # Animal class is called michan = Cat("michan") # Animal class is called # Dogクラスには何も定義していないが、Animalクラスを継承したDogクラスを呼び出すことで # name属性を使うことが出来る print(muku.name) # muku print(michan.name) # michan # runメソッドも使うことが出来る。 muku.run() # muku is running. |
継承時のコンストラクタ
✔️親クラスのコンストラクタは、子クラスのinit関数内でsuper().__init()で呼び出すことが出来る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class Animal(object): def __init__(self, name): self.name = name print("Animal class is called") def run(self): print(f"{self.name} is running.") class Dog(Animal): def __init__(self, name): # <継承時のコンストラクタ> superクラスの属性を呼び出す super().__init__(name=name) # name(Animal) = name(Dog)となる print("Dog init is called") muku = Dog("muku") # Animal class is called print(muku.name) # Dog init is called muku muku.run() # muku is running. |
ex.) トラッククラスを作ってみる(Carクラスを継承したTruckクラスを作る)
Carクラスを継承したTruckクラスに最大積載量、現在の積載量の属性を定義し、loadメソッドで積荷を乗せたり降ろしたり出来るコードを実装してみる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# Carクラスでモデルネーム、マイレージ、製造メーカーを定義 class Car(object): def __init__(self, model_name, mileage, manufacturer): self.model_name = model_name self.mileage = mileage self.manufacturer = manufacturer # Truckクラスを作成 class Truck(Car): # superクラスの属性を継承し、最大積載量と現在の積載量(0とする)の2つの属性を定義する def __init__(self, model_name, mileage, manufacturer, max_loadings): super().__init__(model_name, mileage, manufacturer) self._max_loadings = max_loadings self._loadings = 0 def load(self, weight): # 積載量が0以上の場合、インクリメントで_loadingsに値を追加 if weight > 0: #荷物を積む print(f"{weight}tの荷物を積みました") self._loadings += weight # 積載量が0未満の場合、デクリメントで_loadingsから値を引く else: #現在の積載量が下ろす荷物より多い場合 if self._loadings > -weight: print(f"{-weight}tの荷物を降ろしました") #weightは負の値なので+で引き算をする self._loadings += weight #現在の積載量が下ろす荷物より少ない場合 else: print(f"{self._loadings}t全ての荷物を降ろしました") self._loadings = 0 print(f"現在の積載量は{self._loadings}tです") # 荷物が最大積載量を超えている場合 if self._loadings > self._max_loadings: print(f"最大積載量は{self._max_loadings}tです。重量オーバーです。") if __name__ == "__main__": hino_truck = Truck("トラック", 7, "HINO", 10) hino_truck.load(5) # 5tの荷物を積みました 現在の積載量は5tです hino_truck.load(-3) # 3tの荷物を降ろしました 現在の積載量は2tです hino_truck.load(10) # 10tの荷物を積みました 現在の積載量は12tです hino_truck.load(-30) # 最大積載量は10tです。重量オーバーです。 12t全ての荷物を降ろしました 現在の積載量は0tです |
オーバーライド(overriding)
✔️superclassのメソッドを、subclass用に書き換える/追加すること
✔️オーバーロード(overloading:同じ関数だけど引数が違う)とは別物なので注意(Pythonにオーバーロードはない)
ex.) Carクラス(superclass)のgasメソッドをオーバーライドしてTruckクラスのgasメソッドで上書きする
1 2 3 4 5 6 7 8 9 10 11 12 |
# <superclass> car.py class Car(object): def __init__(self, model_name, mileage, manufacturer): self.model_name = model_name self.mileage = mileage self.manufacturer = manufacturer def gas(self): print(f"{self.manufacturer}の{self.model_name} (燃費:{self.mileage}) アクセルON") def brakes(self): print("{0.manufacturer}の{0.model_name} (燃費:{0.mileage}) ブレーキON".format(self)) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# <subclass> truck.py from car import Car class Truck(Car): def __init__(self, model_name, mileage, manufacturer, max_loadings): super().__init__(model_name, mileage, manufacturer) self._max_loadings = max_loadings self._loadings = 0 # Carクラス(superclass)でもgas()メソッドはあるが、Truckクラス(subclass)で定義すると上書きされる def gas(self): # 現在の積載量が最大積載量を上回っていた場合 if self._loadings > self._max_loadings: print("重量オーバーなので走れません") print(f"{self._loadings - self._max_loadings}tの荷物を降ろして下さい") else: # superclassのgasメソッドを呼ぶ super().gas() def load(self, weight): if weight > 0: print(f"{weight}tの荷物を積みました") self._loadings += weight else: if self._loadings > -weight: print(f"{-weight}tの荷物を降ろしました") self._loadings += weight else: print(f"{self._loadings}t全ての荷物を降ろしました") self._loadings = 0 print(f"現在の積載量は{self._loadings}tです") if self._loadings > self._max_loadings: print(f"最大積載量は{self._max_loadings}tです。重量オーバーです。") if __name__ == "__main__": hino_truck = Truck("トラック", 7, "HINO", 10) hino_truck.gas() # HINOのトラック (燃費:7) アクセルON hino_truck.load(5) # 5tの荷物を積みました 現在の積載量は5tです hino_truck.load(10) # 10tの荷物を積みました 現在の積載量は15tです hino_truck.gas() # 重量オーバーなので走れません 5tの荷物を降ろして下さい |
ex.) 継承時の名前修飾(親、子クラスに同じ名前の関数がある時、subclassからのオーバーライドを避ける方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Person: def __init__(self, name): self.name = name # ここに名前修飾を入れることで、Babyクラスをインスタンスした際に、 # Babyクラスのmymethodが呼ばれてしまうのを防ぐ self.mymethod() # 外からもアクセスできるインスタンスメソッドとする def __mymethod(self): print("Person method is called") # Personクラスのmymethod関数をprivate関数(__mymethod)としないように、 # 下記のような変数に格納して、mymethodをpublic関数とする __mymethod = mymethod class Baby(Person): def mymethod(self): print("Baby method is called") pass hiroki_baby = Baby("Hiroki") hiroki_person = Person("hiroki") # Personクラスのmymethodが正しく呼ばれる print(hiroki_baby.name) # Person method is called Hiroki hiroki_baby.mymethod() # Hiroki Baby method is called |
Polymorphism(ポリモーフィズム)
✔️poly⇨many, morphe⇨form:多様性のこと⇨”違う型でも同じ振る舞いをする”という意味
✔️printオブジェクトもポリモーフィズムを実現している例(printはint, str, bool, dictなんでも出力することが出来る)
✔️継承はポリモーフズムを実現する手段の一つ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# Myclassクラスに__str__メソッドを定義する(print関数の説明に使います) class Myclass(object): def __str__(self): return "Myclassの__str__" # Myclassのインスタンス化 mc = Myclass() print(mc) # mc.__str__() # Myclassの__str__ # ↑この要領でprintはコンソールに出力している # printの引数がstr型で出力出来るのは__str__メソッドが呼ばれているから # それはクラスの引数にあるobjectクラスに定義された__str__()が実行されるから print(1) # 1.__str__() print("1") # "1"__str__() print(True) # True__str__() print([1, 2, 3]) # [1, 2, 3].__str__() various_types = [1, "1", True, [1, 2, 3], (1,), {"1": 1}, {1}] for elem in various_types: print(elem) #.__str__()が実行される # 1 1 True [1, 2, 3] (1,) {'1': 1} {1} |
DuckTyping(ダックタイピング)
✔️動的型付け言語を理解する上で必要な考え方
✔️動的型付け言語の理解を深める時によく用いられるフレーズ
”It walks like a duck and quacks like a duck, it must be a duck”
アヒルのように歩き、アヒルのように鳴くなら、アヒルに違いない
✔️Pyhtonで言うと、『オブジェクトのクラス(型)かどうかではなく、どう振る舞うか』ということ
✔️↑”intか”, “strか”よりも”演算ができるか”に注目し、『演算ができるのであれば、intとして扱いましょう!』と言うこと
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
class Duck: def __init__(self, name): self.name = name def walk(self): print("Walking...") def quack(self): print("quack quack..!") def fly(self): print("Flying!!") class Penguin: def __init__(self, name): self.name = name def walk(self): print("Walking...") def quack(self): print("quack quack..??") def swim(self): print("Swimming!") def walk_and_quack(duck): print(f"I'm {duck.name}.") duck.walk() duck.quack() if __name__ == "__main__": donald = Duck("Donald") batsumaru = Penguin("Batsumaru") donald.walk() # Walking... donald.quack() # quack quack..! batsumaru.walk() # Walking... batsumaru.quack() # quack quack..?? ducklist = [donald, batsumaru] for duck in ducklist: # アヒルではなくても、quack関数が呼ばれて鳴く。つまりデータ型がどうかでは無く、関数として実行できるかどうかに焦点を当てる walk_and_quack(duck) # I'm Donald. Walking... quack quack..! # I'm Batsumaru. Walking... quack quack..?? |
Docstringの書き方
✔️下記のように書くのが一般的だが、社内やチームでのルールに従い必ず記述すること
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class Duck: # classのdocstring """ This is for Duck. Attributes: name(str): the name od the duck Methods: walk: print *** quack: print *** fly: print *** """ def __init__(self, name): # constructorのdocstring """ The constructor for Duck class :param name: the name of the duck """ self.name = name def walk(self): print("Walking...") def quack(self): print("quack quack..!") def fly(self): print("Flying!!") if __name__ == "__main__": # 下記の方法でdoctringを確認することが出来る print(help(Duck.__init__)) print(Duck.__init__.__doc__) |
これでpythonの文法<オブジェクト指向編>は終了です、いかがだったでしょうか?
オブジェクト指向の概念、クラスやクラス継承など、Pythonの習得する上で最も重要で、知っておかなければならないことが盛り沢山だったかなと思います。
一度で全部吸収し切るのは難しいため、今後の学習で詰まったら必ず立ち戻れるようにしておきたいところです🙆♂️
次回はpythonをコーディングする上での決まりごとや標準ルールについて、”StyleGuide”を使って学習していきます。可読性の高い、綺麗なコードを書くためには知っておいて欲しいことがたくさんありますので、一緒に学習していきましょう☀️
今回はこの辺で、ばいばい👋
コメントを残す