Search code examples
pythonclassoopencapsulation

Is It "Python-esque" to wrap all functions in a class?


So, I'm developing a simple web-scraper in Python right now, but I had a question on how to structure my code. In other programming languages (especially compiled languages like C++ and C#), I've been in the habit of wrapping all of my functions in classes. I.e. in my web-scraping example I would have a class called something like "WebScraper" maybe and then hold all of the functions within that class. I might even go so far as to create a second helper class like "WebScraperManager" if I needed to instantiate multiple instances of the original "WebScraper" class.

This leads me to my current question, though. Would similiar logic hold in the current example? Or would I simply define a WebScraper.py file, without a wrapper class inside that file, and then just import the functions as I needed them into some main.py file?


Solution

  • The difference between a class and a function should be that a class has state. Some classes don't have state, but this is rarely a good idea (I'm sure there's exceptions, abstract base classes (ABCs) for instance but I'm not sure if they count), and some functions do have state, but this is rarely a good idea (caching or instrumentation might be exceptions).

    If you want an URL as input, and say a dict as output, and then you are done with that website, there's no reason to have a class. Just have a function that takes an URL and returns a dict. Stateless functions are simpler abstractions than classes, so all other things being equal, prefer them.

    However, very often there may be intermediate state involved. For instance, maybe you are scraping a family of pages rooted in a base URL, and it's too expensive to do all this eagerly. Maybe then what you want is a class that takes the root URL as its constructor. It then has some methods for querying which child URLs it can follow down, and methods for ordering subsequent scraping of children, which might be stored in nested data structures.

    And of course, if your task is reasonably complicated, you may well have layers with functions using classes, or classes calling function. But persisting state is a good indicator of whether the immediate task should be written as a class or set of functions.

    Edit: just to close the loop and come round to the original question: No, I would say it's not pythonesque to wrap all functions in classes. Free functions are just fine in python, it all depends what's appropriate. Also, the term pythonesque is not very pythonic ;-)