Похоже, ваша цель состоит в том, чтобы сделать производный атрибут неизменным на родительском объекте, но позволить дочерним классам изменять его, не требуя, чтобы дочерние классы определяли @setter
для этого.Так что просто сделайте, чтобы родитель определял подкласс дружественные методы получения и установки свойств, которые явно запрещают работать с самим родительским классом:
class Configuration:
param1 = 'a'
@property
def param2(self):
try:
return self._param2 # If child has an override, use that value
except AttributeError:
return self.param1 + 'x' # Otherwise use parent default
@param2.setter
def param2(self, new_val):
# Treat as immutable on parent
if type(self) is Configuration:
raise AttributeError("can't set attribute")
# But allow it to be set on child
self._param2 = new_val # Or type(self)._param2 = new_val if it should be set on class
@param2.deleter
def param2(self):
# Treat as immutable on parent
if type(self) is Configuration:
raise AttributeError("can't delete attribute")
del self._param2 # Or del type(self)._param2 if it's a class attribute, not instance
Теперь экземпляры вашего ребенка могут клобер, unclobber и т. Д., Но исходный родительский класс можетне может быть изменено (вы можете сделать Configuration._param2 = 'new value'
вручную, но это нарушает соглашение о деталях реализации для имен с префиксом подчеркивания).
Обратите внимание, что если вам нужно , эти свойства для переноса атрибутов класса,не атрибуты экземпляра (поэтому изменение config.param2
должно изменить param2
для всех других экземпляров Proj1
), для согласованности вы бы хотели, чтобы поведение работало и при непосредственном назначении Proj1.param2
.Это выглядит ужасно, поскольку определение property
, которое работает с прямым доступом к атрибуту класса через класс, а не экземпляр, требует метакласса.Я не буду вдаваться в подробности здесь, но вы можете прочитать больше в нижней части мой ответ на вопрос, который требовал аналогичного решения .