свойства и наследование python
у меня есть базовый класс со свойством, которое (метод get) я хочу перезаписать в подклассе. Моя первая мысль была что-то вроде:
class Foo(object):
def _get_age(self):
return 11
age = property(_get_age)
class Bar(Foo):
def _get_age(self):
return 44
это не работает (подкласс бар.возвращает возраст 11). Я нашел решение с лямбда-выражением, которое работает:
age = property(lambda self: self._get_age())
Так это правильное решение для использования свойств и перезаписать их в подклассе, или есть другие предпочтительные способы сделать это?
8 ответов:
Я просто предпочитаю повторить
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
другой способ сделать это без создания дополнительных классов. Я добавил метод 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)
Это довольно надуманный пример, но вы должны уловить идею.
Я не согласен с тем, что выбранный ответ является идеальным способом для переопределения методов свойств. Если вы ожидаете, что геттеры и сеттеры будут переопределены, то вы можете использовать лямбда для обеспечения доступа к себе, с чем-то вроде
lambda self: self.<property func>
.это работает (по крайней мере) для версий Python 2.4-3.6.
если кто-нибудь знает способ сделать это с помощью property в качестве декоратора вместо прямого вызова 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"
я обнаружил это на технарь в игре.
Да, это способ сделать это; объявление свойства выполняется во время выполнения определения родительского класса, что означает, что он может только "видеть" версии методов, которые существуют в родительском классе. Поэтому, когда вы переопределяете один или несколько из этих методов в дочернем классе, вам нужно повторно объявить свойство, используя версию дочернего класса метода(ов).
Я согласен с вашим решением, которое, кажется, на лету шаблона. в этой статье сделки с вашей проблемой, и обеспечивает именно ваше решение.
что-то вроде этого будет работать
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'
я столкнулся с проблемами, устанавливая свойство в родительском классе из дочернего класса. Следующий workround расширяет свойство родителя, но делает это путем прямого вызова метода _set_age родителя. Морщины всегда должны быть правильными. Это немного javathonic, хотя.
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)