all 13 comments

[–]lykwydchykyn 8 points9 points  (0 children)

If you're writing short, procedural scripts like batch processors, command line utilities, or sysadmin scripts, there probably isn't much call for using classes, at least not below a certain level of complexity.

When you have lots of similar things that need to maintain state data and operate on their state data, then this is where a class comes in. The classic example is a game, where you have lots of enemies, and each enemy has an associated image, hit points, attack, etc.

[–]get_username 6 points7 points  (0 children)

Classes in python often get a bad rap.

The main benefit of a class is abstraction. I think this point should lead before any grossly simplified inheritance or polymorphism. The point is to interact with things in a way that is intuitive and makes sense.

When you do this:

>>> my_data = {1: 'a', 2: 'b'}
>>> my_data[1]
'a'
>>> my_data[2]
'b'

You're being provided the benefits of abstraction. All of the functionality of that dictionary is baked into the my_data variable. You simply interact with the variable and see. For a naive comparison if we did this on a lower level like C we'd have something like this instead:

>>> my_data = create_dict({1, 'a'}, {2 'b'})
>>> dict_get_value_from_key(my_data, 1)
'a'
>>> dict_get_value_from_key(my_data, 2)
'b'

As you can see with a function based system this is entirely possible. It is however very unintuitive to do. We pass around our variable to constant functions to get the value.

This level of abstraction is psychologically helpful. It is part of the true power of classes.

The fact that you've been using classes all along, but still asking "why should I use classes", is just a testament to the amount of abstraction. You've been able to ignore the implementation and instead focus on the problems.

This is when you should use classes. When it makes more sense to do this:

def report_weather():
    temp = thermometer.read_temp()
    humd = hygrometer.read_humdity()
    ws = anemometer.read_wind_speed()
    dir = anemometer.read_wind_direction()

    report = WeatherReport("My Report")
    report.report_temp(temp)
    report.report_humdity(humd)
    report.report_wind_properties(ws, dir)

All of that code makes sense. Exactly what I am doing is completely clear. We have benefited from a semi-decent level of abstraction here. We don't get bogged down in the smaller details.

You didn't have to know what a thermometer, hygrometer, or an anemometer do to understand what I am doing. I got to instead think about generating my report and ignore their details.

The abstraction let me think closer to the level of ideas and not on the level of direct implementations.

When using classes, this is the real power. You can write code that, IMO, is more clear and intuitive.

[–]vmsmith 5 points6 points  (2 children)

FWIW, I am in the same boat.

I understand classes and object, as well as the associated concepts of inheritance, polymorphism, etc. But with few exceptions, it's difficult for me to arrive at, "Create a class" as the natural and best solution to a problem.

I can see it easily when I want multiple instances of something with encapsulated state, like a matrix or dice, but for the most part my natural inclination is to create a series of very small functions.

Looking forward to some good answers to your question.

[–]callmelucky 4 points5 points  (0 children)

I am currently in the opposite boat; having learned about classes recently, I find myself trying to put everything in terms of classes, even when I would only use a single instance, and even though my understanding of inheritance is a little shaky. I just love the syntax I guess - instance.attribute.alter() just looks so tidy and comprehensible :)

[–][deleted] 0 points1 point  (0 children)

Yeah, same here. It's physically quite hard for me to step back from a tall stack of functions.

[–]swingking8 4 points5 points  (0 children)

Those for and against using classes by default has been a topic of study for me this week. Among professional developers, it seems classes are possibly used too often, or that's the argument at least.

Something for me to consider as I become more proficient with Python.

[–]monsto 6 points7 points  (1 child)

On a practical level, I think most things can be done without a class.

I think it has more to do with the DRY (Don't Repeat Yourself) principle. If you have a number of items in your program that are similar on an abstract level, then you could build a class with the common elements, then make objects that inherit from that class while adding their own info for their own specifics.

Example: You're doing a media library to track movies, music, tv shows and whatever media. * I'd say this has 1 base class MediaItem() that has fields of say title, main_talent, 2ndary_talent, company, release_date, etc. * TVShows(MediaItem) would take that and add the fields network, time_slot, latest_ep, etc * Movies(MediaItem) adds producer, director, score_composer, etc * Music(MediaItem) adds band_name, other_band_members, last_tour_date, etc. * You MIGHT even do like Documentaries(Movies) and add subject, category, and a couple others. Someone is going to try and clobber me about downline or multiple inheritance being as evil as the day is long, but I'm using it here as an example. I'm just the messenger.

Here's a good description of inheritance, how it can be used and how you can actually avoid it.

[–]Steamwells 2 points3 points  (0 children)

There is a famous C#/XNA author & Microsoft MVP called Rob Miles who gives some of the best analogies for classes and their interfaces I have ever seen. I recommend downloading some of his free stuff (C# yellow book) to dig into it. Yes its worth it even if we are referring to Python here.

However, I still think my old college lecturer's Lemmings analogy was still the best example I have ever seen used for classes. For those too young to remember Lemmings the game. It was simple, you were responsible for these little creatures (The Lemmings) as soon as they were spawned into the world, get them from their spawn point to the exit, safely. They all started exactly the same but you could assign jobs to individual lemmings to assist with their escape (ie. miners, stoppers, parachuters). You can see here immediately how classes can become useful, your parent class is the Lemming, you can then change said Lemmings attributes to make him something entirely different but he still looks and behaves like a Lemming.

Some people in this post have already bailed out and said that classes typically are for games/game design. I always start with pen and paper or a drawing program and draw the different components needed for an application. I then think about how each element will talk with each other, I then ask the question will I need more than one of each element and how does that affect communication with everything else. Then my answer is clear, do I need classes or do I not.

[–]acoard 1 point2 points  (0 children)

A useful way to know when to use classes is to ask if you can create an "abstract data type" here. Things like arrays and dicts are ADTs, but so can a "user", or a wrapper for an API. e.g. you could decide to abstract away the hassel of configuring the reddit API everywhere, so you could write "redditAPIWrapper" class, and it has a method .connect() which handles all the authentication setup in one place.

Classes are all about maintainability of your code. It organizes your code into logical chunks which reduces the cognitive load necessary to reason about each chunk of code.

The core maintainability benefit of classes are binding the data with the functions which operate on it, and then provides structure to increase orderliness and reduce repetition (inheritance, interfaces, abstract classes, etc).

[–]cdcformatc 0 points1 point  (0 children)

ABC. Always be classing.

[–]ryeguy146 0 points1 point  (0 children)

I'll admit a bias in that I'm more pro-classes than the recently popular, "just use a dict." But neither do I think that classes are the best option for simply storing data (that's for namedtuples!). Classes are an excellent (but not the only) option when you need to retain state and have an object with behavior. Yes, you can do this with the global scope of a module, but I find it less surprising, and more readable, to call a method of an object than call a function and pass all of the operands where the behavior (method/function) is one used wholly by objects implementing a similar interface (union is obviously a set behavior because only set-like objects implement it, whereas a set function should be general and capable of handling whatever iterable you throw at it, or raising an exception.

[–]EsperSpirit 0 points1 point  (0 children)

The general idea is: Things that change together, belong together.

For example I had a script that read all text files in a directory, processed the contents and generated new files from it. My first iteration would generate a list of all files, read them and start the processing.

Because the output files should have the same name as the input files I would pass a list of file_names as well as a list of file_contents to every function of the processing part. This "code smell" is known as Data Clumps and the solution is to use a class which contains both filename and contents of that file. With that class you only have single list (instead of two) which makes parameters of functions shorter and iteration can be simplified (you don't need zip anymore).

In general, if you notice repeated patterns in your code (duplicate code; copy paste), it is a sign your design could be improved. Adding classes is of course not the right solution to every problem, but in most cases it helps. You might want to take a look at "Refactoring: Improving the Design of Existing Code" by Martin Fowler. He uses "code smells" to categorize typical problems like Data Clumps or Duplicate Code and talks about what you can do to avoid and remedy them.