Легко сделать свою реализацию. Все помнят, что property - всего лишь пример тривиальнейшего дескриптора?
Хотя бы такую (внимание, набор юнит-тестов, естественно, далеко не полон, да и что ожидать от трехминутной работы…)
class dynamic_property(object):
'''property with lazy method binding'''
def __init__(self, getter, setter=None, deleter=None, doc=None):
self._getter_name = getter.__name__
self._setter_name = setter.__name__ if setter is not None else None
self._deleter_name = deleter.__name__ if deleter is not None else None
self.__doc__ = doc
def __get__(self, instance, owner):
assert instance is not None #like standard property
getter = getattr(owner, self._getter_name)
return getter(instance)
def __set__(self, instance, value):
setter = getattr(instance.__class__, self._setter_name)
return setter(instance, value)
def __delete__(self, instance):
deleter = getattr(instance.__class__, self._deleter_name)
return deleter(instance)
import unittest
class A(object):
val = None
def _get(self):
return 'A._get_'+str(self.val)
def _set(self, val):
self.val = val
def _del(self):
self.val = 'deleted'
prop = dynamic_property(_get, _set, _del, 'doc-string')
class B(A):
def _get(self):
return 'B._get_'+str(self.val)
class Test_dynamic_property(unittest.TestCase):
def setUp(self):
self.a = A()
def test_get(self):
self.assertEqual('A._get_None', self.a.prop)
self.a.val = 'val'
self.assertEqual('A._get_val', self.a.prop)
def test_set(self):
self.assertEqual('A._get_None', self.a.prop)
self.a.prop = 'val'
self.assertEqual('A._get_val', self.a.prop)
def test_set(self):
self.assertEqual('A._get_None', self.a.prop)
self.a.prop = 'val'
self.assertEqual('A._get_val', self.a.prop)
def test_del(self):
self.a.prop = 'val'
self.assertEqual('A._get_val', self.a.prop)
del self.a.prop
self.assertEqual('deleted', self.a.val)
def test_overload(self):
b = B()
self.assertEqual('B._get_None', b.prop)
b.val = 'val'
self.assertEqual('B._get_val', b.prop)
if __name__ == '__main__':
unittest.main()
Обратите внимание на цену перегрузки: функции getter-setter приходится искать каждый раз. Объект prop один-единственный для всей иерархии, A и B его разделяют. Поэтому работает чуть медленней стандартного.