2017-01-12 2 views
1

arg2의 기본값이있는 Parent 클래스가 있습니다. 동일한 속성에 대해 다른 기본값을 갖는 하위 클래스 Child을 생성하려고합니다. Child*args**kwargs을 사용해야합니다. 하위 클래스의 기본 생성자 인수 값 변경 (부모 클래스에서 상속)

나는 다음을 시도했지만 작동하지 않습니다 :이 작동하지 않습니다

class Parent(object): 
    def __init__(self, arg1='something', arg2='old default value'): 
     self.arg1 = arg1 
     self.arg2 = arg2 

     print('arg1:', self.arg1) 
     print('arg2:', self.arg2) 

class Child(Parent): 
    def __init__(self, *args, **kwargs): 
     super(Child, self).__init__(*args, **kwargs) 
     self.arg2 = kwargs.pop('arg2', 'new value') 

. 사실, 내가 얻을 :

>>> c = Child() 
arg1: something 
arg2: default value # This is still the old value 
>>> c.arg2 
'new value' # Seems more or less ok 

>>> c = Child('one', 'two') 
arg1: one 
arg2: two 
>>> c.arg2 
'new value' # This is wrong, it has overridden the specified argument 'two' 
+0

이것은 일어날 수밖에 없습니다. 두 번째 예제에서'arg2'는'kwargs [ 'arg2']'가 아니라'args [1]'입니다. – jonrsharpe

+0

@jonrsharpe 네, 그리고 그것을 고칠 좋은 방법을 찾지 못하는 것 같습니다. –

답변

2

당신은 super()에에 전달하기 전에 kwargs의 기본을 설정해야합니다;

class Child(Parent): 
    def __init__(self, *args, **kwargs): 
     if len(args) < 2 and 'arg2' not in kwargs: 
      kwargs['arg2'] = 'new value' 
     super(Child, self).__init__(*args, **kwargs) 

이 그러나이 채우기 위해 얼마나 많은 인수를 알고에 의존 : 동일한 값이 너무 args에없는 것을 확인하기 위해 필요로하는이 까다 롭습니다.

from inspect import getargspec 

class Child(Parent): 
    def __init__(self, *args, **kwargs): 
     super_init = super().__init__ 
     argspec = getargspec(super_init) 
     arg2_index = argspec.args.index('arg2') - 1 # account for self 
     if len(args) < arg2_index and 'arg2' not in kwargs: 
      kwargs['arg2'] = 'new value' 
     super(Child, self).__init__(*args, **kwargs) 

당신은 떨어져 더 나은 것 대신 모든 기본값을 지정 :

class Child(Parent): 
    def __init__(self, arg1='something', arg2='new value'): 
     super(Child, self).__init__(arg1=arg1, arg2=arg2) 
+1

이 위험은'arg2'에 대해 두 개의 값을 가지며 위치 적으로 *와 *를 키워드로 전달합니까? – jonrsharpe

+0

'Child ('one ','two ')':'TypeError : __init __() 인수'arg2 '에 복수 값이 있습니다. –

+1

@jonrsharpe : 그렇습니다. 위험이 있습니다. –

2

당신은 실제로했습니다 당신이 일반적인 경우에 작동하도록 super().__init__의 반성을 사용해야 할 것 클래스의 서명을 변경했습니다. 기본적으로 :

foo(2, 3) 
foo(a=2, b=3) 

으로 :

def bar(**kwargs): 
    ... 

당신이 더 이상 위치 인수로 호출 할 수 없습니다

def foo(a=1, b=2): 
    ... 

당신은 키워드로 위치, 또는으로 호출 할 수 있습니다 :

bar(2, 3) # TypeError! 

*args을 가지고 있기 때문에 실제 코드에 추가로 복잡한 문제가 있습니다. 나는 당신을 줄 수


가장 강력한 조언은 당신이 방법 오버라이드 (override) 할 때 서명을 유지하는 것입니다

class Child(Parent): 
    def __init__(self, arg1='something', arg2='new value'): 
     super(Child, self).__init__(arg1=arg1, arg2=arg2) 

를이 (불행히도)는 DRY (자신을 반복하지 마십시오)로하지 않습니다 아마도 당신은 'something'을 두 번 지정해야합니다. 전역 상수로 변환하거나 Parent.__init__의 서명을 변경할 수 있습니다.

또는 부모 클래스의 서명을 사용하여 올바른 방법으로 올바른 인수를 전달할 수있는 일련의 인트로 스펙 션을 수행 할 수는 있지만 그만한 가치가 있음은 의심 스럽습니다.

관련 문제