こんにちは。明月です。
この投稿はPythonでクラスを継承する方法に関する説明です。
以前の投稿でPythonでクラスを生成して使う方法に関して説明したことがあります。
link - [Python] 12. クラス(Class)を使う方法
Pythonでクラスを生成する時、既存にあるクラスでもっと機能を拡張して使いたい時があります。でも、ただクラスを修正すると既存に参照した領域で影響されるので修正することはできないなのでコピペする時があります。
ただ、コピペすると元のクラスがバグがある時にコピペしたクラスをすべて修正しなければならないです。そのことより、ディベロッパーらしくないコーディングスタイルです。
その時にただコピペでクラスを生成することではなく、継承することで再定義することができます。
# クラス生成
class Main():
# コンストラクタ
def __init__(self):
# アンダーバー(_)二つはprivateだが、一つはprotectedの意味だ。
self._data = "Main Class"
# 関数生成
def exec_function(self):
# コンソール出力
print(self._data)
# Main2クラスはMainのクラスを継承した。
class Main2(Main):
# コンストラクタを再定義
def __init__(self):
# 親クラスの_data変数データを定義
self._data = "Main2 Class"
# Mainインスタンスを生成
a = Main()
# exec_function関数を呼び出す。
a.exec_function()
# Main2インスタンスを生成
b = Main2()
# Main2クラスにはexec_function関数がないがMainクラスを継承したので、使える。
b.exec_function()
上の例をみればMain2クラスは確かにexec_functionがありません。でもMainクラスを継承しましたので、Mainのクラスの機能を使えます。
アンダーバー(_)を一つ使いましたが、protectedという意味で外部では参照できないですが、継承したクラスと内部では参照できるようなアクセス修飾子です。
まとめるとアンダーバーがない場合はpublicですべて参照が可能、アンダーバー(_)が一つで変数名が始まる場合はprotecetdで継承したクラスと内部、アンダーバー(_)が二つで変数名が始まる場合はprivateで内部だけ参照できるような設定です。
つまり、_dataの場合はアンダーバーが一つで変数名が始まるのでMainクラスを継承したMain2で参照ができます。なのでexec_function関数を呼び出すとMainは「Main Class」がMain2は「Main2 Class」が出力されます。
# クラス生成
class Main():
# コンストラクタ
def __init__(self):
# 空欄
pass
# get_data関数
def _get_data(self):
# strデータを返却
return "Main Class"
# exec_function関数で_get_data関数を呼び出す。
def exec_function(self):
# コンソール出力
print(self._get_data())
# Main2クラスはMainのクラスを継承した。
class Main2(Main):
# Mainクラスで_get_data関数がありますが、再定義する。
def _get_data(self):
# strデータを返却
return "Main2 Class"
# Mainインスタンスを生成
a = Main()
# exec_function関数を呼び出す。
a.exec_function()
# Main2インスタンスを生成
b = Main2()
# Main2クラスにはexec_function関数がないがMainクラスを継承したので、使える。
b.exec_function()
上の例ではMainクラスで_get_data関数を生成しましたが、Main2クラスで継承する時に再定義する構造です。結果はexec_function関数を呼び出すと再定義した_get_data関数を呼び出します。
でも、再定義したが親のクラスを使いたい時があります。
# クラス生成
class Main():
# コンストラクタ
def __init__(self):
# 空欄
pass
# get_data関数
def _get_data(self):
# strデータを返却
return "Main Class"
# exec_function関数で_get_data関数を呼び出す。
def exec_function(self):
# コンソール出力
print(self._get_data())
# Main2クラスはMainのクラスを継承した。
class Main2(Main):
# Mainクラスで_get_data関数がありますが、再定義する。
def _get_data(self):
# strデータを返却
return "Main2 Class"
# 関数再定義
# _get_data関数を再定義したが、親クラスの_get_dataを呼び出す。
def exec_function(self):
# コンソール出力
print(super()._get_data())
# Mainインスタンスを生成
a = Main()
# exec_function関数を呼び出す。
a.exec_function()
# Main2インスタンスを生成
b = Main2()
# exec_function関数を呼び出す。
b.exec_function()
上の例はMain2クラスで_get_dataを再定義しました。でもexec_function関数でMain2の_get_dataではなく、親クラス(super())の_get_data関数を呼び出しました。
今まで、使うクラスを継承して機能をそのままで使うクラスを生成しました。
抽象クラスという定義だけして、機能はないクラスを作ることができます。
# 抽象クラスを生成するためにabcモジュールをインポートする。
from abc import *
# 抽象クラスは括弧の中でmetaclass=ABCMetaというデータを入れる。
class Main(metaclass=ABCMeta):
# 抽象メソッドはデコレーターabstractmethodを指定する。
@abstractmethod
# 関数名を設定する。
def _get_data(self):
# 関数機能はなし。
pass
# 関数生成
def exec_function(self):
# コンソール出力
print(self._get_data())
# 抽象クラスを継承したので、_get_data関数を必ず再定義すべきだ。そうではなければエラーが発生する。
class Main2(Main):
# 関数再定義
def _get_data(self):
# strデータをリターン
return "Main2 Class"
# Main2インスタンスを生成
b = Main2()
# exec_function関数を呼び出す。
b.exec_function()
# 抽象クラスはインスタンス生成だけでエラーが発生する。
a = Main()
# 上でエラーが発生するからこれもできない。
a.exec_function()
Main2クラスは一般クラスなので正常にインスタンスを生成して使うことができます。
Mainクラスは抽象クラスなのでインスタンスを生成ができないです。Main2クラスで継承する時にも抽象メソッドは必ず再定義しなければならないです。それで完全体クラスになることです。
Pythonでは継承は一つだけではなく、複数の継承ができます。
# 抽象クラスを生成するためにabcモジュールをインポートする。
from abc import *
# 抽象クラスは括弧の中でmetaclass=ABCMetaというデータを入れる。
class Main1(metaclass=ABCMeta):
# 関数生成
def _get_data1(self):
# strデータを返却
return "Main1"
# 抽象メソッド生成
@abstractmethod
def exec_function(self):
# 関数機能はなし。
pass
# 抽象クラスは括弧の中でmetaclass=ABCMetaというデータを入れる。
class Main2(metaclass=ABCMeta):
# 関数生成
def _get_data2(self):
# strデータを返却
return "Main2"
# 抽象メソッド生成
@abstractmethod
def exec_function(self):
# 関数機能はなし。
pass
# Main3にはMain1とMain2のクラスを複数の継承した。
class Main3(Main1, Main2):
# Main1クラスの関数とMain2クラスの関数を使える。
def exec_function(self):
# コンソール出力
print(self._get_data1())
# コンソール出力
print(self._get_data2())
# Main3インスタンスを生成
b = Main3()
# exec_function関数を呼び出す。
b.exec_function()
複数の継承する場合は親のクラスで関数名が重複なる可能性があります。
# 抽象クラスを生成するためにabcモジュールをインポートする。
from abc import *
# 抽象クラスは括弧の中でmetaclass=ABCMetaというデータを入れる。
class Main1(metaclass=ABCMeta):
# 関数生成
def _get_data(self):
# strデータを返却
return "Main1"
# 抽象メソッド生成
@abstractmethod
def exec_function(self):
# 関数機能はなし。
pass
# 抽象クラスは括弧の中でmetaclass=ABCMetaというデータを入れる。
class Main2(metaclass=ABCMeta):
# 関数生成
def _get_data(self):
# strデータを返却
return "Main2"
# 抽象メソッド生成
@abstractmethod
def exec_function(self):
# 関数機能はなし。
pass
# Main3にはMain1とMain2のクラスを複数の継承した。
class Main3(Main1, Main2):
# 関数生成
def exec_function(self):
# Main1クラスとMain2クラスの両方に_get_data関数がある状況
print(super()._get_data())
# Main3インスタンスを生成
b = Main3()
# exec_function関数を呼び出す。
b.exec_function()
Main3クラスを生成する時にMain1、Main2で継承する順番があります。一番左のクラスが優先で上の状況はMain1とMain2で両方に_get_data関数がある状況ならMain1の_get_dataを呼び出す。
複数継承は様々なクラスを特性を持ってきてよいと思いますが、実際は可読性で悪いので進めるプログラム文法ではないです。
クラスを複数で継承して同じ関数が多いだと思うと呼び出す時にスタック追跡することが大変になります。
ここまでPythonでクラスを継承する方法に関する説明でした。
ご不明なところや間違いところがあればコメントしてください。
- [Python] 21. データベース(mariaDB)を連結する方法2020/06/24 18:51:50
- [Python] 20. stringフォマード(Formatting)と補間法(interpolation)2020/06/23 19:03:21
- [Python] 19. 非同期IOのasync/await(asyncio)を使う方法2020/06/22 18:10:12
- [Python] 18. ネットワーク(Socket)通信する方法2020/06/18 19:53:56
- [Python] 17. スレッド(Thread)とロック(lock)、そしてデッドロック(deadlock)2020/06/18 00:19:45
- [Python] 16. IO(ファイル読み取り、書き込み)を扱う方法2020/06/16 18:37:00
- [Python] 15. クラスを継承する方法2020/06/15 18:20:07
- [Python] 14. クラスプロパティ(Property)2020/06/12 17:45:13
- [Python] 13. クラス関数(class method)とダック・タイピング、そして特殊メソッド2020/06/11 19:42:29
- [Python] 12. クラス(Class)を使う方法2020/06/10 19:33:33
- [Python] 11. デコレーター(Decorator)を使う方法2020/06/09 17:27:18
- [Python] 10. モジュールとパッケージ(import)2020/06/08 19:07:50
- [Python] 09. 例外処理する方法2020/06/05 17:11:47
- [Python] 08. ジェネレータ(Generator)2020/06/04 18:46:08
- check2024/04/10 19:03:53
- [Java] 64.Spring bootとReactを連結する方法(Buildする方法)2022/03/25 21:02:18
- [Javascript] Node.jsをインストールしてReactを使う方法2022/03/23 18:01:34
- [Java] 63. Spring bootでcronスケジューラとComponentアノテーション2022/03/16 18:57:30
- [Java] 62. Spring bootでWeb-Filterを設定する方法(Spring Security)2022/03/15 22:16:37
- [Java] JWT(Json Web Token)を発行、確認する方法2022/03/14 19:12:58
- [Java] 61. Spring bootでRedisデータベースを利用してセッションクラスタリング設定する方法2022/03/01 18:20:52
- [Java] 60. Spring bootでApacheの連結とロードバランシングを設定する方法2022/02/28 18:45:48
- [Java] 59. Spring bootのJPAでEntityManagerを使い方2022/02/25 18:27:48
- [Java] 58. EclipseでSpring bootのJPAを設定する方法2022/02/23 18:11:10
- [Java] 57. EclipseでSpring bootを設定する方法2022/02/22 19:04:49
- [Python] Redisデータベースに接続して使い方2022/02/21 18:23:49
- [Java] Redisデータベースを接続して使い方(Jedisライブラリ)2022/02/16 18:13:17
- [C#] Redisのデータベースを接続して使い方2022/02/15 18:46:09
- [CentOS] Redisデータベースをインストールする方法とコマンドを使い方2022/02/14 18:33:07