I’m a fledgling programmer, experienced enough to write code that works and solves real business problems but by no means a seasoned software engineer. I mainly code in Python, and as I gain experience I find myself reading code written by other programmers more and more frequently. I’m usually reading the code of mature, highly regarded tools (e.g., Requests, Ansible, some lesser-known but clearly high-quality tools), and I can’t help but notice that the people who write this code tend to take a much more object-oriented approach than I do. In particular, they use classes in situations where I would use modules, and objects in situations where I would use dicts or tuples (or named tuples, which I’m fond of). The style I’ve developed so far is to use a module when I’m trying to bundle related functions that don’t manage state, and to use classes when state-management is inherent to the problem and I want to shield clients from it (or “encapsulate” it).
On the one hand, I don’t want to blindly imitate programmers who are dealing with problems of a different type (or scale) than those I’m dealing with and end up making my own code unnecessarily complex. I sometimes have an imaginary conversation with a composite “seasoned Python programmer” in which I proudly show him code that I’ve written as a collection of classes, and he looks at me quizzically and says, “Why did you write all these classes to solve this problem? I would have just used modules.”
On the other hand, as I’ve matured as a programmer I’ve noticed that my code has started to look more like the code I read, not due to conscious imitation, but because I’ve improved and those improvements have naturally made my code look more like the code of more experienced programmers. If I’m inevitably going to rediscover the reason for using objects when state isn’t an issue, I might as well just be told what I’m missing and save myself some time (and spare my employer the inferior code that I’ll be writing in the interim).
Classes also has some extra trickery over modules which you can use and abuse. Such as __getattr__ and __getitem__.