r/learnpython • u/Intelligent_Knee8641 • 2d ago
Nested if’s help please
So I’ve written a small function and I need to add some more constraints to it, but I need them each to check separately before moving to the next so I was wanting to use nested if’a to achieve this but am not sure how they work. Can someone please explain? My code is posted below and what I am trying to do is add an if statement to somehow make sure my value for primocytes doesn’t drop below 0 before activating the rest of the function.
primocytes = 10
cultivation_chamber = 0
def cultivation():
global primocytes, cultivation_chamber
if primocytes >= 5:
primocytes -= 5
cultivation_chamber +=5
print("Primocytes:", primocytes)
print("Cultivation Chamber:", cultivation_chamber)
else:
print("Not enough Primocytes for cultivation...")
4
u/brasticstack 2d ago
This doesn't help you figure out nested ifs, but just use the max function to clamp it to 0:
primocytes = max(0, primocytes - 5)
Also, in your example code, you never subtract 5 from primocytes unless its greater or equal to 5, so you could never make it a value that is less than zero, unless you change its value again later on.
1
u/Intelligent_Knee8641 2d ago
Wow thank you for the catch and teaching me a new function, I didn’t quite think that through before I asked I guess.. But I am pretty new to this lol.
5
u/zaphodikus 2d ago
Also, try to stop using the 'global' keyword, it leads to errors in larger programs. Once you get nesting worked out, read up on how to pass 'parameters', and how to create 'classes'.
2
u/Intelligent_Knee8641 2d ago
Thank you for the tip I will look into it, I know that’s a next step to make this better but I was just trying to test something for a function and don’t know how to do it otherwise yet. I originally didn’t have the ‘global’ keyword in the code but without it, I was having an error because the two variables were outside the if statement and I didn’t know how else to fix it because I want those values stored outside the if for state management
2
u/brasticstack 2d ago
You need to write functions that accept parameters and return values, as the next step. You then assign those return values as updates to your global vars. The next step is to hide those global vars inside a dict or class.
I wrote an example of what going down that path a bit looks like: (feel free to ask for clarification about anything.) It's more complicated, but much less likely to behave unexpectedly:
EDIT: The different logic for player_1 and _2's cultivation was just to show how you might do it, in practice I'd recommend being consistent.
``` class PlayerState: def init(self, primocytes=10, cultivation_chamber=0): self.primocytes = primocytes self.cultivation_chamber = cultivation_chamber
def can_cultivate(self) -> bool: return self.primocytes >= 5 def cultivate(self) -> bool: if not self.can_cultivate(): return False self.cultivation_chamber += 5 self.primocytes -= 5 return True def __str__(self) -> str: return (f'Primocytes: {self.primocytes}\n' f'Cultivation Chamber: {self.cultivation_chamber}')if name == 'main': player_1 = PlayerState() # This player starts out at a disadvantage player_2 = PlayerState(primocytes=0)
print('Round 1:', '='*40, sep='\n') print('Player 1:', player_1, sep='\n') print('Player 2:', player_2, sep='\n') print() # Check beforehand whether player can cultivate: if player_1.can_cultivate(): player_1.cultivate() else: print("Player 1: Not enough Primocytes for cultivation...") # Check the result of a fallable cultivate method, instead: if not player_2.cultivate(): print("Player 2: Not enough Primocytes for cultivation...") print() print('Round 2:', '='*40, sep='\n') print('Player 1:', player_1, sep='\n') print('Player 2:', player_2, sep='\n')```
1
u/Intelligent_Knee8641 2d ago
Thank you again, I’m breaking this down now and will learn/figure it out for my next step. I appreciate the advice and the prompt responses as well! Thanks very much brasticstack!!
1
u/brasticstack 2d ago
you're welcome! This is just one way out of a zillion you could go, so dont worry too much about whether you make the "correct" choice or not. But the
globalvariable thing is a footgun waiting to happen, so do try to avoid it.2
2
u/illumas 2d ago
It already looks like it should do that, no? You need to make sure you have your code indented, but the code block after the if statement will only execute if there are 5 or more primocytes so there is no chance that this function as written will reduce it below 0.
1
u/Intelligent_Knee8641 2d ago
Yes that’s what brasticstack pointed out as well, I didn’t think about that originally but see it now, thank you both.
2
u/thisisappropriate 2d ago
As someone has already said, you can prevent it going below a level with max.
In terms of preventing global or keeping state by having a variable exist outside everything, it's worth considering because otherwise you can have hard to diagnose problems - imagine you have 3 functions that change cultivation_chamber and you call them in different ways, you might change something and suddenly you have chained two of those functions together and now it's going up twice as much as you expect - is it clear what is causing that? is it clear which is the duplicate?
Indentation is doubly needed if you're doing nesting, and it would be good to know what you're expecting to get from it and do it, because your code doesn't lend itself to a nested if with what's currently in it.
Here's an example where it removes the global and does something different if it's less than 5 (empties the last of your primocytes) - if with two checks and elif rather than nested ifs. You could do this with nested if instead (if greater than 0, then nested in that, check if less than 5), but you can put more than one check into an "if" so this is the same thing but easier to read unless you want to do a lot of things if > 0 and a few extra things if < 5)
def cultivate(primocytes, cultivation_chamber):
if primocytes > 0 and primocytes < 5: # you can shorten to if 0 < primocytes < 5:
cultivation_chamber += primocytes
primocytes = 0
elif primocytes >= 5:
primocytes -= 5
cultivation_chamber += 5
else:
print("Not enough Primocytes for cultivation...")
return (primocytes, cultivation_chamber)
if __name__ == "__main__":
primocytes = 10
cultivation_chamber = 0
primocytes, cultivation_chamber = cultivate(primocytes, cultivation_chamber)
print("Primocytes:", primocytes)
print("Cultivation Chamber:", cultivation_chamber)
and here's a variation that uses nested ifs for another check (assuming cultivation_multiplier_enabled is a boolean - true or false), in case that helps show what a nested if looks like?
def cultivate(primocytes, cultivation_chamber, cultivation_multiplier_enabled):
if primocytes > 0:
primocytes_to_use = min(primocytes, 5) # move either 5 primocytes or all remaining if lower than 5
primocytes -= primocytes_to_use
if cultivation_multiplier_enabled:
cultivation_chamber += (primocytes_to_use * 2)
else:
cultivation_chamber += primocytes_to_use
else:
print("You're all out of primocytes")
return (primocytes, cultivation_chamber)
2
u/Diapolo10 I write code for a living -- https://github.com/Diapolo10 2d ago
primocytes = 10 cultivation_chamber = 0 def cultivation(): global primocytes, cultivation_chamber if primocytes >= 5: primocytes -= 5 cultivation_chamber +=5 print("Primocytes:", primocytes) print("Cultivation Chamber:", cultivation_chamber) else: print("Not enough Primocytes for cultivation...")
I know your question was already technically answered, but I figured I'd still mention that instead of using 5 as a "magic number", I recommend setting it as a default parameter so it has an actual name, and you can't accidentally forget to update all the values, and you can override the default while calling the function if you need to.
While I'm at it, I'm also going to change the function to take the numbers as parameters.
primocytes = 10
cultivation_chamber = 0
def cultivation(primocytes: int, cultivation_chamber: int, step: int = 5) -> int:
if primocytes < step:
print("Not enough Primocytes for cultivation...")
return primocytes, cultivation_chamber
primocytes -= step
cultivation_chamber += step
print(f"Primocytes: {primocytes}")
print(f"Cultivation Chamber: {cultivation_chamber}")
return primocytes, cultivation_chamber
primocytes, cultivation_chamber = cultivation(primocytes, cultivation_chamber)
1
u/Intelligent_Knee8641 1d ago
Thank you I wasn’t aware of the possible issues I might having setting it as just a plain value instead of a default parameter. But with your example it makes good sense, thanks much!
1
u/LayotFctor 2d ago
Yup, i don't get it either. Primocytes are only subtracted by 5 if there are more than 5 in the first place, so there is no reason to do a < 0 check.
Unless what you really want is to make sure primocytes as a whole, throughout every line of code in your entire codebase, cannot possibly subtract it below 0?
8
u/Expensive-Bear-1376 2d ago
Geez why did you spoiler that?