В сущности, проблема заключается в том, что метод get и метод set являются частью одного и того же атрибута класса. В @property
x
есть fget
, fset
и fdel
, которые составляют геттер, сеттер и удалитель (не обязательно все установлено). Они могут быть абстрактными и мешать инициализации, или просто не существовать.
В вашем class D
вы создаете новый @property
, который полностью переопределяет родительский @property
, так что больше нет никакого абстрактного установщика, который бы предотвращал Инициирование класса.
from abc import ABC, abstractmethod
class C(ABC):
@property
def x(self):
pass
@x.setter
@abstractmethod
def x(self, val):
pass
class D(C):
@property
def x(self):
pass
def examine_property(p):
print('get', p.fget, getattr(p.fget, '__isabstractmethod__', False) if p.fget is not None else None)
print('set', p.fset, getattr(p.fset, '__isabstractmethod__', False) if p.fset is not None else None)
print('del', p.fdel, getattr(p.fdel, '__isabstractmethod__', False) if p.fdel is not None else None)
print("C.x:")
examine_property(C.x)
print("D.x:")
examine_property(D.x)
Вывод:
C.x:
get <function C.x at 0x101ac4550> False
set <function C.x at 0x101ac45e0> True
del None None
D.x:
get <function D.x at 0x101ac4670> False
set None None
del None None
Итак, если вы хотите переопределить геттер, вам нужно очень точно указать c об этом, используя @C.x.getter
:
class D(C):
@C.x.getter
def x(self):
print("non-abstract getter")
Вывод:
C.x:
get <function C.x at 0x1022fb550> False
set <function C.x at 0x1022fb5e0> True
del None None
D.x:
get <function D.x at 0x1022fb670> False
set <function C.x at 0x1022fb5e0> True
del None None
Таким образом, вы не переопределяете целое property
, а только его конкретную c функцию.
I не будет go смешивать создание новых properties
и переопределение родителей, я видел это привередливое поведение в моем тестировании:
class D(C):
@property
def x(self):
pass
@C.x.setter
def x(self, val):
pass
print("D.x:")
examine_property(D.x)
Вывод:
D.x:
get <function C.x at 0x10cdd74c0> False
set <function D.x at 0x10cdd7670> False
del None None
# Our new override property is gone
Переупорядоченное определение класса:
class D(C):
@C.x.setter
def x(self, val):
pass
@property
def x(self):
pass
Выход:
D.x:
get <function D.x at 0x105048670> False
set None None
del None None
# We entirely lost the `setter`