web-dev-qa-db-ja.com

TypeError:一貫したメソッド解決順序(MRO)を作成できません

これは、ゲームに使用する予定のコードです。しかし、MROエラーについては不満を述べています。理由はわかりません。誰かが私のために説明できますか?どうもありがとう。

class Player:
    pass

class Enemy(Player):
    pass

class GameObject(Player, Enemy):
    pass

g = GameObject()
74
user188276

GameObjectPlayerから継承していますおよびEnemyEnemyalreadyPlayer Pythonを継承するため、メソッドを最初に検索するクラスを決定できません; Player、またはEnemyで、Playerで定義されているものをオーバーライドします。

ここでEnemyのすべての基本クラスに名前を付ける必要はありません。その1つのクラスから継承するだけです。

class GameObject(Enemy):
    pass

Enemyには既にPlayerが含まれています。再度含める必要はありません。

99
Martijn Pieters

元のコードが機能しない理由を説明します。

Pythonは、インスタンス属性/メソッドを検索するときに、(直接および間接の)基本クラスを検索する順序を決定する必要があります。これを行うには、継承グラフを線形化します。つまり、 C3またはMRO というアルゴリズムを使用して、基本クラスのグラフをシーケンスに変換します。 MROアルゴリズムは、いくつかの望ましい特性を実現する独自のアルゴリズムです。

  1. 各祖先クラスは1回だけ表示されます
  2. クラスは常にその祖先の前に表示されます(「単調性」)
  3. 同じクラスの直接の親は、クラス定義にリストされているのと同じ順序で表示される必要があります(「一貫したローカル優先順位」)
  4. クラスAの子がクラスBの子の前に常に表示される場合、ABの前に表示される必要があります(「一貫した拡張優先順位」)

コードでは、2番目の制約ではEnemyが最初に表示される必要があります。 3番目の制約では、Playerが最初に現れる必要があります。すべての制約を満たす方法はないため、pythonは、継承階層が不正であることを報告します。

GameObjectの基本クラスの順序を次のように切り替えると、コードが機能します。

class GameObject(Enemy, Player):
    pass

これは単なる技術的な詳細ではありません。メソッドが複数のクラスで定義されている場合、一部の(願わくはまれな)場合、メソッドが呼び出されたメソッドを取得するためにどのクラスを使用するべきかを考えたいかもしれません。基本クラスを定義する順序は、この選択に影響します。

54
max

書いたのは、GameObjectPlayerEnemyの両方にすることです。しかし、EnemyはすでにPlayerです。 MROの問題では、aにフィールドPlayerがある場合、GameObjectインスタンスでこのフィールドを要求することはあいまいです。最初のaからのPlayerか、Playerから継承したEnemyの継承である場合?

しかし、ここでは継承の代わりに構成を使用したくないのですか?

class GameObject(object):
    def __init__(self):
        self.player = Player()
        self.enemy = Enemy()
6
Francis Colas