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.