Python Coding Style – When Is It Not Pythonic to Use Properties?

coding-stylepropertiespython

It's widely agreed that Python's properties are not merely a kludge for working around the past mistake of exposing of publicly exposing data members. But then when is it not Pythonic to use a property instead of a method that doesn't take any arguments?

For example, if we were writing the Python standard library from scratch, would it be more Pythonic to replace dict.items() with dict.items? We could even add a setter with perfectly intuitive behavior. That feels wrong but I can't articulate rules for what is and isn't a Pythonic use of properties that would disqualify this use. One obvious rule might be that if there's no reasonable setter, then properties shouldn't be used. That disqualifies dict.values() and dict.keys() but not dict.items().

Obviously style can be subjective, but since it's a Python motto that "There should be one — and preferably only one — obvious way to do it.", I think this question is reasonable. Also, let's try to stick to the PEPs and code in the Python standard library.

Best Answer

This problem is not specific to Python, but is shared by any language with properties, e.g. C#. And since there is only syntactic difference between getters and properties, this is the same question as whether we should use a getter-like method or a normal method.

In general:

  • Prefer properties where you would have otherwise used a getter method.
  • Prefer properties/getters when you are conceptually accessing a property of the object, and not telling the object to do some work. Getters and even more so properties come with the expectation that they are fast, and run in O(1) time.
  • Prefer ordinary methods if you're telling the object to do something, if the operation is expensive, or if you need to supply arguments. (Although for a single argument, a __getitem__-interface can sometimes be appropriate in cases where you would otherwise use a property.)
  • Whether a property is read-only or not is not in itself a good indicator of whether a property or a method would be more idiomatic.

In case of a dictionary, these are often implemented in a way that allows cheap iteration over entries, keys, and values. It would then be feasible to use dict.items, dict.keys properties that return an iterator. This is in fact a big difference between Python 2 and 3: in Python 2, these would all return lists that would have to eagerly traverse all entries, not just return a cheap view object as in Python 3. So it was a sensible design in Python 2 to use methods. In Python 3 this is only a sensible design because of backwards compatibility.

Note that while the “Zen of Python” is a nice goal, it is not a good description for a language that has accumulated a lot of cruft and weird corners over the years. As in all things, you will have to use your own judgement rather than relying on a vague motto.

Related Topic