IT박스

파이썬 속성과 상속

itboxs 2020. 12. 24. 23:29
반응형

파이썬 속성과 상속


하위 클래스에서 덮어 쓰려는 속성 (get 메서드)이있는 기본 클래스가 있습니다. 내 첫 생각은 다음과 같았습니다.

class Foo(object):
    def _get_age(self):
        return 11

    age = property(_get_age)


class Bar(Foo):
    def _get_age(self):
        return 44

이것은 작동하지 않습니다 (하위 클래스 bar.age가 11을 리턴 함). 작동하는 람다 식으로 솔루션을 찾았습니다.

age = property(lambda self: self._get_age())

그렇다면 이것이 속성을 사용하고 하위 클래스에서 덮어 쓰기에 적합한 솔루션입니까, 아니면 다른 선호하는 방법이 있습니까?


클래스 메서드를 재정의 할 때 데코레이터 property()를 반복 할뿐만 아니라 반복하는 것을 선호합니다 @classmethod.

이것은 매우 장황 해 보이지만 적어도 Python 표준에서는 다음과 같은 것을 알 수 있습니다.

1) 읽기 전용 속성의 property경우 데코레이터로 사용할 수 있습니다.

class Foo(object):
    @property
    def age(self):
        return 11

class Bar(Foo):
    @property
    def age(self):
        return 44

2) 파이썬 2.6, 속성은 방법의 한 쌍의 성장 setter 하고 deleter있는 일반적인 속성에 읽기 전용 사람을위한 이미 사용할 수있는 바로 가기를 적용 할 수 있습니다 :

class C(object):
    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

선택한 답변이 속성 메서드를 재정의 할 수있는 이상적인 방법이라는 데 동의하지 않습니다. getter 및 setter가 재정의 될 것으로 예상하는 경우 람다를 사용하여 lambda self: self.<property func>.

이것은 Python 버전 2.4 ~ 3.6에서 (적어도) 작동합니다.

직접 property () 호출 대신에 속성을 데코레이터로 사용하여이 작업을 수행하는 방법을 아는 사람이 있다면 듣고 싶습니다!

예:

class Foo(object):
    def _get_meow(self):
        return self._meow + ' from a Foo'
    def _set_meow(self, value):
        self._meow = value
    meow = property(fget=lambda self: self._get_meow(),
                    fset=lambda self, value: self._set_meow(value))

이렇게하면 재정의를 쉽게 수행 할 수 있습니다.

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

그래서:

>>> foo = Foo()
>>> bar = Bar()
>>> foo.meow, bar.meow = "meow", "meow"
>>> foo.meow
"meow from a Foo"
>>> bar.meow
"meow from a Foo, altered by a Bar"

나는 괴짜 놀이에서 이것을 발견 했다 .


추가 클래스를 만들지 않고이를 수행하는 또 다른 방법입니다. 두 가지 중 하나만 재정의하는 경우 수행 할 작업을 보여주는 set 메서드를 추가했습니다.

class Foo(object):
    def _get_age(self):
        return 11

    def _set_age(self, age):
        self._age = age

    age = property(_get_age, _set_age)


class Bar(Foo):
    def _get_age(self):
        return 44

    age = property(_get_age, Foo._set_age)

이것은 꽤 인위적인 예이지만 아이디어를 얻어야합니다.


예, 이것이 그렇게하는 방법입니다. 속성 선언은 부모 클래스의 정의가 실행될 때 실행됩니다. 즉, 부모 클래스에 존재하는 메서드의 버전 만 "볼"수 있습니다. 따라서 자식 클래스에서 이러한 메서드 중 하나 이상을 재정의 할 때 메서드의 자식 클래스 버전을 사용하여 속성을 다시 선언해야합니다.


즉시 템플릿 방식으로 보이는 귀하의 솔루션에 동의합니다. 이 기사 는 문제를 다루고 정확하게 해결책을 제공합니다.


이런 식으로 작동합니다.

class HackedProperty(object):
    def __init__(self, f):
        self.f = f
    def __get__(self, inst, owner):    
        return getattr(inst, self.f.__name__)()

class Foo(object):
    def _get_age(self):
        return 11
    age = HackedProperty(_get_age)

class Bar(Foo):
    def _get_age(self):
        return 44

print Bar().age
print Foo().age

Same as @mr-b's but with decorator.

class Foo(object):
    def _get_meow(self):
        return self._meow + ' from a Foo'
    def _set_meow(self, value):
        self._meow = value
    @property
    def meow(self):
        return self._get_meow()
    @meow.setter
    def meow(self, value):
        self._set_meow(value)

This way, an override can be easily performed:

class Bar(Foo):
    def _get_meow(self):
        return super(Bar, self)._get_meow() + ', altered by a Bar'

I ran into problems setting a property in a parent class from a child class. The following workround extends a property of a parent but does so by calling the _set_age method of the parent directly. Wrinkled should always be correct. It is a little javathonic though.

import threading


class Foo(object):
    def __init__(self):
        self._age = 0

    def _get_age(self):
        return self._age

    def _set_age(self, age):
        self._age = age

    age = property(_get_age, _set_age)


class ThreadsafeFoo(Foo):

    def __init__(self):
        super(ThreadsafeFoo, self).__init__()
        self.__lock = threading.Lock()
        self.wrinkled = False

    def _get_age(self):
        with self.__lock:
             return super(ThreadsafeFoo, self).age

    def _set_age(self, value):
        with self.__lock:
            self.wrinkled = True if value > 40 else False
            super(ThreadsafeFoo, self)._set_age(value)

    age = property(_get_age, _set_age)

class Foo:
    # Template method
    @property
    def age(self):
        return self.dothis()
    # Hook method of TM is accessor method of property at here
    def dothis(self):
        return 11
class Bar(Foo):
    def dothis(self):
        return 44

Same as Nizam Mohamed, just to mention that style guide 2.13.4 using both template method and property

ReferenceURL : https://stackoverflow.com/questions/237432/python-properties-and-inheritance

반응형