파생 클래스에서이 속성을 덮어 쓰는 경우 기본 클래스의 속성을 호출하는 방법은 무엇입니까?


88

getter 및 setter의 광범위한 사용에서 속성의 비단뱀 사용으로 일부 클래스를 변경하고 있습니다.

하지만 이제는 이전 getter 또는 setter 중 일부가 기본 클래스의 해당 메서드를 호출 한 다음 다른 작업을 수행하기 때문에 문제가 발생합니다. 그러나 이것이 속성으로 어떻게 이루어질 수 있습니까? 부모 클래스에서 속성 getter 또는 setter를 호출하는 방법은 무엇입니까?

물론 속성 자체를 호출하는 것만으로도 무한 재귀를 얻을 수 있습니다.

class Foo(object):

    @property
    def bar(self):
        return 5

    @bar.setter
    def bar(self, a):
        print a

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return self.bar # --> recursion!

    @bar.setter
    def bar(self, c):
        # perform the same action
        # as in the base class
        self.bar = c    # --> recursion!
        # then do something else
        print 'something else'

fb = FooBar()
fb.bar = 7

답변:


103

속성에 의해 호출되는 기본 클래스 함수를 호출 할 수 있다고 생각할 수 있습니다.

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar(self)

이것이 시도해 볼 수있는 가장 명백한 것임에도 불구하고 , bar는 콜 러블이 아니라 속성이기 때문에 작동하지 않습니다.

그러나 속성은 해당 속성을 찾는 getter 메서드가있는 개체 일뿐입니다.

class FooBar(Foo):

    @property
    def bar(self):
        # return the same value
        # as in the base class
        return Foo.bar.fget(self)

Foo.bar.fset(self, c)상속 된 setter를 호출해야하는 이유는 무엇 입니까? Foo.bar.fset(c)"자기"없이는 왜 안 되겠습니까?
nerdoc

2
TypeError : 'property'개체를 호출 할 수 없습니다
hithwen dec

@nerdoc selfget은 체인에서 어디를 의미 Foo.bar.fset합니까?
Tadhg McDonald-Jensen

그냥 생각-AFAIK 자체는 항상 암시 적으로 전달됩니다. foo = Foo()\를 하면 self 는 전달 foo.bar(c)되지 않지만 bar () 는 파이썬에서 그것을받습니다. 저는 Python 전문가가 아니며 어느 정도 초보자이기도합니다. 그것은 단지 생각입니다.
nerdoc

self메서드가 클래스의 인스턴스에서 호출 될 때만 암시 적으로 전달됩니다. 예를 들어 A메서드 가있는 클래스 가 있고 b(self, arg)인스턴스를 만드는 경우 c = A()호출 c.b(arg)은 다음 과 같습니다.A.b(c, arg)
TallChuck

55

Super 가 트릭을해야합니다.

return super().bar

Python 2.x에서는보다 자세한 구문을 사용해야합니다.

return super(FooBar, self).bar

1
TypeError : super ()는 적어도 하나의 인수 (0이 주어짐)를
취합니다

4
나는 (글쎄, 링크 : P로 판단)이 대답은 python3과 관련이 있습니다. python3에서 super ()는 0 인수를 취할 수 있습니다.
shylent 2009-06-20

6
super (). bar는 getter에서 제대로 작동하는 것 같지만 재정의 된 setter에서 기본 속성을 통한 할당에는 작동하지 않습니다. . 나는 슈퍼 할 경우 () 바 = 3 I GET AttributeError : '슈퍼'개체가 어떤 속성 '바'가 없다
롭 Smallshire

1
좋은 지적 롭, 몰랐습니다. 여기에 자세한 정보는 다음과 같습니다 stackoverflow.com/questions/10810369/...
Pankrat

2
이것은 얻기 위해 작동하지만 AttributeError.
Ethan Furman

25

사용하는 대안이 있습니다 super기본 클래스 이름을 명시 적으로 참조 할 필요가없는 이 있습니다.

기본 등급 A :

class A(object):
    def __init__(self):
        self._prop = None

    @property
    def prop(self):
        return self._prop

    @prop.setter
    def prop(self, value):
        self._prop = value

class B(A):
    # we want to extend prop here
    pass

B에서 부모 클래스 A의 속성 getter에 액세스 :

다른 사람들이 이미 대답했듯이 다음과 같습니다.

super(B, self).prop

또는 Python 3에서 :

super().prop

이것은 getter 자체가 아니라 속성의 getter가 반환 한 값을 반환하지만 getter를 확장하는 것으로 충분합니다.

B에서 부모 클래스 A의 속성 setter에 액세스 :

지금까지 본 최고의 권장 사항은 다음과 같습니다.

A.prop.fset(self, value)

나는 이것이 더 낫다고 믿는다.

super(B, self.__class__).prop.fset(self, value)

이 예에서 두 옵션은 모두 동일하지만 super를 사용하면의 기본 클래스와 독립적이라는 이점이 B있습니다. 속성을 확장 B하는 C클래스 에서 상속하는 경우 B의 코드 를 업데이트 할 필요가 없습니다 .

A의 속성을 확장하는 B의 전체 코드 :

class B(A):
    @property
    def prop(self):
        value = super(B, self).prop
        # do something with / modify value here
        return value

    @prop.setter
    def prop(self, value):
        # do something with / modify value here
        super(B, self.__class__).prop.fset(self, value)

한 가지주의 사항 :

속성에 setter가 없으면 둘 B중 하나의 동작 만 변경하더라도 setter와 getter를 모두 정의 해야합니다.


안녕하세요, 매우 도움이됩니다. 이에 대한 후속 질문이 있습니다. 이 설정은 잘 작동합니다. 그러나 추가 속성을 정의하기 위해 B에 대해 init 를 설정하면 작동이 중지됩니다 . B에 대해 별도의 초기화 를 갖는 방법이 있습니까? 감사합니다
Sang

super(B, self.__class__)정확히 어떻게 작동 하는지 설명해 주 super(class, class)시겠습니까? 어디에 문서화되어 있습니까?
Art

나는 내 대답
Eric

4

시험

@property
def bar:
    return super(FooBar, self).bar

파이썬이 기본 클래스 속성 호출을 지원하는지 확실하지 않지만. 속성은 실제로 지정된 함수로 설정된 다음 클래스에서 해당 이름을 대체하는 호출 가능한 객체입니다. 이것은 사용 가능한 슈퍼 기능이 없음을 쉽게 의미 할 수 있습니다.

그래도 항상 property () 함수를 사용하도록 구문을 전환 할 수 있습니다.

class Foo(object):

    def _getbar(self):
        return 5

    def _setbar(self, a):
        print a

    bar = property(_getbar, _setbar)

class FooBar(Foo):

    def _getbar(self):
        # return the same value
        # as in the base class
        return super(FooBar, self)._getbar()

    def bar(self, c):
        super(FooBar, self)._setbar(c)
        print "Something else"

    bar = property(_getbar, _setbar)

fb = FooBar()
fb.bar = 7

이것은 기본 클래스를 작성하면 잘 작동합니다. 그러나 속성과 게터에 동일한 이름을 사용하는 타사 기본 클래스를 확장하면 어떻게 될까요?
akaihola 2013 년

1

Maxime의 답변에 대한 몇 가지 작은 개선 사항 :

  • __class__쓰기를 피하기 위해 사용 B. 주 self.__class__의 실행시의 형태이다 self,하지만 __class__ 하지 않고는 self 바깥 쪽 클래스 정의의 이름입니다. super()super(__class__, self).
  • 사용 __set__대신에 fset. 후자는 propertys에만 해당되지만 전자는 모든 속성 유사 객체 (설명자)에 적용됩니다.
class B(A):
    @property
    def prop(self):
        value = super().prop
        # do something with / modify value here
        return value

    @prop.setter
    def prop(self, value):
        # do something with / modify value here
        super(__class__, self.__class__).prop.__set__(self, value)

0

다음 템플릿을 사용할 수 있습니다.

class Parent():
    def __init__(self, value):
        self.__prop1 = value

    #getter
    @property
    def prop1(self):
        return self.__prop1

    #setter
    @prop1.setter
    def prop1(self, value):
        self.__prop1 = value

    #deleter
    @prop1.deleter
    def prop1(self):
        del self.__prop1
  
class Child(Parent):

    #getter
    @property
    def prop1(self):
        return super(Child, Child).prop1.__get__(self)

    #setter
    @prop1.setter
    def prop1(self, value):
        super(Child, Child).prop1.__set__(self, value)

    #deleter
    @prop1.deleter
    def prop1(self):
        super(Child, Child).prop1.__delete__(self)

노트! 모든 속성 메서드를 함께 다시 정의해야합니다. 모든 방법을 재정의하지 않으려면 대신 다음 템플릿을 사용하십시오.

class Parent():
    def __init__(self, value):
        self.__prop1 = value

    #getter
    @property
    def prop1(self):
        return self.__prop1

    #setter
    @prop1.setter
    def prop1(self, value):
        self.__prop1 = value

    #deleter
    @prop1.deleter
    def prop1(self):
        del self.__prop1


class Child(Parent):

    #getter
    @Parent.prop1.getter
    def prop1(self):
        return super(Child, Child).prop1.__get__(self)

    #setter
    @Parent.prop1.setter
    def prop1(self, value):
        super(Child, Child).prop1.__set__(self, value)

    #deleter
    @Parent.prop1.deleter
    def prop1(self):
        super(Child, Child).prop1.__delete__(self)

-4
    class Base(object):
      def method(self):
        print "Base method was called"

    class Derived(Base):
      def method(self):
        super(Derived,self).method()
        print "Derived method was called"

    d = Derived()
    d.method()

(당신의 설명에서 빠진 것이 없다면)


1
당신은 다음과 같습니다 그는 일반되지 메서드, 속성에 대해서 이야기
akaihola
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.