1. ホーム
  2. python

[解決済み] 実行時にインスタンスの基底クラスを動的に変更するには?

2023-07-01 03:20:37

質問

この記事 の使用法を示すスニペットがあります。 __bases__ を使って、既存のクラスコレクションにクラスを追加することで、Pythonコードの継承階層を動的に変更しています。 OK、これは読みにくいので、おそらくコードがより明確です。

class Friendly:
    def hello(self):
        print 'Hello'

class Person: pass

p = Person()
Person.__bases__ = (Friendly,)
p.hello()  # prints "Hello"

ということです。 Person を継承していないのです。 Friendly を継承するのではなく、この継承関係は実行時に __bases__ 属性の変更により、実行時に動的に追加されます。 しかし、もし FriendlyPerson を(object を継承して)新しいスタイルクラスとする場合、次のようなエラーが発生します。

TypeError: __bases__ assignment: 'Friendly' deallocator differs from 'object'

これに関して少しググってみると、どうやら はいくつかの非互換性を示しています。 を示唆しているようです。 具体的には 新スタイルのクラスオブジェクトは、その ベース 属性への割り当てをサポートしません。 .

質問ですが、上記の Friendly/Person の例を Python 2.7+ の新しいスタイルのクラスを使って動作させることは可能でしょうか。 __mro__ 属性を使用することで可能でしょうか?

免責事項: 私は完全にこれは無名のコードであることを理解します。 これは純粋に思考実験であり、Python が多重継承に関連する問題をどのように扱うかについて何かを学ぶためのお遊びであることを、私は十分に理解しています。

どのように解決するのですか?

OK、もう一度言いますが、これは通常行うべきことではなく、情報提供のみを目的としたものです。

Pythonがインスタンスオブジェクトのどこでメソッドを探すかは __mro__ 属性によって決定されます (そのオブジェクトを定義するクラスの M メソッド R 解決方法 O rder 属性)。 したがって、もし私たちが __mro__Person のようにすれば、望ましい動作が得られるでしょう。 こんな感じ。

setattr(Person, '__mro__', (Person, Friendly, object))

問題なのは __mro__ が読み取り専用の属性であるため、setattr が動作しないことです。 Python の第一人者であれば、それを回避する方法があるかもしれませんが、明らかに私は第一人者には程遠いので、それを思いつきません。

可能な回避策は、単にクラスを再定義することです。

def modify_Person_to_be_friendly():
    # so that we're modifying the global identifier 'Person'
    global Person

    # now just redefine the class using type(), specifying that the new
    # class should inherit from Friendly and have all attributes from
    # our old Person class
    Person = type('Person', (Friendly,), dict(Person.__dict__)) 

def main():
    modify_Person_to_be_friendly()
    p = Person()
    p.hello()  # works!

これは、以前に作成した Person インスタンスに hello() メソッドを使用します。 例えば、(単に main() ):

def main():
    oldperson = Person()
    ModifyPersonToBeFriendly()
    p = Person()
    p.hello()  
    # works!  But:
    oldperson.hello()
    # does not

の詳細が不明な場合は type の呼び出しの詳細が明確でない場合は、次のように読んでください。 e-satis's excellent answer on 'What is a metaclass in Python?'(Pythonのメタクラスとは何か? .