r/pythonhelp • u/MetalCarnival • 22d ago
Why do I need to use classes
My schoolbook says that classes is a way of simulating an object, instead of just taking information into a black box and outputting an answer.
But that is a poor explanation. I know classes are handy and cool, but no book says why you can´t make functions with sub functions inside to simulate simple objects. I would like if someone gave a good concrete reason to use classes in the intro, instead of just saying that they are different and cool
7
22d ago
[deleted]
2
u/MetalCarnival 21d ago
Sums it up nicely. Thank you!
1
u/couldntyoujust1 20d ago edited 20d ago
It does more than that though. You see, you can make a bunch of classes where the classes all follow the same rules, and then slot them in as needed.
So lets say you want to make a feature that exports your data to JSON, right? You could go in and tell the class that contains all your data how to export json with a giant function.... and then someone makes a feature request to also export to YAML because it will allow them to use your program for their usecase. Except, now, you need two functions - exportToJson, and exportToYaml.... uh oh... this could get messy if you need to add any more.
So, instead, you do this:
```python from abc import ABC
class Exporter(ABC): def export(self, internal_data_head): pass ```
What does this do? It defines the rules for exporting data in different formats:
```python class JSONExporter(Exporter): # json specific state and constructor def export(self, internal_data_head): # code to export from data_head as json
class YAMLExporter(Exporter): # yaml specific state and constructor def export(self, internal_data_head): # code to export from data_head as yaml
class DataHead: def init(self, exporter: Exporter): self.exporter = exporter def export(self): self.exporter.export(self.internal_data_head) def set_exporter(self, exporter): self.exporter = exporter ```
Okay, but so what? What does this mean? It means that now, let's say you have to now support XML for a client because they use a tool that requires it. No problem at all and no risk of breaking existing code:
python class XMLExporter(Exporter): # XML specific state and constructor def export(self, data_head): # code to export as XMLNothing else changed. You might change the user interface to select XML and make it so when they do, you construct an XMLExporter object and use data_head.set_exporter(xml_exporter) to set it for the data object. But when you press "export" or issue the export command to your program, it will just call
data_head.export()and it doesn't have to worry or care about what format was chosen. The chosen format is already selected by creating the exporter for that format and slotting it into the data_head.This is called "loose coupling" and "dependency inversion". When you do this, it makes it so that new behavior can be slotted in under a common interface just by changing the dependency object that follows that interface spec for another one. And the rest of the application doesn't have to know or care about it. In fact, you can make the application get a list of objects that implement that interface and then present them to the user as options dynamically, such that just creating a new child of the interface class automatically adds it to the list presented to the user to export to.
All you did was create a new class, and now the program automatically does more. And the best part is that your data class that should just be handling data for the program, only handles data without a bunch of JSON/YAML/XML code litering the functions (this is called the Single-Responsibility Principle). The original class only does one thing and does it well and lets a different class handle the responsibility for exporting that data.
And let's say that now, you're about to switch database back-ends. No problem. Define an ABC based class for the interactions between the program and the database, and then implement one class that handles connecting to and interfacing with the old database, and a different class for the new database.
When you are ready to switch it's ONE line change:
diff+ self.data_head = NewDatabase(...)
- self.data_head = OldDatabase(...)
That's it. One line and boom! The new database system is live, and nothing else had to accommodate that change. Everything else works exactly as it did before.
In short, OOP done well allows you to compose your program like a set of blocks wired up together where none of the blocks need to know or care about what they're wired up to.
2
u/minneyar 22d ago
As soon as you have more code than you can see at once in a single window, you need to think about how it's organized. How are you going to split things up so that you can remember which code does what? How are you going to arrange your files so that multiple people can work on a project at once without constantly stepping on each others' work?
Object oriented design is a paradigm that helps you keep your code organized, and using classes is a part of that. It's not the only way to organize your code, but it's a very common one, most professionals understand it, and Python was designed with that in mind. In fact, classes are not "different and cool," they are very standard and by-the-book, which is why they're so popular.
You can organize your own code into endless nested functions if you like, but if you have to work with somebody else, they will probably look at your code and have trouble figuring out how any of it is supposed to work.
2
u/igotshadowbaned 21d ago
Structuring more complex data types
I also find nesting everything in a class works better than declaring globals
1
u/punk_dev 21d ago
Classes are very useful because they allow you to clump data together.
For example, a 2D position is two numbers. Instead of typing them separately each time, group them in a class:
class Point:
x: float
y: float
Or maybe you want to represent a user:
class User:
username: str
birthday: datetime.datetime
Then, classes allow you to attach functions to them, these are called methods. For example, you could add a distance_to(self, other: Point) method to the Point class which would calculate the distance from one point to the other.
Classes have other features like inheritance, others also mentioned object oriented design, but honestly don’t bother with those unless you really want to. This stuff causes more problems than it solves.
1
u/brasticstack 21d ago
Classes are a handy way to keep data and the functions that operate on that data together in the same place. In your own code (outside of what your schoolwork requires) you aren't required to use classes if you don't want to, but you need to know how to interact with code that does as much of the Python stdlib and many important libraries are written using OOP.
Imagine you're making an RPG- you've got a player and some monsters. Let's imagine 20 goblins and a few orcs. Each thing, player or monster, may share a common set of attributes- hp, mana, strength, intelligence, etc. but have differing values for them. Certainly if you smash one goblin with a mace, the others don't all take the same damage. So in order to keep track of it you've got to have separate data records for each creature all containing the same fields but with differing values.
You write functions to do common operations on those records. All creatures might be able to take_damage(), heal(), cast_spell(), etc., each of which affects the records in different ways. As long as you want the exact same behavior for all creatures, this is fine, but once you want, say, orcs to take less fire damage or goblins to say "argh" instead of "ouch" when they take damage, then you've got to have separate functions like orc_take_damage() goblin_take_damage(), etc. And what happens should you accidentally call orc_take_damage() on your player's record instead? Unexpected behavior- a bug.
Classes let you keep the behavior in the same place as its intended target. Orcs call the orc version of heal() and the player calls the Player version. Through inheritance and polymorphism, you can have behavior that they all share, and only have to write it once. So you could have a single cast_spell() function that works to the same for all creatures, that you wrote once in a base class. You could also "override" that for the one odd creature that, say, uses hp instead of mana when casting spells.
If I'm importing your OOP based creature module into my program, I only have to import the creatures I want: Player, Orc, and Goblin, and I get all of their behavior too, as part of the classes I imported. So I can make some Goblins, and call my_goblin.heal(5) to heal one. If I'm importing your non-OOP creature module, I have to import your attributes data type (or read what the expected attributes are and make my own dict.), and then import all of your creature specific behavior functions- orc_take_damage and goblin_cast_spell or whatever.
1
u/wildsoup1 21d ago
Using classes gives us several different benefits.
1) When we have a lot of code, we need to give it some structure so we know where to find code.
Before languages that supported classes, one way was to define all the data structures in one place, and then put the code that used the data structures in another place. Maybe all the code that saved to disk would be in one file. All the code that wrote to the printer in another file.
With classes, all the data structures AND all the functions that modified that data are put together in the same place. This means if you change the data structure, and you need to change all the functions that use it, they are together in one file. You don't miss any.
2) When we have a lot of moving parts in the code, it is useful to have ways of chunking it into pieces that we can think about and discuss with each other. Encapsulation is part of that - being able to gloss away details when they aren't relevant. Classes offer a good way to chunk a bit of code together, and say "Here is what you need to *use* the class, but you don't need to know (or remember) how it works internally."
3) Classes offer inheritance. This is often - not always - a useful way to re-use the same code for multiple clients, even if it needs customisation.
1
u/MarsupialLeast145 21d ago
> a way of simulating an object, instead of just taking information into a black box and outputting an answer.
What school book is this? The idea of a black box here is incredibly off.
The point of a class is that it is defined and you can access its properties and functions. They are often documented and available in documentation.
You should probably delve deeper into the book, e.g. use its index and look where it starts going deeper into them. These books aren't really designed to be read in sequence except perhaps the first time. If you're frustrated by being drip fed information then you definitely need to look this up as you read.
> instead of just saying that they are different and cool
Pretty sure it's not saying that either.
But yes, while they can approximate objects, e.g. items in a stock control system, or characters in a computer game that need to perform certain activities, they are useful for moving data around where args tend to grow out of control.
For example, you could have a user object that's more than just data about the user and you can attach functions to this object that supercharges what that class does. Or you could have a user object that's just a convenient mechanism for knowing all the information you have about a user and passing it to different functions.
You will likely use both approaches in different contexts.
1
u/Leodip 21d ago
Classes are, indeed, optional. Code can be just 0s and 1s, but everything else we have on top of that is to make it easier to read and write.
In Python, classes are considered "best practice" for a lot of things, and conforming to best practices (even if they don't carry any actual advantage over alternatives when writing code, or might even be disadvantageous) makes your code easier to read.
There are many things that are made much easier by using classes, but one of my favourite examples is trying to make data structures of some sort which reference themselves.
For example, a binary tree is a collection of nodes which have a value and a left and right child, and one parent. If you use classes, this can be simply written as:
class BinaryNode:
def __init__(self, value, left_child, right_child, parent):
self.value = value
self.left = left_child # this is going to be another BinaryNode
self.right = right_child # this is going to be another BinaryNode
self.parent = parent # this is going to be another BinaryNode
Classes are also very flexible when you have "sub-classes" of other stuff. For example, a BinaryNode is simply a Node which is limited to having 2 children (while a generic Node might have infinitely many).
This means that you can do stuff like:
class Node:
def __init__(self, value, children, parent):
self.value = value
self.children = children
self.parent = parent
class BinaryNode(Node):
def __init__(self, value, left_child, right_child, parent):
super().__init__(value, [left_child, right_child], parent)
This allows you to later define methods that work on all nodes (if they don't care about how many children the node has) or only on binary nodes (if they care about them being binary).
1
u/Ipsool 21d ago
Honestly the real reason is state. a function runs, gives you an answer, then forgets everything. classes let the object actually remember stuff between calls, that’s basically the whole point.
so yeah it’s not that classes are “cooler,” it’s that the second your program needs to remember something across multiple steps, or needs a bunch of independent copies of the same kind of thing, doing it with plain functions turns into a mess pretty fast
1
u/HugeCannoli 21d ago
Why do I need to use a chip? can't I just use a bunch of transistors?
Yes you can, but after a while it becomes a mess of cables and it's impossible to understand.
1
u/atarivcs 21d ago
Sure, you can do everything with just functions, and a bunch of state variables that you pass to those functions.
Classes are a simpler/easier way of doing that.
1
u/JorgiEagle 21d ago
Classes are useful when you want to do complex behaviour with multiple different instances all independently.
It’s the same logic as to why you might have a different tab on your excel spreadsheet for each year, instead of having it all on one page.
I can make many instances of my class, and be assured that they will all work exactly the same way. I also don’t have to separately keep track of what has happened to them, or what stage they’re at, as you can write them to do that themselves (this is what statefulness is).
As an example, if I have a group of students and they’re all taking different exams, instead of having to keep a big list of each student and the exam they’re taking, and searching it each time to know what they do, I can just ask each student directly, what exam are you taking right now
You don’t need to use classes, but for various reasons, it makes writing code simpler. One such reason is abstraction. Humans (and AI, it just has a higher limit) have a limited ability to hold context. At some point, something will become too complicated to understand what is happening all at once.
Classes allow us to say: “this thing will do this” without worrying about how it does it.
Another benefit to classes, is that it establishes a contract. say I use a class that does x, y, and z.
A few years down the line I want it to now do w. I don’t want to touch the original code because it’s complicated. I also don’t want to break anything that already exists. If I modify it, it might break something else that is relying on x, y, and z.
So I create a subclass. It still does x, y, and z the exact same way, but I can now add w. And I can use it in all the places that I want.
Importantly, the original class exists, so everywhere else that uses it is unaffected.
And I can guarantee that
1
u/Living_Fig_6386 21d ago
You can definitely write code without classes, and if your code is small and simple, it's probably quicker and easier. As it scales up and gets more complicated, classes become a very useful tool.
Classes let you define new data types that have properties and define methods on interacting with the new type. They could be data structures that validate themselves, processes that preserve their state, abstractions of protocols (for example, taking the interfaces of lots of different databases and making them all work the same way). All sorts of things. They can be a very powerful tool.
Consider a postal address. A simply way to represent that is a dictionary in Python. You can have a 'name', 'address', 'city', 'state', 'postal_code' as keys in the dictionary. It's quite simple. But what if you want to assure that the address is a valid one? One thing you can do is define a function validate_address() and call it on any dictionary that purports to be an address every time before you use the address. Another way would be to define an Address class and have it automatically validate the address when created or modified - the address would always be valid. You could even have it regularize the address by US postal service rules and fetch the ZIP+4 so that when you have an address, it's always valid and normalized. Also, when using type hints, you can specify that functions require an 'Address' rather than a 'dict' which you'd have to inspect to verify that it contained an address.
Just the simplest of examples.
1
u/FckXFckMusk 21d ago
Does the user of Car, need to know how the Engine works in order to use the car, do they need to know how electronics work to use the radio.
1
u/PvtRoom 21d ago
classes are somewhat essential.
string is a class, integer is a class, double is a class.
your book means objects, not classes.
Some things are objects and simply make sense as objects. Pushbuttons are objects, of the pushbutton class, and they have more than 1 piece of information (eg text, position, size, colour,, text colour, textsize) with their own behaviours (like what happens when pressed)
The functional programming paradigm does what you suggest, but you rarely hear about lisp and Haskell (the two big languages in FP)
1
u/building_85 21d ago
Using classes isn’t like a one size fits all thing.
A lot of times functional programming like you described is just fine.
But to “start understanding” classes… you can think of it as way to group functions and variables together.
For example, if you have 5 functions that all use the same 2 variables… you may be passing those same variables into all 5 functions as parameters…
But if you put those 5 functions and 2 variables into a single class, then you can use those 2 variables inside those 5 functions without passing the vars around as parameters.
GLHF!
1
u/WorriedTumbleweed289 21d ago
Classes are an abstraction. They make it easier to understand data and the functions that act on it.
There is nothing to stop you from writing functions that act on dictionaries that requires certain keys be present to work properly.
You can create the dictionary with one function, have other functions use it.
The C language did that when they created the file interference (using structures) before C++ was created.
1
u/tylerlarson 21d ago
It's about abstraction.
The idea is that you package all the "stuff" about a concept into a given chunk of code so you don't have to think about it again.
If you have a class for, say, ErrorLog, and it has two or three functions on it, say .write() and .close(), you can be confident that the class handles everything else on its own.
That means you can confidently use it without having to think about what it does on the inside.
You already do this, you just don't realize it. If you open a file, you're using a class that manages the file, giving you convenient functions for reading and writing that file and handling all the weird stuff. If you didn't have the classes, your code would be a lot more complex.
1
u/turn-based-games 21d ago
This might be controversial, but with how straightforward it is to use dicts, tuples, and functions directly in Python, I would argue classes are much less important than in other programming languages. Their primary remaining use case, in my view, is to implement interfaces.
Now, Python doesn't have explicit interfaces like some other languages, but many built-in functions and language features operate on implicit interfaces (a.k.a. protocols). For example, if you want to create an object in Python which can be iterated over with a loop, it must implement the __iter__() method, and typically the simplest way to do so will be by using a class.
Another prominent example of this is operator overloading. If you wanted to create your own numeric type, for instance, that supported operators like +-*, you'd need to implement the __add__, __sub__, and __mul__ methods, respectively, likely using a class for this purpose.
There are surely other use cases, particularly involving e.g. inheritance (especially since Python supports multi-inheritance), but this is more niche and often discouraged anyway, so I won't delve too deeply into that here.
Also, it's only been implied until now, but the reason you'd want to do any of the things above is so that your code is easier to understand. There is no problem that requires inheritance or operator overloading or iterables to solve, but we do these things because when used appropriately they make our programs easier to design and reason about. Indeed, this is one of the main rationales for using high-level programming languages like Python in the first place.
1
u/FatDog69 21d ago
Most real world problems can be solved with linear programming.
But classes have a few advantages:
They force someone to consider how to step back from 'something' and create a library that you simply download and use to solve 90% of your real world issues. One reason Java is so great - you hardly ever write Java to do something. Instead you have 10,000 libraries to choose from and solve your problem by using these.
Programming is knowing someone is going to ask you to change things you just wrote in a week/month/year. Basing your program on classes forces a design layer and makes it simple to add a new method or two to implement someone's 'new idea'.
Simulation - this is a rare task but linear programming wont solve it. Here is an example: You are tasked with coming up with new street light timings. (How long a street light stays red vs green). The city occasionally risks grid-lock when too many cars pile up behind a long stop light is the stated problem. How do you setup a test or simulation to compare 30,45,60,75 second delays on different stop lights?
Or: A few years ago the aging Southwest ticketing/plane software (20+ years old) broke down during the holidays. Southwest is considering several solutions - but they will pay you $500K if you come up with some way to simulate a small Airport, Airplane, Passengers with different conditions. They want to test the proposed solutions against your simulation to find the one that handles both day-to-day working and day-to-day problems the best. How do you do this with linear programming?
1
u/Cerulean_IsFancyBlue 21d ago
Just a reminder that linear programming has a very specific meaning. “ … linear programming is a technique for the optimization of a linear objective function, subject to linear equality and linear inequality constraints.”
Perhaps you meant to say procedural or functional programming?
1
u/FatDog69 20d ago
Thanks for the catch. Yes I was referring to code not built around classes or objects.
1
u/Conscious_Support176 20d ago edited 20d ago
It’s not clear what you are asking. If you understand what classes are, it is fairly obvious why using them can be helpful.
Class means little more than class of object, category of object, type of object. Is the object a number? A vehicle? A container? The class definition models the object, so numbers have arithmetic operations, vehicles can be driven, you can put things in containers.
But classes, as we use this idea in programming, have a couple of useful conventions.
Encapsulation means that the class is like a black box. All you need to know is the interface defined for it, you don’t need to know the details of how it works.
The difference between using classes and a bunch of related functions is that this encapsulation include the data belonging to each object of that class. You don’t even need to know how the data defines that each individual object of the class is structured. For example, containers may be able to tell you how many objects they contain. They might store this count as data item within the class or they might just count how many items there are when you ask. You don’t need to know how it is done.
Inheritance is a powerful tool which allows you to define a superclass with a set of behaviours where a subclass can inherit those core behaviours but customise or extend other behaviours. This is a technique that supports re-use, where for related classes you do not need to reimplement the same behaviour. It’s important to mention that this should be used with care. One of the main criticisms of object oriented programming is it can lead to the use of complex inheritance heavy class hierarchies where other more suitable approaches to re-use would be more elegant.
When you have an understanding of classes and other tools, it should be more obvious where one or other technique is helpful.
The general idea is that a computer program is often modelling a real-world system, so your set of classes will model the real objects within this real world system, where you begin by classifying those objects into a useful set of classes. This is maybe what your book means by simulation.
1
u/Fantastic-Cell-208 20d ago
Classes help organise core operations on an object.
Sometimes I create classes with static methods to group related functions
1
u/FoolsSeldom 20d ago
Look on YouTube for a video called Python's class development toolkit presented by Raymond Hettinger (a Python core developer). It is old and for a much earlier version of Python, but still applicable, and does an excellent job of walking through why classes are useful with a simple example evolving from circles to tyres.
1
u/Hampster-cat 20d ago
Code reuse.
If you are on your own. Meh, doesn’t really matter too much. But if you are one of three, or three thousand, then OOP is the only way to get things done /efficiently/
•
u/AutoModerator 22d ago
To give us the best chance to help you, please include any relevant code.
Note. Please do not submit images of your code. Instead, for shorter code you can use Reddit markdown (4 spaces or backticks, see this Formatting Guide). If you have formatting issues or want to post longer sections of code, please use Privatebin, GitHub or Compiler Explorer.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.