Python class @property: use setter but evade getter?
Don't use a property
in this case. A property
object is a data descriptor, which means that any access to instance.var
will invoke that descriptor and Python will never look for an attribute on the instance itself.
You have two options: use the .__setattr__()
hook or build a descriptor that only implements .__set__
.
Using the .__setattr__()
hook
class MyClass(object): var = 'foo' def __setattr__(self, name, value): if name == 'var': print "Setting var!" # do something with `value` here, like you would in a # setter. value = 'Set to ' + value super(MyClass, self).__setattr__(name, value)
Now normal attribute lookups are used when reading .var
but when assigning to .var
the __setattr__
method is invoked instead, letting you intercept value
and adjust it as needed.
Demo:
>>> mc = MyClass()>>> mc.var'foo'>>> mc.var = 'bar'Setting var!>>> mc.var'Set to bar'
A setter descriptor
A setter descriptor would only intercept variable assignment:
class SetterProperty(object): def __init__(self, func, doc=None): self.func = func self.__doc__ = doc if doc is not None else func.__doc__ def __set__(self, obj, value): return self.func(obj, value)class Foo(object): @SetterProperty def var(self, value): print 'Setting var!' self.__dict__['var'] = value
Note how we need to assign to the instance .__dict__
attribute to prevent invoking the setter again.
Demo:
>>> f = Foo()>>> f.var = 'spam'Setting var!>>> f.var = 'ham'Setting var!>>> f.var'ham'>>> f.var = 'biggles'Setting var!>>> f.var'biggles'
property
python docs: https://docs.python.org/2/howto/descriptor.html#properties
class MyClass(object): def __init__(self): self._var = None # only setter def var(self, newValue): self._var = newValue var = property(None, var)c = MyClass()c.var = 3print ('ok')print (c.var)
output:
okTraceback (most recent call last): File "Untitled.py", line 15, in <module> print c.varAttributeError: unreadable attribute
The @WeizhongTu answer
class MyClass(object): def __init__(self): self._var = None # only setter def var(self, newValue): self._var = newValue var = property(None, var)c = MyClass()c.var = 3print ('ok')print (c.var)
Is fine, except from the fact that is making the variable ungettable...
A similar solution but preserving getter is with
var = property(lambda self: self._var, var)
instead of
var = property(None, var)