As you probably know very well, in Python you can add properties to your classes. They behave like instance fields syntactically, but under the hood they call accessor functions whenever you want to get or set the property value:
Often – like in the example above – properties are read-only, providing only the getter method. It’s very easy to define them, too: just stick a @property
decorator above method definition and you’re good to go.
Occasionally though, you will want to define a read-write property. (Or read-delete, but those are very rare). One function won’t cut it, since you need a setter in addition to getter. The canonical way Python docs recommend in such a case (at least since 2.6) is to use the @property.setter
decorator:
Besides that I find it ugly to split a single property between two methods, this approach will annoy many static code analyzers (including PEP8 checker) due to redefinition of x
. Warnings like that are very useful in general, so we certainly don’t want to turn them off completely just to define a property or two.
So if our analyzer doesn’t support line-based warning suppression (like, again, pep8), we may want to look for a different solution.
I’ve found one by complete accident: I unintentionally triggered autocompletion for “property” stem in my text editor. When you do that inside Python file opened in Sublime Text 2, you will be served with the following template snippet (which has multiple cursors conveniently placed at every occurrence of foo
– yes, Sublime is that awesome):
As you can see, this is quite clever trick. We define a function returning dictionary of keyword arguments for property
; these include getter and optionally setter, deleter and/or docstring. It just happens that this dictionary is simply the dict
of locals()
, cleverly named to match the argument names for property
.
Neat, isn’t it? Best part is that it looks almost like a dedicated syntactic construct, kinda like the property block in C#. It’s almost self-contained, too: just the property
call at the end stands out like a sore thumb.
I thought I could fix that, as well as the weird docstring-in-variable shenanigan. Most importantly, I wanted a decorator back again, since I consider them one of the most beautiful features in Python.
And so I made an objectproperty
decorator, with code published in this gist. It allows to improve the previous example and arrive at the following syntax:
With some stubbornness and stackframe trickery, you might be able to get rid of the return locals()
at the end. But this is the level of magic I dare not to approach, recommending others to do likewise :)
If you really want to get rid of locals, you can change def
to class
:
https://gist.github.com/4340763
So much hacking for a simple thing, huh?
Too bad you can’t just say:
@x.setter
def x_set(self, value):