2011-12-17 7 views
25

実行時にオブジェクトクラス(クラスではない)に基本クラスを追加することは可能ですか? RubyでどのようにObject#extend作品の線に沿って何か:Pythonで基本クラスをインスタンスに動的に組み合せる

class Gentleman(object): 
    def introduce_self(self): 
    return "Hello, my name is %s" % self.name 

class Person(object): 
    def __init__(self, name): 
    self.name = name 

p = Person("John") 
# how to implement this method? 
extend(p, Gentleman) 
p.introduce_self() # => "Hello, my name is John" 
+0

なぜコメントなしでこれを下げますか?たぶんRubyという言葉がテキストに表示されているからでしょうか? oO –

+1

Uuuuurrghghhh !!!!!クラスを変更せずにインスタンスを変更することは、災害のためのレシピです。これを行うためのより良い方法は、 'Person'のサブクラスを作成し、' Gentleman'をそれにミックスすることです。 – katrielalex

+1

@katrielalex:ほとんどの場合、おそらくあなたは正しいでしょう。それにもかかわらず、インタフェースを変更できないサードパーティライブラリに機能を追加したいので、私はその機能が必要です。ミックスインかプロキシパターンのどちらかを選ぶ必要がありました。後者はあまり好きではありません。 –

答えて

32

これは、動的に新しいクラスGentlePersonを定義し、p再割り当て「それまでのクラス:あなたの要求ごと

class Gentleman(object): 
    def introduce_self(self): 
    return "Hello, my name is %s" % self.name 

class Person(object): 
    def __init__(self, name): 
    self.name = name 

p = Person("John") 
p.__class__ = type('GentlePerson',(Person,Gentleman),{}) 
print(p.introduce_self()) 
# "Hello, my name is John" 

を、これはp修正します」元のクラスを変更しません。したがって、Personの他のインスタンスは影響を受けません(introduce_selfが呼び出された場合はAttributeErrorになります)。


それが直接質問に尋ねられませんでしたが、私は動的にクラスの拠点を変更することも可能であるが、(私の知る限り)クラスを直接継承していない場合にのみこと、のGooglerと好奇心を求める人のために追加しますobjectから:

def extend(instance, new_class): 
    instance.__class__ = type(
      '%s_extended_with_%s' % (instance.__class__.__name__, new_class.__name__), 
      (instance.__class__, new_class), 
      {}, 
     ) 
+0

非常に良い。私は実際に '__class__'に代入しようとしましたが、これは動的に作成されたクラスでしか動作しないようです。これは私が望んでいた解決策です、ありがとうございます。 –

+0

ニース! _directly_から 'object'がキーiircです。クラスオブジェクト(オブジェクト):pass'を定義するのが標準の回避策です。 – katrielalex

+0

'Gentleman'クラスが' Person'クラスのプロパティをオーバーライドしたかったので、私はちょっと遭遇しました。その場合、私は '' type( 'GentlePerson'、(Gentleman、Person)、{}) 'に命令を切り替えました。邪悪をもたらさないことを願っています。 – letmaik

5

それはすでに答えていますが、ここでは機能です

def extend_instance(obj, cls): 
    """Apply mixins to a class instance after creation""" 
    base_cls = obj.__class__ 
    base_cls_name = obj.__class__.__name__ 
    obj.__class__ = type(base_cls_name, (base_cls, cls),{}) 
+0

実用的な解決策があるのは良いことですが、この黒い魔法の使用はよく理解できなければならないことを覚えておいてください。難解なコードと難解なコードのパスかもしれません。 –

7

少しクリーナーバージョン:

class Gentleman(object): 
    def introduce_self(self): 
    return "Hello, my name is %s" % self.name 

class Base(object):pass 
class Person(Base): 
    def __init__(self, name): 
    self.name = name 

p = Person("John") 
Person.__bases__=(Gentleman,object,) 
print(p.introduce_self()) 
# "Hello, my name is John" 

q = Person("Pete") 
print(q.introduce_self()) 
# Hello, my name is Pete 
+1

すてきな解決策。私は既存のインスタンスのメソッドをオーバーライドするためにこれを使用しています。この場合、型の順序は '(cls、base_cls)'でなければなりません。 – miraculixx

関連する問題