我需要使用/模仿语法糖语法在子类中动态装饰 getter 和 setter 对方法。
我正在努力解决 setter 的实现问题。
class A:
def __init__(self, x):
print('init')
self.__x = x
@property
def x(self):
print('getter')
return self.__x
@x.setter
def x(self, v):
print('setter')
self.__x = v
class Dec:
def __init__(self):
print('init - dec')
def __call__(self, cls):
c = type('A_Dec', (cls,), {})
# super-init
setattr(c, '__init__', lambda sub_self, x: super(type(sub_self), sub_self).__init__(x))
# getter
setattr(c, 'x', property(lambda sub_self: super(type(sub_self), sub_self).x))
# setter - see below
return c
dec_A = Dec()(A)
dec_a = dec_A('p')
print(dec_a.x)
Output
init - dec
init
getter
p
如果我尝试实现 setter 方法Dec
, dec_a.x = 'p'
,通过以下方法我收集了以下错误:
# setter-statements of __call__
# Attempt 1
setattr(c, 'x', property(fset=lambda sub_self, v: super(type(sub_self), sub_self).x(v)))
# AttributeError: unreadable attribute
# Attempt 2 - auxiliary function
def m(sub_self, v):
print('--> ', sf, super(type(sub_self), sub_self))
super(type(sub_self), sub_self).x = v
# Attempt 2.A
setattr(c, 'x', eval('x.setter(m)'))
# NameError: name 'x' is not defined
# Attempt 2.B
setattr(c, 'x', property(fset=lambda sf, v: m(sf, v)))
# AttributeError: unreadable attribute
# Attempt 2.C: !! both at once, `fget`and `fset` so, in case, comment the getter in the above code to avoid conflicts
setattr(c, 'x', property(fget=lambda sub_self: super(type(sub_self), sub_self).x, fset=m))
# AttributeError: 'super' object has no attribute 'x'
# Attempt 2.D
p = property(fget=lambda sub_self: super(type(sub_self), sub_self).x, fset=m)
setattr(c, 'x', p)
# AttributeError: 'super' object has no attribute 'x'
尝试1引发错误,因为(我猜)用括号设置属性。所以在尝试2我使用了辅助功能,因为lambda
不允许初始化、'='语句,同样没有成功。
-
有没有办法动态模仿属性 getter/setter 装饰器? (可能不需要额外的进口)
还有其他方法吗?
-
额外:为什么 super 没有属性就不起作用?super().x(v)
-> TypeError: super(type, obj): obj must be an instance or subtype of type
EDIT:
- 额外的答案:来自文档:零参数形式仅适用于类定义内部[...]
- 使用 python3.9