2013-08-02 10 views
7

基本クラスBaseとサブクラスSpecialがあります。BaseClassオブジェクトを慣用的にSubClassオブジェクトに変換しますか?

class Base(object): 
    def __init__(self, name): 
     self.name = name 
    def greet(self): 
     return 'Hello %s' % self.name 

class Special(Base): 
    def __init__(self, name): 
     super(Special, self).__init__(name) 
    def rhyme(self): 
     return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name 

どのように私は、インスタンスSpecialBaseのインスタンスを回すことができますか?現在、私はちょうど__dict__をreassignes Special上で定義されたclassmethodを持っている:

class Special(Base): 
    ... 
    @classmethod 
    def from_base(cls, baseobj): 
     special = Special() 
     special.__dict__ = baseobj.__dict__ 
     return special 

は、この慣用句ですか?何がそうでないならば?

P.S.シナリオの例:基本クラスはいくつかのデフォルトの実装です。野生では、おそらくベースクラスのオブジェクトを見つけるでしょう。現在、いくつかのプロジェクトでは、基本クラスはサブクラスであり、特別なメソッドがサブクラスに追加されています。今では主に基本クラスオブジェクトで作業していますが、いくつかのメソッドにアクセスする必要があるため、時折、特別クラスに "アップグレード"したいことがあります。

+0

なぜインスタンス化またはSpecial' 'の力を使用することはできません。

とにかく、ここのコードですか? –

答えて

6

これは、代替コンストラクタを定義し、インスタンスの__class__属性を再割り当てすることで実現できます。

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

    def greet(self): 
     return 'Hello %s' % self.name 

    @classmethod 
    def alt_constructor(cls, *args, **kwargs): 
     obj = cls(*args, **kwargs) 
     obj.__class__ = Special 
     return obj 


class Special(Base): 
    def __init__(self, name): 
     super(Special, self).__init__(name) 

    def rhyme(self): 
     return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name 


>>> s = Base.alt_constructor("test") 
>>> print s.rhyme() 
Hi test! How are you? Fine, thanks. What about you? 

EDIT:

SpecialからBaseにコンストラクタを移動しました。

Baseクラスを変更できない場合は、クラスメソッドをSpecialに追加すると、渡されたオブジェクトのクラスが変更されます。

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

    def greet(self): 
     return 'Hello %s' % self.name 


class Special(Base): 
    def __init__(self, name): 
     super(Special, self).__init__(name) 

    def rhyme(self): 
     return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name 

    @classmethod 
    def convert_to_special(cls, obj): 
     obj.__class__ = Special 

>>> b = Base("test") 
>>> print type(b) 
<class '__main__.Base'> 

>>> Special.convert_to_special(b) 
>>> print type(b) 
<class '__main__.Special'> 

より汎用的な解決策は、どのクラスにも追加できるミックスインを作成することです。

class ConverterMixin(object): 

    @classmethod 
    def convert_to_class(cls, obj): 
     obj.__class__ = cls 


class Special(ConverterMixin, Base): 
    def __init__(self, name): 
     super(Special, self).__init__(name) 

    def rhyme(self): 
     return 'Hi %s! How are you? Fine, thanks. What about you?' % self.name 

>>> b = Base("test") 
>>> print type(b) 
<class '__main__.Base'> 

>>> Special.convert_to_class(b) 
>>> print type(b) 
<class '__main__.Special'> 
+0

@mikuあなたが正しいです、私の元の答えでは、クラスが振る舞う方法を変える、 'Base'に代わるコンストラクタを追加しました。私は私があなたが探していると信じて私の答えを更新しました。 – FastTurtle

+0

ありがとうございます。 '__class__'を使用すると、新しいオブジェクトを作成しないので、驚くことではありません。 – miku

1

実際には可能ですが、私はそうすべきではありません。 typecastingの代わりに、この種の状況を解決するためのダックタイピングがあります。

>>> base = Base("I'm a base!") 
>>> hasattr(base, 'rhyme') 
False 
>>> base.__class__ = Special 
>>> hasattr(base, 'rhyme') 
True 
>>> base.rhyme() 
"Hi I'm a base!! How are you? Fine, thanks. What about you?" 
関連する問題