8

という名前の Python クラスを作成しました。このクラスは、 という名前のクラスと というLiger名前のクラスを拡張します。クラスはとの両方からメソッドを継承しますが、それでも構文は有効です。エラー メッセージは出力されませんが、代わりにのメソッドの実装が に継承されます。Python でこのようなメソッド名の衝突を検出して、メソッド名がこのように衝突したときにエラー メッセージが出力されるようにすることは可能ですか?LionTigerLigerspeak()LionTigerTigerspeak()Liger

'''
Conflicting method names in python
'''


class Tiger():
    @staticmethod
    def speak():
        print "Rawr!";

class Lion():
    @staticmethod
    def speak():
        print "Roar!";

class Liger(Tiger, Lion):
    pass
'''both superclasses define a speak() method, and I need a way to detect this type of conflict.'''    

Liger.speak(); ''' this prints "Rawr" instead of printing an error message. '''
'''Is there any way to detect method name collisions like this one?'''

コードはオンラインでテストおよびデバッグできます: http://ideone.com/xXOoVq

4

2 に答える 2

4

問題を解決するために継承が適切なメカニズムであるかどうかはわかりません。継承は、2 つのクラス間の「IS-A」関係を定義するとよく言われます。つまり、 がAから継承されBている場合、 のすべてのインスタンスBは のインスタンスでAもあります。

多重継承を使用している場合、クラスは一度に複数の種類のオブジェクトになってしまいます。あなたの例では、Ligerインスタンスは同時に aTigerと a の両方Lionです。

おそらく、種の継承をモデル化するためにクラスの継承を使用したくないでしょう。名前にもかかわらず、それらは実際には同じことを意味するわけではありません。たとえば、家猫はおそらくかなりトラっぽいものの子孫ですが、家猫がトラであると言うのは正しくありません。

クラスで静的メソッドを使用しているという事実は、おそらくクラスをまったく使用するのではなく、より一般的なAnimalクラスのインスタンスを使用することを望んでいると思います。

class Animal(object):
    def __init__(self, sound):
        self.sound = sound

    def speak(self):
        print self.sound

lion = Animal("Roar!")

そこには継承のメカニズムはありませんが、何らかの方法で、ある種類の動物を別の種類に変異させるメソッドを追加することは可能です。

さて、本当にクラスと多重継承を使いたいと思っているのであれば、(静的メソッドではなく通常のインスタンス メソッドを使用する) 2 つの適切なアプローチがあります。

1 つ目は、「共同多重継承」を行い、各メソッドが MRO の次のクラスで同じメソッドを呼び出すようにすることです。通常、これを機能させるには、共通の基本クラスから継承する必要があります (そうしないと、メソッドが定義されていない最後の呼び出しsuperが getになります)。object

class Animal(object):
    def speak(self):
        pass

class Lion(Animal):
    def speak(self):
        print("Roar!")
        super(Lion, self).speak()

class Tiger(Animal):
    def speak(self):
        print("Rawr!")
        super(Tiger, self).speak()

class Liger(Lion, Tiger):
    pass

この状況では、Ligerインスタンスのspeakメソッドは両方のRoarthenRawrを出力します。これは、ライオンとトラの両方を同時に表しているため、理にかなっています。ただし、コラボレーションを正しく機能させるのは難しい場合があるため、このスタイルのコーディングには注意してください。たとえば、メソッド シグネチャを変更して、共同多重継承の状況で正しく機能することを期待することはできません (キーワード引数のみを使用し、認識されていない引数を .xml で渡さない限り**kwargs)。

2 番目の解決策は、何を行うかを明示的に選択するLiger独自のspeak実装を提供することです (基本クラスの 1 つを呼び出す場合もあります)。これは、C++ などの他の言語で必要です。リクエストした継承が意図したとおりに機能しない場合は、おそらくこれが最も簡単な修正方法です。

class Liger(Lion, Tiger):
    def speak(self):
        Tiger.speak(self)
于 2013-03-10T23:20:43.427 に答える
3

メタクラスを使用して、この種の競合を検出できます。

class ConflictCheck(type):
    def __new__(meta, name, bases, dct):
        # determine attributes per base class, except for magic ones
        attrs_per_base = [set(a for a in dir(b) if not a.startswith("__"))
                          for b in bases]
        if len(set.union(*attrs_per_base)) < sum(map(len, attrs_per_base)):
            raise ValueError("attribute conflict")
        return super(ConflictCheck, meta).__new__(meta, name, bases, dct)

class Liger(Lion, Tiger):
    __metaclass__ = ConflictCheck  # will raise an error at definition time

これは非常に粗雑な最初のバージョンで、エラー メッセージが貧弱で、継承ツリーの上でメソッドがオーバーライドされるたびに実際にエラーが発生しますが、Liger始めるには十分なはずです。

于 2013-03-10T22:53:19.490 に答える