2013-08-02 2 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의 인스턴스를 설정할 수 있습니다? 현재 내가이 classmethod 그냥 __dict__을 reassignes Special에 정의 :

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

이 관용적인가? 그게 아니라면?

P. 예제 시나리오 : 기본 클래스가 일부 기본 구현입니다. 야생에서는 기본 클래스의 객체를 찾을 수 있습니다. 이제 일부 프로젝트에서는 기본 클래스가 하위 클래스가되었으며 특수 메서드가 하위 클래스에 추가되었습니다. 이제는 대부분 기본 클래스 개체로 작업하지만, 때때로 일부 메서드에 액세스해야하기 때문에 때때로 특수 클래스로 "업그레이드"할 것입니다.

+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? 

편집 :

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 python 대신 이런 종류의 상황을 해결하기 위해 오리 - 타이핑이 있습니다.

>>> 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?" 
관련 문제