Property decorators are discussed at length in the documentation and the machinery which resolves them is discussed as well, but only for getters. I have been entirely unsuccessful in making a setter work for an uninstantiated class. Simple example:
My Property Decorator
class ClassyProp(object):
""" Classmethod + property """
def __init__(self, input_func):
log(f"ClassProp.__init__({input_func})")
self.func = input_func
def __get__(self, obj, cls=None):
log(f"ClassProp.__get__({obj}, {cls})")
return self.func
def __set__(self, obj, value):
log("__ClassyProp__.__set__()")
def setter(self, fset):
log("__ClassyProp__.setter()")
def fset(*args):
log("__ClassyProp__.fset()")
Test Class
class foo(object):
""" Test class """
def __init__(self):
pass
@ClassyProp
def f(cls):
""" Test property_lazy_static get , set """
pass
Run
print("======== ObjFoo ========")
ObjFoo = foo()
print(ObjFoo.f)
ObjFoo.f = 18
print(ObjFoo.f)
print("======== class foo ========")
print(foo.f)
foo.f = 15
print(foo.f)
Yields
[ 00s] ClassProp.__init__(<function foo.f at 0x7f4330c88268>)
======== ObjFoo ========
[ 00s] ClassProp.__get__(<__main__.foo object at 0x7f4351522748>, <class '__main__.foo'>)
<function foo.f at 0x7f4330c88268>
[ 00s] __ClassyProp__.__set__()
[ 00s] ClassProp.__get__(<__main__.foo object at 0x7f4351522748>, <class '__main__.foo'>)
<function foo.f at 0x7f4330c88268>
======== class foo ========
[ 00s] ClassProp.__get__(None, <class '__main__.foo'>)
<function foo.f at 0x7f4330c88268>
15
NOTE: If I had ClassyProp return values it wouldn't say the function id, does say proper values for get, but I just wanted print outs for the purpose of debugging.
As you can see, the getter AND setter is called properly for the Instance of ObjFoo. But not for the uninstantiated class foo. Is having a property setter simply not possible on classes? The documentation states (I added breaks):
For objects, the machinery is in
- object.getattribute() which transforms b.x into
- type(b).dict['x'].get(b, type(b))The implementation works through a precedence chain that
- gives data descriptors priority over instance variables,
- instance variables priority over non-data descriptors, and
- assigns lowest priority to getattr() if provided.
and
For classes, the machinery is in:
- type.getattribute() which transforms B.x into
- B.dict['x'].get(None, B)
With no mention of __set__ for either. (get obviously is working for both the class and the instance)
So I am left wondering now, is this possible? I see nothing in the documentation suggesting it isn't, but all testing suggests this.