Python class @property: use setter but evade getter? Python class @property: use setter but evade getter? python python

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)