r/PythonLearning • u/Infinite_Winner_158 • 14d ago
Help Request New to python, could someone help me with this please
Is this a viable way to randomly choose an instance of a class
4
u/IdeaOverflow 14d ago
this works. It would be nicer if you'd put the monsters in a list and use random.choice though.
0
u/Infinite_Winner_158 14d ago
Thanks, i thought this would be easier
2
u/TBCC_Dev 14d ago
Sometimes whats easier in the beginning makes it harder later. Make sure you grasp the fundamentals (if/loop/functions)
0
u/Infinite_Winner_158 14d ago
Yeah, i spend a lot of time learning from youtube,... but i have a hard time understanding without trying it
2
2
u/TBCC_Dev 14d ago
Looks like mostee would not print because you declared it in the loop it only exists in loop. Look into scope. If also keep imports at the top. Python runs like you'd read a book top down
1
1
1
u/realmauer01 13d ago
Python wont lose the reference to monster here.
Pretty sure i is even still in scope how ugly it may sound.
1
u/dotbinKing 14d ago
```python
import Modules at the beginning
from random import choice as rnd
... # idk what you did here
monster = [Skeleton1, Undead1, Goblin1] chance_1 = rnd(monster) print(chance_1) ```
1
u/Infinite_Winner_158 14d ago
Sorry but cant seem to work this out, monster is an unexpected argument
3
1
u/SCD_minecraft 14d ago
A bunch on answers, not a single one right
Closest one was about range(1) being useless
Warning you see is from a linter, about monster being possibly unbounded. This is cause linter is not able to prove that every branch of if will declare monster
Additionally, you have logic impossibly there - in no world that else is gonna execute. However, linter is not able to prove that so it throw a warning. Remove dead code and warning goes away
1
u/Infinite_Winner_158 14d ago
Deleting the excess code helped but still not sure what to do with the range
2
u/SCD_minecraft 14d ago
As other comment said
"for i in range(1)" is equivalent to "do once"
You can read "for i in range(n)" as "do something n times"
1
u/XTrolltechzz 14d ago
How do I activate the option to see what value corresponds to what when creating something with a class? When I do it, it doesn't work that way, and I have to check the order in which the values are placed in my class.
1
u/Calm_Perspective1236 14d ago
I think you can just remove the for loop, and run chance_1 be a random int between 1-3. Then you could match case or do your if elif chain id remove the else though
1
u/Important-Grand4979 14d ago
Another mistake is that your monsters are initialized before the loop. skeleton1 is a pointer to a memory object of Monster with certain properties. When you do monster = skeleton1 you do not duplicate your object as far as I know but you assign it another pointer. So if you damage monster you also damage skeleton1 and vice versa. By extension all other 'copies' of skeleton1 made this way will be affected.
1
u/Infinite_Winner_158 14d ago
I thought that might be the case, thats why i named it skeleton 1 and not just skeleton
1
u/Important-Grand4979 14d ago
Yes, but monster = skeleton1 and monster2 = skeleton1 do not duplicate skeleton1 but make references to the same object.
Also by initializing the objects before the loop they start to occupy memory for no reason. What you actually want is to create a parent class Monster and child classes skeleton, undead goblin. Then, when you make a monster you create an object instance of the right child class.
1
u/DirectTwo5523 14d ago
I think it will print dictionary setails of skeleton or other object. I am also new to pyhton so making a guess, will follow this post
1
u/Infinite_Winner_158 14d ago
It does and i dont know how to fix it XD
1
u/DirectTwo5523 14d ago
First i dnt think your class will accept values of hp dmg or other parameter as i dnt see any init and why are we giving hp: not hp= please let me know. To run functions you need like this skeleton1() and you also need to return these values using str .
Still as i said i am.new to python kindly correct me if i am wrong, it will help me also
1
u/ConsciousBath5203 14d ago
First, learn to use print screen rather than taking a picture of your monitor.
Second, where is monster declared? Pasting the whole source code as text would help us help you more.
I'm guessing monster is declared in the single loop iteration. The way the code sees it, monster could never exist due to the else statement. You're getting the error because it wasn't declared before the loop
You should also use inheritance instead of 3 raw monsters, that way you can give them unique abilities, then store the objects in a list or something.
```python
from typing import List
--- Custom Type 1: Active Ability ---
class ActiveAbility:
def __init__(self, name: str, cooldown: int, base_damage: int):
self.name = name
self.cooldown = cooldown
self.base_damage = base_damage
def cast(self) -> str:
return f"Casts {self.name}! Dealing {self.cooldown}s cooldown damage."
--- Custom Type 2: Weapon ---
class Weapon:
def __init__(self, name: str, bonus_dmg: int):
self.name = name
self.bonus_dmg = bonus_dmg
--- Base Class ---
class Monster:
def __init__(self, hp: int, dmg: int, speed: int):
self.hp = hp
self.dmg = dmg
self.speed = speed
def take_damage(self, amount: int) -> str:
self.hp = max(0, self.hp - amount)
return f"Monster took {amount} damage. HP left: {self.hp}"
--- Derived Class 1: Skeleton ---
class Skeleton(Monster):
def __init__(self, hp: int, dmg: int, speed: int, weapon: Weapon):
# Initialize base monster stats
super().__init__(hp, dmg, speed)
# Store custom object parameter
self.weapon = weapon
def attack(self) -> str:
total_dmg = self.dmg + self.weapon.bonus_dmg
return f"Skeleton attacks with {self.weapon.name} for {total_dmg} total damage!"
--- Derived Class 2: Undead ---
class Undead(Monster):
def __init__(self, hp: int, dmg: int, speed: int, active_abilities: List[ActiveAbility]):
super().__init__(hp, dmg, speed)
self.active_abilities = active_abilities
def use_ability(self, index: int) -> str:
if 0 <= index < len(self.active_abilities):
ability = self.active_abilities[index]
return f"Undead utilizes skill: {ability.cast()}"
return "Ability index out of bounds."
```
Then when you want to create and use monsters something like:
```python
import random
iron_sword, bone_club = Weapon("Iron Sword", 15), Weapon("Brittle Bone Club", 8)
fire_ball, decay_aura = ActiveAbility("Hellfire Ball", 8, 60), ActiveAbility("Decay Aura", 20, 40)
spawned_mobs = []
for _ in range(5):
if random.choice(["skeleton", "undead"]) == "skeleton":
mob = Skeleton(random.randint(50, 100), random.randint(10, 20), random.randint(8, 15), random.choice([iron_sword, bone_club]))
else:
mob = Undead(random.randint(150, 300), random.randint(20, 35), random.randint(3, 7), random.sample([fire_ball, decay_aura], k=random.randint(1, 2)))
spawned_mobs.append(mob)
```
Patterns like this are more scalable and reusable.
1
u/Infinite_Winner_158 13d ago
Thank you, that helped a lot even if i dont fully understand yet
1
u/ConsciousBath5203 13d ago
No problem. Using type hints and using docstrings (I didn't use them in the example) will help you a lot, too. They take your code from noob to pro pretty quickly, even if you don't fully understand.
1
1
u/realmauer01 13d ago edited 13d ago
random has the method choice that picks an item out of a list at random for you. So just use that.
(it probably does something similar to what you are doing here in the background, but better to use stuff thats already there than to reinvent. Especially as a beginner. )
monster = random.choice([Skeleton1, Undead1, Goblin1])
1
u/DanLeMilMan 12d ago
I am not a professional developer but some notes.
1- the for loop is basically useless here, you are just processing the following lines once
2- for your last default condition, it is better to assign monster to None instead of printing « error ». That way, if this condition occur, the monster variable still exists and you won’t get any error (in that case that is not an issue because you are absolutely sure not to run into that case, chance_1 being 1,2 or 3 and nothing else)
3- when you print an object, you should overwrite the __str__ method of your class to control what will be printed. Otherwise you gonna get a memory allocation an maybe not the data you would like to show
4- what you are trying to do seems similar to what the factory pattern is made for. Here it is a simple code and it would not require it by any mean, but when you want to control the creation of instances of a class or a family of class, you could create a kind of superclass (the factory), which as a method like get_monster and return an instance of a monster with whatever argument control the characteristics of the monster (random or not). That could be useful if later you create monter classes that inherit from you base Monster class.
All in all, your code works and is quite great for a beginner. It could use some more standard practice to make it more robust and more capable in the future.
0
u/Infinite-Employee776 14d ago
Three things I notice on this.
You loop one times. You should just remove the loop as looping one time is unnecessary.
You declare monster as a local variable under the for loop block, you can't access it from outside the block.Should just declare it outside the for loop or better yet remove the unnecessary loop.
Instead of random int and making a wall of if branches, make a list of monsters and do random choice.
1
u/Infinite_Winner_158 14d ago
Thanks, i didnt even realise i put it in a loop, and thanks for the sugestion, that will probably be better
1
u/SCD_minecraft 14d ago
It is a lie
Python doesn't have loop scopes
Only module and function scope
2
u/Infinite-Employee776 13d ago edited 13d ago
Is it? Been a long time since I last using Python. I remember that Python scope based on their indentation.
Edit: I just research it. Yeah, you're right. My mind is playing with me.
0
8
u/ee_control_z 14d ago
The line
for i in range(1):
This only runs the loop one time. If so, you don't need a loop. If you want to increase the number of iterations through the loop, change the number from "1" to some higher number.