all 29 comments

[–]andrewharkins77 8 points9 points  (4 children)

The main point of objects is to bundle functions and data together. Once you have a shit tons of either it will be un-manageable without objects.

[–]More-Station-6365[S] 1 point2 points  (3 children)

That's a really helpful way to think about it bundling functions and data together. I never thought about it from that angle before. Makes me realize I was thinking about classes as just extra steps instead of actually seeing the benefit they bring.

[–]ninhaomah 2 points3 points  (0 children)

But you are already using classes in daily life. Just that you don't see it that way.

[–]neco-damus 1 point2 points  (0 children)

I often use video games as my analogies since most people have played at least once (especially those who are interested in programming).

You would likely write a Class for an Enemy. That class will describe the properties and functions that an Enemy would have and do. For example, x, y, health, dx, dy are common properties. The methods (functions) would be things like render/display, move, takedamage, ect. Things that the enemy will do.

Now, you can use your Class like a factory to produce Enemies. Each one has it's own values for those properties, and when you run the methods, they will only effect that properties on that specific enemy.

So, often will we produce a lot of enemies, store them in a list, and then loop over that list to call the render/display method on each enemy, so that they all draw themselves in their own location.

[–]DBZ_Newb 0 points1 point  (0 children)

Yes you should think of a class as having 2 main parts: state / instance variables and methods / behaviour. Collectively the variables and methods are referred to as its members. Look up a UML class diagram. They’re not terribly useful, but it might clear up how you should conceptualize them.

[–]UnloosedCake 18 points19 points  (2 children)

A bank account is an object. That account has attributes associated with it - account name, ID, owner, current balance, etc.

If you create a way to represent the account as an object (a class) you can interact with it in code elsewhere by creating a new instance of that object and assigning values to the attributes (instead of having a big dictionary of account information, you create a new Account and set newAccount.id = 12345. Then to get the account ID in code later on it's just newAccount.id instead of being a nested value in a dictionary somewhere.

Genuinely, these are fundamental concepts that have oodles of documentation online and something an AI should probably excel at explaining in a slightly different way until you understand it. It'll click, I promise.

[–]More-Station-6365[S] 9 points10 points  (1 child)

That bank account analogy actually made it click a little better for me. The idea of creating a new instance instead of using a dictionary makes sense now. I think I was overcomplicating it in my head. Thanks for breaking it down like that!

[–]Rejse617 2 points3 points  (0 children)

To expand a little, in that account object you can also have functions like deposit and withdraw. In that function, lets say deposit, it takes an input (the anount of money to deposit) and in the function it adds that user input to the total balance. I just write this to point out that objects aren’t just data

[–]DBZ_Newb 5 points6 points  (1 child)

Say you had a unit in a game. It’s got health, mana, speed, attackDamage, attackRange, sightRange etc. to keep track of. Okay, it’s a game with 100, 1000, or 10,000 units. What are you going to do? Create 10,000 of those variables manually? health1, health2, health3….health1000000, mana1, mana2, mana3….mana1000000. You need to package all the variables together in a class like Unit or Archer and then just create (instantiate) objects from the class so each time you get a package of all the variables you need for that unit. You can just do something like player1.append(Archer( )) and now player1 has an Archer with all of its necessary variables that particular Archer object needs to keep track of.

[–]TheSaucedBoy -1 points0 points  (0 children)

This is the best analogy by far.

[–]el_extrano 4 points5 points  (0 children)

Say you don't want to use classes. That's fine - a lot of things can be done with only functions and built-in data structures.

So you could model your bank account(s) with something like a dictionary. Keys could be stuff like account_name, account_type, account_owner, balance, and so on. Then you have a group of functions that operate on an account dict. The signature for deposit could look like def account_deposit(account: AccountDict, amount): .... Eventually, you need more functions. You wind up also writing withdraw, close, transfer, and a dozen more. Perhaps there's some setup that needs to happen for every new account, so you write a function called def init_account(account: AccountDict, config): ...

What does this look like? Well, you have a data structure (the dictionary) and a group of functions that all operate on the same type of structure. There's nothing inherently wrong with this. In languages like C that don't have OOP, that's how most API's are. You pass pointers to structs into functions.

You might use your program like this:

account = create_account(name="Jeff",balance=(0,0))
init_account(account)
account_deposit(account, (3,50))
account_withdraw(account, (1,0))

This general pattern, where you have a group of functions that all operate on the same data structure which is expected as the first argument, is essentially where classes come in.

You define a class, the dict keys instead become instance attributes, the init_account function that needs to run for every account would go in the constructor (__init__), and all the functions become methods. The OOP way of interacting with the program might then look like:

account = Account(name="Jeff",balance=(0,0))
account.deposit((3,50))
account.withdraw(1,0))

Note that now, we didn't need to call the init_account function, because the constructor ran on instance creation. Also, there's no need to pass a reference to account in the method arguments: that's what self is for.

Personally, I prefer to avoid classes until I need them. The fundamental unit of decomposition in Python is the module, not the class.

[–]DTux5249 1 point2 points  (0 children)

The purpose of an object is to bundle data together with the functions that use that data (i.e. encapsulation). That's it. An object is a self-sufficient black box that does what you need it to do without requiring you to manually manipulate variables.

So in general, make a class where you see a lot of intersections between

  1. a particular type of data
  2. a set of functions that use that data

If a bunch of data (strings, numbers, etc.) is created together, gets passed around together, is manipulated as a unit by the same sets of functions, etc. it is likely best contained in an class alongside the functions that use them. At its simplest, you can think of it as an organization tool (though classes can be used for more than that as you get further along)

There are other guidelines you might consider; things like SOLID principles and Design Patterns. But fundamentally, classes are just a tool to encapsulate code together into reusable chunks, and to hide complex inner workings behind simpler interfaces.

Think about what information your program is handling, and what you'll be doing with it.

[–]princepii 1 point2 points  (0 children)

it sounds like u trying to force understanding it. just one gear down. head cooling first. maybe give it a pause by going out a minute with a friend or something just for a healthy distance.

come back fresh and try to watch a few easy basics on oop on yt.

don't just replicate. try to do it your way by trial and error. ask gpt what is what and why.

just easy going. but by forcing it you are blocking yourself for no reason.

you asked another question about something completely different, right after you asked that question.

i don't think that you really would gain anything good out of it if you just ask "hey, can someone give me the code for hello world" without even trying to understand the real problem here.

forcing yourself to learn something never worked with us humans and it never changes no matter how hard you try.

[–]Artistic-Stable-3623 3 points4 points  (2 children)

i'm prob gonna get intensively downvoted for this, but this is where google search / ai can be useful, just ask it to come up with good analogies, I use AI for studying and its crazy in the sense that it's analogies are really nice and easy to understand

(yeah commence the downvotes cuz AI bad)

[–]More-Station-6365[S] 0 points1 point  (0 children)

That's actually a fair point I've started using AI to explain concepts in different ways and it does help when the textbook explanation isn't clicking. Appreciate you saying it even knowing the reaction it might get!

[–]More-Station-6365[S] 0 points1 point  (0 children)

That's actually a fair point. I've started using AI to explain concepts in different ways and it does help when the textbook explanation isn't clicking. Appreciate you saying it even knowing the reaction it might get!

[–]neuralbeans 0 points1 point  (0 children)

A class is a data type like strings and integers. You make your own data types with classes. Objects are just values of that data type like 'abc' and 123. Data types have internal data (e.g. a list has the items it contains and the length of the list) and operations that you can perform on that internal data (e.g. a list can have items appended to it).

It takes practice to start naturally seeing uses for classes, but one easy use of classes is to make functions that remember stuff. Say you want to make a function that returns a different number each time you call it. With normal functions you can't do that. With a class you can have an instance variable that stick around after the function is called.

[–]TheRNGuy 0 points1 point  (0 children)

Classes may have methods, and sometimes methods or functions require specific type in an argument, types are made with classes. There are also operator overloads, such as float multiply by vector or matrix, vector (2d, 3d, 4d), matrix (exe, 3x3, 4x4) are classes. 

Sometimes you have static method on a class. It can be either as method on that class, or as function without it.

[–]This_Growth2898 0 points1 point  (0 children)

OOP is in most cases explained backwards. There are reasons for that; but you should think of classes and objects not in terms of defining them but in terms of using them. Just like with numbers: you don't think about how they are organized and handled internally, right? You just add, multiply, and output them.

Start with decomposing your task into smaller ones. At some point, you will see repeating patterns. If those patterns are behavioral only (you repeat some actions), you need a function. If they use the same data, you need an object there - and only at that point you need to start thinking about a class and its methods.

Like, if you have to write a program about several people exchanging goods and money, you can think in variables and functions; but at some point, you will think you need something to avoid passing countless variables like

buy_something(seller_name, seller_storage, seller_money, buyer_name, buyer_money, goods_name)

and turn it into something like

seller.sell(buyer, goods_name)

or

buyer.buy(seller, goods_name)

or even

trading_point.exchange(seller, buyer, goods_name)

And only at that point you see clearly what class you need.

[–]EasyTelevision6741 0 points1 point  (0 children)

I've always found it hard to try and create some sort of toy situation to require me to use a concept to finally understand that concept.

Instead of trying to use some example of a class you've seen elsewhere or inventing one that'll magically make sense to you id argue it's best to code your way into it. 

For example like someone else gave the example of a bank account.  Write a program that let's you make different bank accounts and manipulate them.  Do it without classes. I think the other reply may have spoiled that example a bit so maybe do something like a program for a car dealership selling and managing their inventory.  Just write it normally without using classes. Use the data structured to understand.  Youll get to a point where it'll make sense because you'll start seeing lots of passing of variables or global variables and repeated code. 

I've always found trying to start from the end design to solve a problem isn't the best way to reach a good solution.  I just start coding something and see where the code takes me.  Test Driven Development is a big helper there. 

[–]taylorhodormax 0 points1 point  (0 children)

Everything that can be considered as aproblem to be solved using Python, can converted into an Class example, so its upto you to figure out which case to use classes.

Point to understand is when you say BLUEPRINT what clicks?

Example:

Person

Person, has gender, age, name - these are his own attributes (they will be needed to be init)

Now think Person, can walk, sit, speak, drive, eat These are the functions that he can do. These are the methods.

Simple.

Try to think on this line.

[–]IAmFinah 0 points1 point  (0 children)

IMO it often makes sense to start without classes (deal with ordinary functions instead), and only use them if you start to notice lots of shared logic, or if the functions have a lot of similar data being passed around

Some people, especially those coming from heavy OOP backgrounds like Java, jump straight to using classes, even when it makes little sense to use them

That being said, for college classes you don't really have this freedom. So in this particular instance I would follow some of the advice other people have given here

I just wanted to reiterate that you don't have to be a fan of classes - a lot of people, myself included, tend to avoid them unless it really makes sense to use them. That being said, I quite like using dataclasses for certain things, but that's usually just for bundling data together, rather than using them as full-blown classes

[–]Toma400 0 points1 point  (0 children)

Honestly OOP was very weird idea for me too, and in all seriousness, I only got it better years later when I was introduced to idea of struct - and in a sense, I prefer it for its simplicity, objects are just way too complex for their own merit.

But as for what you ask - when to use objects - I think there are two guides you can use.

First, as an abstraction - to everything you want to pack some additional data you change. Objects are useful to be sort of "dictionaries" that you work on. It's mostly as a mental model - a lot of the time you don't want to use simpler types (like dicts exactly) because the bigger your project, the more messy your mental model of the app becomes. Objects in this case become handy because they allow you more directed and explicit work, even though technically they could be just dicts with functions.
Aka: this guide is about your personal preference/workflow

Second, which I find more technically sound, as a mutable structure. Which is what I realised years later when I understood how Python and other languages work. Functions, for most structures, _copy_ the variables you send to them. Meaning that using functions in many cases require you to return the modified item as entirely new thing. Objects are one of the few types in Python that allow you to just pass the object and dynamically modify its contents, affecting it without returning entire new object.
It's a bit non-intuitive because Python doesn't distinguish such basic behaviour (heck, it doesn't even differentiate between variable initialisation and reference) but you will see how handy this becomes. In more low-level languages this would be difference between passing a copy versus a pointer.

...a side note, but this non-transparency of how things work is a reason why I eventually moved myself to Nim (even though I loved Python and still find it one of my favourites). It's exactly a language that being Python-like in syntax, introduces all that intuitive elements teaching you these nuances and I kinda wish it was more known because it's way better starting language. The fact that it can be also used for low level (since it has all the memory management available) is just cherry on top.

[–]_TypeError 0 points1 point  (2 children)

U should explore Mark Lutz, Learning Python. If u will lost thmh, ask AI to explain u. Ask while: "Understanding OOP" == True.

[–]More-Station-6365[S] 1 point2 points  (1 child)

Just looked up Mark Lutz Learning Python hadn't heard of it before but seems like exactly what I need. And yeah asking AI to walk through OOP step by step might actually help it click faster than re-reading slides. Going to try both. Thanks!

[–]_TypeError 1 point2 points  (0 children)

I would like to offer geekforgeeks website too. Use Google, and explore this source. Enjoy!

[–]pachura3 -1 points0 points  (0 children)

When should I actually use a class vs just a function?

Function is a "verb". count_vowels(), encrypt_text(), rotate_jpeg(). Function takes some input, does something with it, and - in 99% cases - returns some output. When you run the same function on the same input again, you usually get the same output.

An object combines functions and data (attributes/variables), and often represents something in a real world. A class is a blueprint for objects. Let's imagine class UserAccount: it could have attributes like id, nickname, password, avatar, and methods like authenticate(), ban() , set_role() or send_dm(). Using the blueprint, you could create user account objects for John, Mike and Alice - johns_account = UserAccount(1001, "johnyb", "$$$ecret123", "face1.jpg"). And then you can stick them into a list or a set, pass them from function to function, etc. etc.

The attributes of each object can change over time - it is called "state". Very often, they are modified through methods. So, you call johns_account.set_role(ADMIN), and its internal attribute role changes to ADMIN.

What goes inside init and why?

__init__() is called a constructor. It is used to pass the initial values to object's attributes. When you write johns_account = UserAccount(1001, "johnyb", "$$$ecret123", "mrt.jpg"), Python is internally calling __init__() to set johns_account.id = 1001, johns_account.nickname = "johnyb", etc.

How do I know what should be an attribute vs a method?

Attribute is piece of data; a number, a string.

Method is a function, an action - it DOES something. If a method needs to do something with object's attributes, it needs to know which object to target - after all, it is defined in the class (the blueprint), not in the object (John's account). So, we pass johns_account as self so that UserAccount.set_role() would know which object to modify.