質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

Q&A

解決済

3回答

1987閲覧

【python3】菱形継承時に動的に継承するクラスを選択することはできるでしょうか。

shirai

総合スコア1289

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

0グッド

1クリップ

投稿2020/01/28 14:13

概要

仕事で開発しているpythonの設計に関する質問です。
文字ばかりで見づらく申し訳ございません。

状況

同ディレクトリ上に5つのpythonファイルがあります。

親.py, 子1.py, 子2.py, 孫.pyにはクラスが1つずつあり、
実行.pyは実行用のファイルです。

子1と子2のクラスはどちらも親のクラスを継承していて、
孫のクラスは子1と子2のクラスを継承しています。
いわゆる菱形継承です。

phpが実行.pyを叩いて、実行.pyのなかで孫のインスタンスを作成し、
孫の中のインスタンスメソッドを実行するというイメージです。

孫のクラスは2つインスタンスメソッドを持っていますが、
それぞれが子1、子2のクラスにのみ対応しています。

phpに実行.pyを叩かせた時の引数によって場合分けされ、
どちらかのインスタンスメソッドしか呼び出しません。
つまり子1、子2のいずれか片方には縁のないままプログラムの一生を終えることになります。
先輩と吟味しましたがこの点は将来的にも変わりません。

ですがどちらのパターンでも親のもつインスタンスメソッドにはアクセスする必要があります。

質問内容

先の質問にて、明示的にどちらのクラスを経由させて親にアクセスさせられるかについては把握できましたが、
そもそも孫のクラスがどちらか片方しか継承されないようにすればいいと思いつきました。
他の処理との兼ね合いもあり、この菱形を解消するのは難しいのですが、
そのような孫のクラスの宣言方法はpython3にはあるのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakaiY

2020/01/28 15:01

「どちらか片方しか継承されないようにすればいいと思」ったとのことですが、子1, 子2 の両方を継承したままでどのような問題があるのでしょうか? 実行.py が実行されたときにしかわからない引数でクラスの構成を変えるにはメタクラスを使う方法があることはあります。
quickquip

2020/01/28 15:23 編集

> どちらかのインスタンスメソッドしか呼び出しません。 これが本当なら孫のクラスがなぜ必要なのか説明できないように見えます。 というか子1、子2の必要性すら感じないです。
shirai

2020/01/28 15:30

ありがとうございます。 実を言うと他にもいくつか先人の方々が作成したメソッドが 親子孫ところどころにくっついているのですが、 正直私も良く動きが分かっていない状況です。 孫も何人かいますが、片方の子からしか継承していないなどものによって異なっています。。 今回対象にした孫ではいずれのメソッドも片方しか利用していないことが かろうじて分かったので、ここだけでも見やすくできたらと思いました。 親のメソッドをそれぞれの子がオーバーライドしていて、 正直めちゃめちゃ分かりづらいので、せめて部分的にでも分断させられたら と思い立ち質問に至りました。
quickquip

2020/01/28 23:01 編集

> 分断させられたら 「分断させられるように書き直せる」なら「(菱形継承した共通の)孫クラスを使わないに書き直せる」のでは。 さらに複雑になるように書き直したい、と言っているようなものかと思います。 (追記) 失礼しました。もとの質問が「菱形継承しないように上位クラスを動的に選択できないか」という趣旨なのですね。でしたらこのコメントは不要でした。
quickquip

2020/01/29 00:39

hayataka2049さんのコードに加えて「func1がGrandChildでもオーバーライドされている」あるいは「func1がChildAでもChildBでもGrandChildでもオーバーライドされている」というような状況だということでしょうか?
shirai

2020/01/29 02:19

GrandChildではChildやParentのメソッドををオーバーライドはしていないようです。 ChildではParentのメソッドをオーバーライドしているものもあるようです。
shirai

2020/01/29 02:22

メタクラスについて調べてみました。 軽く見ただけですが確かにこれを利用するとより複雑になりそうですね。。。 しかも想定以上に改修難易度も高そうです。
hayataka2049

2020/01/29 16:14 編集

技術的に可能かどうかは置いておいて(いろんなやり方が思いつかなくはないのがPythonの嫌な所ですが)、わけわからないものの上に更にわけわからないものを重ねてもどうにもならないので、普通にリファクタリングするしかないかと…… 「動的に継承する親クラスを変えるクラス」のコードなんて仮に書いた本人は理解できても他の人には扱いきれないでしょうし、コードレビューで真っ先に蹴られそう。
guest

回答3

0

回答に書くべきことじゃないのですけれどそこそこコードがあるので現状の確認ということで。

python

1class Parent: 2 def func(self): 3 print("do something func in Parent") 4 5 6class ChildA(Parent): 7 def func(self): 8 print("do something func in ChildA") 9 10 def func_a(self): 11 self.func() 12 print("do something func_a in ChildA") 13 14 15class ChildB(Parent): 16 def func(self): 17 print("do something func in ChildB") 18 19 def func_b(self): 20 self.func() 21 print("do something func_b in ChildB") 22 23 24class GrandChild(ChildA, ChildB): 25 def func_a_dash(self): 26 self.func_a() 27 28 def func_b_dash(self): 29 self.func_b() 30 31 32x = GrandChild() 33 34 35# ★ 36if なんか条件: 37 x.func_a_dash() 38else: 39 x.func_b_dash()

こういう感じになって、★のところをよくよく見てみたらなにか条件で分岐していて、
func_aの系列しか使わない処理の塊と、func_bの系列しか使わない処理の塊とで
完全に分かれているので、GrandChildが菱形継承する必要はないのでは?
と推測した。

という現状でしょうか?

(こういうことなら

x.func_b_dash()の結果が

plain

1do something func in ChildA 2do something func_b in ChildB

なので、GrandChildをうかつに2つに分割するとハマる理由も理解できますが)

投稿2020/01/29 03:58

編集2020/01/29 03:59
quickquip

総合スコア11029

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

回答はあとで考えますが、先に要件の確認です。

単純化すると、こんな感じで合っていますか?

python

1## 定義しているファイルとする 2 3class Parent: 4 def func1(self): 5 print("Parent") 6 7class ChildA(Parent): 8 def func2(self): 9 self.func1() 10 print("ChildA") 11 12class ChildB(Parent): 13 def func3(self): 14 self.func1() 15 print("ChildB") 16 17class GrandChild(ChildA, ChildB): 18 # ここで何とかする? 19 20 21## ---以下 実行.py とする--- 22 23cond = # どこかからもらってくる 24if cond: 25 gc = # 何とかしてChildAの方の子としてインスタンス化する 26 gc.func1() 27 gc.func2() 28else: 29 gc = # 何とかしてChildBの(ry 30 gc.func1() 31 gc.func3() 32

投稿2020/01/28 14:57

編集2020/01/28 15:07
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shirai

2020/01/28 15:05

ありがとうございます。 おおよそこのようなイメージですが、 func2やfun3の中でfunc1を呼び出しています。
hayataka2049

2020/01/28 15:06

直しておきます。質問文を改めて読んでみたんですが、これそんな困る状況ですか? 単に要らないメソッドがあるだけのような気も。
hayataka2049

2020/01/28 15:06

TakaiYさんの修正依頼とかぶった。
quickquip

2020/01/28 15:42

gc = # なんか作る cond = # どこかからもらってくる if cond: □gc.func2() else: □gc.func3() で一切不都合ないですよね……
guest

0

自己解決

ご回答いただきましたみなさまありがとうございました。
リアクションに時間がかかりまして誠に申し訳ございませんでした。

もう一度コードを見てよく考えてみましたが、
やはりこれ以上ぐちゃぐちゃにしても誰も喜ばないと判断しましたので、
今回の質問に関しては諦めることにします。

お時間いただきまして本当にありがとうございました。

投稿2020/02/02 15:22

shirai

総合スコア1289

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問