Вопрос

У меня есть базовый класс со свойством, которое (метод 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) в Python 2.6 в свойства выросли пара методов setter и deleter , которые можно использовать для применения к общим свойствам ярлыка, уже доступного только для чтения:

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

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

Другие советы

Я не согласен с тем, что выбранный ответ является идеальным способом переопределить методы свойств.Если вы ожидаете, что геттеры и сеттеры будут переопределены, вы можете использовать лямбда-выражение для предоставления доступа к себе, например lambda self: self.<property func>.

Это работает (по крайней мере) для версий Python от 2.4 до 3.6.

Если кто-нибудь знает способ сделать это, используя свойство в качестве декоратора вместо прямого вызова свойства(), я хотел бы это услышать!

Пример:

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

То же, что и @ mr-b , но с декоратором.

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)

Таким образом, переопределение может быть легко выполнено:

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

Я столкнулся с проблемами при установке свойства в родительском классе из дочернего класса. Следующая рабочая среда расширяет свойство родителя, но делает это путем непосредственного вызова метода _set_age для родителя. Морщинистый всегда должен быть правильным. Это немного джаватонично, хотя.

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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top