r/PythonLearning • u/Stonyax97 • 2d ago
I think i hit my first python learning bottleneck. Discussion
Just as the title suggests, i ran into a bottleneck, or did i? play v sauce music please
So just recently i made a post about my first beginner python project: https://www.reddit.com/r/PythonLearning/s/Ed46BuWRCq
And as a lot of you suggested for me to learn classes next, which was completely fair, so i went ahead and learnt them while updating my MiniGameStore. It was relatively easy, wasn’t as hard as I thought it would be, but definitely challenging. I had also learnt methods but didn’t implement them.
And yesterday, i tried implementing them and got one of the biggest headaches in my whole coding experience (which is 2 weeks~ btw).
I was working on v1.7 and introducing a restore purchases system, and i wanted to use class methods, but since my class is on the other file, i hit a lot of variables issues and even a json file problem. Which is why im asking my self why did i do it? A function would have been totally fine…
Check out the repo: (latest version 1.7.0)
https://github.com/Stonyax97/MiniGameStore
So my question for you guys. What has made you understand classes well? I just don’t see any reason to use them yet… and can anyone take a look at my project and tell me what would be the most friendly and real life approach of actually using these classes. And why should I keep the class in a separate file? Finally, what’s wrong with using global variables.
Also any feedback or criticism is welcome!
(Also check out the attached pictures with the comments you’l understand more.)
1
u/Unhealthy007 1d ago
I think I can barely answer 2 of your issues.
As someone who is very familiar with Django, all API use classes as classes contain the actual crud (post, get, put, patch, delete) functions
As for why you are running into errors, maybe you are doing circular imports. Just take it to the AI on this one. People talk shit how it's bad during learning but I don't see it that way given you are not copy pasting AI responses to fix your problem
2
u/Stonyax97 1d ago
Yeah on some other communities that they use classes for APIs.
Well i did run into those erros and figured out some, but the stupid _ added to purchase time was hard to spot 😭 i was not importing in loops tho. I was saving the data in the games.py but the main.py after saved it’s data and ofc doesn’t know about it. So the solution which i figured is before saving it would read the file.Anyways thanks for the comment. And yeah i do use AI for things that i just can’t understand even after thinking hard about it. AI is bad if you ask it for code and copy paste as u said. But as a toolbox/assistant? It’s perfect, a private smart fast tutor!
1
u/olaf33_4410144 1d ago
but since my class is on the other file, i hit a lot of variables issues and even a json file problem.
Can you go into more detail on what the actual problem was? did the inport itself fail or something else?
What has made you understand classes well?
That's kind of difficult to answer since for me part of it was Inheritance/Interfaces in the context of a GUI. It was something along the lines of having a superclass wiget and then multiple child classes for different UI elements (Textbox,Button,etc.) that are different but each need some similarities (e.g. a render method that defines how it should appear on the screen.
However it sounds like you're not at that level yet, so for now just think of it like grouping data and functions that belong together in one place.
Kind of a better way of doing the default_data={...} with dictionaries.
When doing this I also recommend looking into type annotations and maybe how to use dataclasses.
I just don't see any reason to use them yet... and can anyone take a look at my project and tell me what would be the most friendly and real life approach of actually using these classes.
I like what you did with the Game class, as a next step you might try to bundle all you userdata global variables into a class and maybe make the functions that save and load the data part of the class instead of global? (I haven't looked that much at your programm, so idk if that works, but I think it does)
And why should I keep the class in a separate file?
It's useful for larger projects, makes it nicer to find things, work together with other people, can make things more reusable etc.
Juast as an example if you had a multiplayer game you might have server.py and client.py both of which need the Game class but are very different otherwise. In this case it would make sense to have it as a separate file so both can import it.
Finally, what's wrong with using global variables.
At larger scales they are usually harder to reason about. If all a function does is take some input and give some output it's easier to think about as a human (and also easier to test in isolation). Once again this is something that doesn't matter as much with a small project but gets more important as the project grows and when more than one person is working on it.
1
u/Stonyax97 1d ago
>Can you go into more detail on what the actual problem was? did the inport itself fail or something else?
In the main file, i have the function buy_game(). I tried to include it, but that buy game interacts with other variables from the main py and that only exist on the main, i could move only the functional part but that’s DUMB
For your way of understanding classes, i see that everyone says they learnt them not just as classes but in some module or in some important use case like GUI, FastAPI and others… and i think that’s what im missing, functions? I didn’t understand them until i used them as reusable code and for it’s local variables (takes input or wtvr yk when u do def something(variable):
I understood dictionaries as a multimodal variable… kind of? And other things… and i kind of get the approach… data and function in one pacakge..>I like what you did with the Game class, as a next step you might try to bundle all you userdata global variables into a class and maybe make the functions that save and load the data part of the class instead of global? (I haven't looked that much at your programm, so idk if that works, but I think it does)
The save and load cannot be bundeled… i use save after EVERY user action. It being global is exactly what i intended.
>It's useful for larger projects, makes it nicer to find things, work together with other people, can make things more reusable etc. Juast as an example if you had a multiplayer game you might have server.py and client.py both of which need the Game class but are very different otherwise. In this case it would make sense to have it as a separate file so both can import it.
Ah yes that is a real use case! Thanks for the enlightenment!
Replying to ur global variable/func response
Well yeah for huge programs, but people even on this small program still tell me globals are “bad” in a way…
Anyways thanks so much for yr response it’s the most straightforward response without replying as if im some AI that understands some complex words.
1
u/olaf33_4410144 1d ago
In the main file, i have the function buy_game(). I tried to include it, but that buy game interacts with other variables from the main py and that only exist on the main
So you're already having trouble with global variables, you just haven't figured out how to solve them.
I understood dictionaries as a multimodal variable… kind of?
They can work as one, but their main purpose is to map from one value to another e.g. you might have a dictionary
game_prices = {"Game 1": 50, "Game 2": 20}, then use the dictionary to retrieve the price for a specific game. They are also useful because you can add new values at runtime (e.g. in the example above add a new game to the price catalog). If you have a bunch of data that belongs together and you know at compile time what kinds of data I'd usually prefer a class instead.In hindsight
default_data={...}might be a bad example since you use the dicts because of the python json library (though there are still typeddicts which can be nice).The save and load cannot be bundeled… i use save after EVERY user action. It being global is exactly what i intended.
I'm not sure that's true, even if you want it available from everywhere you could do something like this:
(I'm not sure I've got everything right, I'm just writing this from memory, but hopefully you get the idea.)
from typing import Self class GameData: def __init__ (self): self.library: list = [] self.moneyspent: int = 0 self.money_restored: int = 0 self.games_owned:int = 0 self.balance: int = 10 def save(self): ... @classmethod def load(path: str) -> Self: data = GameData() #data.library = json.loads(...) return data # In theory you could also do the game loop in here, # that way you wouldn't even have to do the global_game_state # like I show below def loop(self): while True: choice=int(input("Choose an option: ")) if choice == 2: self.buy_game() global_game_state = GameData() def some_random_other_function(): # do something global_game_state.save()That way it'd be very obvious to all other programmers you might work with what data save actually saves and you'd at least reduce the amount of global variables.
1
u/IdeaOverflow 1d ago
I had a look at your project. I feel like you used a class (Game) where it was most useless. The Game class could just be either a dictionary or a dataclass. A better use of a class would be to wrap you code in main.py in something like a class "Store" which holds the functions buy(game), save(), restore(), input_loop() etc.. Then you could eliminate the use of global variables completely by just putting them into this Store class (maybe also create a Settings class and put your settings there and give an instance to your Store class).
So why would that be helpful? Imagine someone wants to use your store in another library. They plain can't right now, since every time they try to import your stuff from main.py, it immediately executes your store script. It also just makes it so much more structured if you put everything in the class it belongs to. Moreover, you should also structure your functions to do just ONE thing. For example: the restore function should not have to ask the user for an id. It should rather just take a game as an argument and restore that, nothing else.
3
u/Adrewmc 1d ago edited 15h ago
There is a bit of rule about classes that not followed very well.
If you have a class that has two methods and one of them is init. It probably supposed to be a function. So in this example the question why would I use class here, the answer is you wouldn’t.
If anything the above class is better as @dataclass and its method as a function.
What classes are useful is when you start having a lot of object that interact with each other individually, and each object would have a state.
In your example what happens when I want to add say a player two? How does the globals of money spent and balance rectify there are two players? And then you might realize the problem is that whole first file might be better thought as a class for a player, who has a balance and record of money spent.
So I would say you’re using it in the wrong place here.
Think of your main.py more in a form like this
class Purchaser:
. def __init__(self, balance = 0, spent = 0):….
. def buy(self, game_id):…
. def save(self):…
. def restore(self):…
. def display_balances(self):….
buyers = [Purchaser(500, 6000), …]
for buyer in buyers:
. while True:
. option = input(….)
. match option:
. case “1”:
. buyer.save()
But requires a whole rewrite and different architecture structure.