About getters and setters in Python

Recently I’ve been developing a fairly large Python application, involving a somewhat articulate and deep class hierarchy. With time, I ended up writing a certain amount of getters and setters which felt suspiciously unpythonic. Looking for better solutions I stumbled upon a number of sources making fun of people writing getters and setters in Python (e.g. Python Is Not Java), because:

  • there’s no real data member protection in Python anyway (“we are all consenting adults here”)
  • if you later want to embed some logic in the retrieval of an attribute, you can keep the same interface by just adding a property

These arguments were so compelling that made me feel pretty stupid. Consequently, I immediately started converting all my getters and setters into variables or, when needed, into properties.

Unfortunately, it soon became apparent that I had not considered all the facets of the problem. Problems surfaced soon, primarily because, as I had to find out the hard way, avoiding getters/setters does not play that well with inheritance.

First of all, overriding the access of an attribute becomes a bit quirky — despite being perfectly acceptable when using getters. In particular, the child class must know if a certain attribute is indeed an attribute or a property — and this already breaks the promise of keeping the switch from variable to property a local change.

class Foo(object):
	@property
	def foo(self):
		return 5

class Bar(Foo):
	@property
	def foo(self):
		return Foo.foo.fget(self) + 1

print Foo().foo # 5
print Bar().foo # 6

The syntax gets really cumbersome. For instance, if you want to override only the getter or the setter, verbosity ensues:

class Foo(object):
	@property
	def foo(self):
		return 5

	@foo.setter
	def foo(self, val):
		print val

# one way to do that
class Bar1(Foo):
	@property
	def foo(self):
		return Foo.foo.fget(self) + 1

	@foo.setter
	def foo(self, val):
		return Foo.foo.fset(self, val)

# another way
class Bar2(Foo):
	def foo_get(self):
		return Foo.foo.fget(self) + 1

	def foo_set(self, val):
		return Foo.foo.fset(self, val)

	foo = property(foo_get, foo_set)

Foo().foo = 4
Bar1().foo = 3
Bar2().foo = 2

Granted, true Pythoners would say that this is not Python’s fault but mine, as I have evidently made some wrong, or at least unpythonic, design decisions at a higher level. That’s an acceptable criticism, but I still think that the organization of my program was fair when employing getters and setters. Most importantly, though, the consequences of substituting them in class hierarchies where overriding is common have not been sufficiently explained by the previously mentioned Internet sources.

In other words, sometimes “practicality beats purity“!

Use ack!

By misspelling awk during a search, I’ve come to know a very useful utility: ack. I wholeheartedly suggest to install it and use it as a drop in replacement for grep in most circumstances.

Basically, it’s a developer-friendly grep that, by default, ignores many annoying things that tend to get in the way nowadays, such as .svn folders. Other common options, such as recursiveness and “operate on all files in this directory” are assumed without the need of explicitly typing them. The output is structured, colored and highlighted in a meaningful and useful way — but it still plays well in a pipe, where it reverts to a more sober, grep-like output. It maintains a small (but extendable) database of filetypes, so that you can ask for specific categories of files to be included or not: for instance –noshell ignores .sh, .bash, .csh, .tcsh, .ksh, and .zsh files.

It’s also actively maintained.

It’s already an indispensable tool for me. Go grab it, you won’t regret it!