これは、ゲームに使用する予定のコードです。しかし、MROエラーについては不満を述べています。理由はわかりません。誰かが私のために説明できますか?どうもありがとう。
class Player:
pass
class Enemy(Player):
pass
class GameObject(Player, Enemy):
pass
g = GameObject()
GameObject
はPlayer
から継承していますおよびEnemy
。 Enemy
alreadyはPlayer
Pythonを継承するため、メソッドを最初に検索するクラスを決定できません; Player
、またはEnemy
で、Player
で定義されているものをオーバーライドします。
ここでEnemy
のすべての基本クラスに名前を付ける必要はありません。その1つのクラスから継承するだけです。
class GameObject(Enemy):
pass
Enemy
には既にPlayer
が含まれています。再度含める必要はありません。
元のコードが機能しない理由を説明します。
Pythonは、インスタンス属性/メソッドを検索するときに、(直接および間接の)基本クラスを検索する順序を決定する必要があります。これを行うには、継承グラフを線形化します。つまり、 C3またはMRO というアルゴリズムを使用して、基本クラスのグラフをシーケンスに変換します。 MROアルゴリズムは、いくつかの望ましい特性を実現する独自のアルゴリズムです。
A
の子がクラスB
の子の前に常に表示される場合、A
はB
の前に表示される必要があります(「一貫した拡張優先順位」)コードでは、2番目の制約ではEnemy
が最初に表示される必要があります。 3番目の制約では、Player
が最初に現れる必要があります。すべての制約を満たす方法はないため、pythonは、継承階層が不正であることを報告します。
GameObject
の基本クラスの順序を次のように切り替えると、コードが機能します。
class GameObject(Enemy, Player):
pass
これは単なる技術的な詳細ではありません。メソッドが複数のクラスで定義されている場合、一部の(願わくはまれな)場合、メソッドが呼び出されたメソッドを取得するためにどのクラスを使用するべきかを考えたいかもしれません。基本クラスを定義する順序は、この選択に影響します。
書いたのは、GameObject
をPlayer
とEnemy
の両方にすることです。しかし、Enemy
はすでにPlayer
です。 MROの問題では、a
にフィールドPlayer
がある場合、GameObject
インスタンスでこのフィールドを要求することはあいまいです。最初のa
からのPlayer
か、Player
から継承したEnemy
の継承である場合?
しかし、ここでは継承の代わりに構成を使用したくないのですか?
class GameObject(object):
def __init__(self):
self.player = Player()
self.enemy = Enemy()