I’m making a small project every day in python for the next 30 days (minus some vacation days). I’m hoping to learn many new packages and make a wide variety of projects, including games, computer tools, machine learning, and maybe some science. It should be a good variety and I think it will be a lot of fun.
Day 14: Properties, A Python Idiom
Today’s project was to learn how to use properties in Python. I put this project in my queue back when I was working on Tetris and Snake. Because I had learned to write ‘set’ and ‘get’ methods from dabbling in Java, I found myself habitually using them all over the place to handle the position, velocity, and rotation of the tetris piece, blocks, sprites, and snake segments. It was really tedious, and I knew that Python was supposed to better than this.
Through a quick Google search, I found PJ Eby’s Python is not Java:
Pretend that Python is a magic wand that will miraculously do whatever you want without you needing to lifting a finger. Ask, “how does Python already solve my problem?” and “What Python language feature most resembles my problem?” You will be absolutely astonished at how often it happens that thing you need is already there in some form. In fact, this phenomenon is so common, even among experienced Python programmers, that the Python community has a name for it. We call it “Guido’s time machine”, because sometimes it seems as though that’s the only way he could’ve known what we needed, before we knew it ourselves.
This was a promising start, especially since he also said, “Getters and setters are evil. Evil, evil, I say!”
Instead of translating your coding behavior from Java to Python directly, he suggests you take a step back and learn the features of Python that allow you to truly use the language – not fight it. These features of Python are what are colloquially known as “Python Idioms.” Features such as list comprehensions, properties, and many others are distinct in Python. They don’t directly translate. I knew roughly what an idiom was, but since it kept showing up in every Python blog post and question on Stack Overflow (the Q&A forum), I thought it best to get a solid definition from wikipedia:
An idiom is a combination of words that have a figurative meaning owing to its common usage.
Which is simple enough, but my first reaction was: why would you want to fill a language that strives for clarity with idioms? Wouldn’t you want clear, simple words with no figurative meaning? But as I thought about this more I realized that idioms are what actually make a language clear, even if not at the word by word level. When you literally translate one language to another, say French to English, you end up with all sorts of awkwardness: “s’il vous plait” becomes “if it pleases you.” While that works, what the speaker really means is simply “please.” In English you can say “Fred kicked the bucket” which means “Fred died” but those two aren’t quite interchangeable. There is a subtle difference. The former accomplishes more. It removes some of the sadness and it adds some separation to the event, softening the blow. An idiom carries extra meaning beyond what is indicated by the individual words – it’s meaning is greater than the sum of its parts.
When switching from Java to Python you can’t translate word for word. You have to translate at the figurative level; don’t literally translate, idiomatically translate. Here’s an example of a the property idiom (the last few lines):
def set_pos(self, pos):
'''Sets the position of the tetroid'''
self._pos = pos
'''Gets the position of the tetroid'''
pos = property(get_pos, set_pos)
my_tetroid = Tetroid(old_pos,...)
#blocks are updated without calling a set method:
my_tetroid.pos = new_pos
I highly recommend Ryan Tomayko’s take on the specific getter/setter problem in this follow up to PJ Eby as a beginner’s introduction to using properties instead of ‘sets’ and ‘gets’ littering your code. Having started my journey with the frustration of the tedium of ‘sets’ and ‘gets’, I found this line particularly inspiring:
Programming languages are for humans, not machines. If you have code that looks like it doesn’t do anything useful, is hard to read, or seems tedious, then chances are good that Python has some language feature that will let you remove it.
Now for my particular usage of properties:
- I deleted useless straight pass through sets/gets
- Sprite has a position property that ensures it has its own copy of the list when the position is set
- Sprite has rotation and rotation matrix properties, making it easy to calculate offset points that rotate relative to the sprite for drawing
- Tetroid inherits from Sprite
That last one was really cool to get working and is my best example of the property idiom being more than just sets and gets. Tetroid is a sprite that has a list of four blocks which are also sprites. It was its own object type that had special rotation features that duplicated Sprite features but handled updating its four blocks. Now to update the Tetroid position you can just set its position with a new value. The property takes care of finding the set method which then updates all the blocks and the whole thing moves. The same thing works for rotation. Worrying about updating all the parts in many places is replaced with updating the whole and letting it take care of the rest.
Now I will be the first to admit that my usage of properties is still not idiomatic. I know decorators can do very cool things but I just haven’t learned how to use them yet. From PJ Eby’s post, it seems like there’s a way to use functions of functions to get the input handling that I want with even less duplication. So there is more work to be done, but the work has already paid off. The latest version of Tetris has a proper preview pane and it was easy to write because I could just set the Tetroid’s position and move on.
Learning how to use properties in Python – and seeing that programming by idiom is more that just a buzzword- has made me excited to use the Python magic wand. I look forward to taking many more trips in Guido’s time machine.
For those who are interested here’s my github repo for the games project: https://github.com/robb07/python_games