New python learner here. I'm trying to design a text rpg in python and i want the stats of all the enemy mobs to increase at a specific part of the game. Here is my code for some those enemies:
class Executioner:
def __init__(self,name):
self.name = name
self.potions = 0
self.maxhp = 800
self.hp = self.maxhp
self.attack = 25
self.ability = 0
self.defense = 0
self.goldgain = 333
self.expgain = 250
ExecutionerIG = Executioner("Executioner the slayer")
class Goblin:
def __init__(self,name):
self.name = name
self.potions = 0
self.maxhp = 80
self.hp = self.maxhp
self.attack = 25
self.ability = 0
self.defense = 0
self.goldgain = 5.5
self.expgain = 22
GoblinIG = Goblin("Goblin")
class Zombie:
def __init__(self,name):
self.name = name
self.potions = 0
self.maxhp = 180
self.hp = self.maxhp
self.attack = 19
self.ability = 0
self.defense = 0
self.goldgain = 7
self.expgain = 28
ZombieIG = Zombie("Zombie")
I thought a way to do this quickly can be defining those classes into a big class called enemies and then call enemies.hp, enemies.attack etc to increase.
But i don't know how to do that either as i am quite weeb for now.
Suggestions on how to increase class stats by specifying small classes under a big class or ways to increase class stats quickly(just typing them up and increasing them won't work as i will be having lots of enemy mobs) will be greatly thanked.
What Daniel Roseman said is true, you should try to not repeat yourself when writing code. If two objects are very similar and only differ in some certain values, then really they are the same object. All bikes are bikes, but some have different wheel sizes for example. Here, your objects are all one Enemy object, and can be implemented as such.
I will however answer your question, because subclassing is very important to know. To subclass a class, you pass in the parent class in a definition, like so:
class Zombie(Enemy):
Then if the Enemy class is defined like so for example:
class Enemy:
def attack():
<your code>
You could call attack on a Zombie object. It will look for attack() in the Zombie class, and if it doesn't find it, it will look for it in the parent class. If it doesn't find it in the parent class it will look for it in that parent's class and so on, moving all the way up to the top level object. If it doesn't find it at all an Exception will be raised. If you defined attack() in the Zombie class for example, then it would overwrite attack() in the Enemy class.
Given all this though, Daniel Roseman is right. You should put all this in one class and pass in hp etc upon construction.
No, that wouldn't be a good way to do it. Nested classes are rarely useful in Python, and certainly wouldn't be helpful here.
Much better to simply put them into a list you can loop through:
enemies = []
...
ExecutionerIG = Executioner("Executioner the slayer")
enemies.append(ExecutionerIG)
and so on. Then, when necessary, just iterate:
for enemy in enemies:
enemy.hp += 1
As an aside, I would question whether you really need separate classes for Executioner, Zombie and Goblin; they only differ in the numbers for each stat, so perhaps you should just accept those values in the __init__ method for a generic Enemy class.
Related
I am new to python and apologize in advance if this is too bad.
Suppose i dynamically make an object an attribute of another object.
Can the assigned as an attribute object access the assigned to object's other attributes without inheritance or passing as an argument?
e.g:-
class human:
def __init__(self):
self.health = 100
class fire:
def __init__(self):
self.fire = 10
def damage(self):
????.health -= self.fire #can i do anything to get bill's health?
bill = human()
bill.fired = fire()
bill.fired.damage() #the fired object wants to know the bill object's health
I know i can pass bill's health as an argument to the damage function:-
class human:
def __init__(self):
self.health = 100
class fire:
def __init__(self):
self.fire = 10
def damage(self, obj):
obj.health -= self.fire
bill = human()
bill.fired = fire()
print bill.health
bill.fired.damage(bill) #now the fired object knows bill's health
print bill.health #works fine
But is there any other way or is this a dead end? Apart from the inheritance.
(I'm using python v2.7, but of course would like to know v3 solution too)
Once again i apologize if this question is too bad or has been answered.
I tried to read this one Can an attribute access another attribute?, but i couldn't understand it, its too complex. And if i google this question the results only lead to "How to access objects attributes" e.g this https://www.geeksforgeeks.org/accessing-attributes-methods-python/. And this one How to access attribute of object from another object's method, which is one of attributes in Python? uses inheritance.
Yes, you can pass the human into fire when it is created since they seem to be linked to one another:
class Human:
def __init__(self):
self.health = 100
class Fire:
def __init__(self, human):
self.fire = 10
self.human = human
def damage(self):
self.human.health -= self.fire
bill = Human()
bill.fired = Fire(bill)
bill.fired.damage() #the fired object damages bill object's health
I'm not sure what's your goal, but as I mentioned, your issue looks like a code smell to me (an indication that something's not right).
Assuming you want the human instances to catch fire (i.e. create a fire instance) and then deduce the fire damage their health, consider the refactoring below:
class human:
def __init__(self):
self.health = 100
self.fire = None
def set_on_fire(self):
self.fire = fire()
def suffer_burn_damage(self):
if self.fire is not None:
self.health -= self.fire.damage
class fire:
def __init__(self):
self.damage = 10
bill = human()
print(bill.health) # output: 100
bill.set_on_fire()
bill.suffer_burn_damage()
print(bill.health) # output: 90
This way, you do not need the fire instances to know about the human's health in the first place. It's the human's "job" to keep track of whether it is burned or not, and when to deduce its own damage.
This makes sense in a more abstract meaning, too - which is one of the points of using OOP. A fire in real life has a certain energy. A human that catches fire will have its "health" deduced from whatever amount of energy that fire has. The fire itself has no business knowing about the human's health, or anything else for that matter.
i'm trying to create a function to raise max hp whenever a stat is increased or decreased. i have tried changing self.maxHpCalc() player.** moving the variables = (int) into the orc class in every why i can think of and have been having no luck. depending on how i change it i get self/player have no attribute strength, maxHp or maxHpCalc is not defined.
class player:
def __init__(self, hp = 1 , maxHp = 1, strength = 4, defense = 5):
self.hp = hp
self.maxHp = maxHpCalc()
self.strength = strength
self.defense = defense
def maxHpCalc():
player.maxHp = player.strength + player.defense
class orc(player):
def __init__(self, hp, maxHp, strength , defnese):
super().__init__(hp, maxHp, strength, defense)
print(player.maxHp)
everything i change give me player/self has no attribute strength at the moment
Here's some fixed code, with a small driver program to exercise the classes.
Note the following changes
The function maxHpCalc should be a bound method, if it is to operate on data contained in a player instance. Therefore it should have a self parameter and should reference strength and defense from that self reference.
When calling _maxHpCalc you should reference self. I made it a bound method and it needs an instance to work on. I added an underscore to indicate it's a private method.
You should call maxHpCalc after setting the values of strength and defense, otherwise they are not defined at the point the function is called.
player.maxHp makes no sense. player is a class and has no static
property maxHp, you need an instance to access that property. I create an instance and reference that.
code:
class player:
def __init__(self, hp=1, maxHp=1, strength=4, defense=5):
self.hp = hp
self.strength = strength
self.defense = defense
self.maxHp = self._maxHpCalc()
def _maxHpCalc(self):
return self.strength + self.defense
class orc(player):
def __init__(self, hp, maxHp, strength , defense):
super().__init__(hp, maxHp, strength, defense)
p = player()
o = orc(1,2,3,4)
print(p.maxHp)
print(o.maxHp)
I also have to ask, why include a constructor parameter maxHp if you don't use it but calculate it from other parameters?
So I have this code:
class vehicle(object):
def __init__(self):
self.age = 6
self.make = 8
self.colour = 'colour'
self.cost = 'cost'
class car(vehicle):
def __init__(self):
vehicle.__init__(self)
self.type = 'car'
car1 = car()
print car1.make, car1.colour, car1.cost, car1.type, car1.age
n = raw_input()
dic = {'name' : n}
dic['name'] = car()
print dic['name'].make
In the last bit, I was able to resolve a previous issue I had: Creating an instance of the car class with its name being one that the user inputs in n
Now, say I wanna ask the user to input a name and now I have to find the class' instance that has that name.
For example if at one point an instance with the name car2 was created. Now user wants to get info about car2 and inputs 'car2'. how can I use this input to access attributes of the instance called car2?
I tried:
a = raw_input()
dic['fetch'] = a
dic['fetch'].make
does not work.
It seems to me you have a fair bit of misunderstanding. The way you're assigning the input into the dictionary doesn't make sense. Your description indicates that you want a dictionary that maps a "name" to a car description.
Your initial creation of the dictionary is off. The way you're currently doing it, you're actually losing the name the user inputs when you assign the car data. Some better variable naming might help you. Create your dictionary like this:
cars_by_name = dict()
name = raw_input()
cars_by_name[name] = car()
So now you have a name (given by the user) that maps to a car description.
Now you need to fetch that same car instance again. You do it by using the name as the key in the dictionary:
name2 = raw_input()
print cars_by_name[name2].make
Next, let's look at your classes. My first question: why do you need a vehicle and a car class? If you're never going to have classes other than car inheriting from vehicle, you don't really need them both. Even if you do plan the have more subclasses, I would probably still recommend against inheritance here. Your vehicle has no behavior (methods) for subclasses to inherit. It's just a data object. With duck typing so strongly encouraged in Python, inheriting from a class with no methods doesn't buy you anything. (What a base class would buy you with methods is that you'd only have to define the method in one place, making it easier to modify later on.) Particularly in your case, there doesn't seem to be any motivation to create a subclass at all. A single class for all vehicles will work just fine. So let's simplify your classes:
class Vehicle(object):
def __init__(self):
self.age = 6
self.make = 8
self.colour = 'colour'
self.cost = 'cost'
self.type = 'car'
(Also, note that class names are usually given in camel case in Python.) Now there's one more problem here: those constants. Not all Vehicles are going to have those same values; in fact, most won't. So lets make them arguments to the initializer:
class Vehicle(object):
def __init__(self, age, make, colour, cost, type):
self.age = age
self.make = make
self.colour = colour
self.cost = cost
self.type = type
Then you create one like this:
v = Vehicle(6, 8, 'colour', 'cost', 'car')
Good luck in your endeavors learning. Hope this helps.
If I understand you correctly and you want to map string names to instances:
n = raw_input()
dic = {n: car()}
print dic[n].make
print(dic)
dic[n].cost = 10000
print(dic[n].cost)
Another option would be to take a name for each car instance and have a class attribute dict mapping names to self.
In [13]: paste
class vehicle(object):
def __init__(self):
self.age = 6
self.make = 8
self.colour = 'colour'
self.cost = 'cost'
class car(vehicle):
dic = {}
def __init__(self, name):
vehicle.__init__(self)
car.dic = {name: self}
self.type = 'car'
self.name=name
car1 = car("car1")
car2 = car("car2")
car2.colour="blue"
print car1.make, car1.colour, car1.cost, car1.type, car1.age
n = raw_input()
print car.dic[n]
print car.dic[n].make
print car.dic[n].colour
## -- End pasted text --
8 colour cost car 6
car2
<__main__.car object at 0x7f823cd34490>
8
blue
For some reason, in a method I make, I put self as the first parameter, but it doesn't read it. When I try to run the method, it says it needs the 'self' positional argument.
class Monster():
name = "Snake"
health = 100
def decreaseHealth(self):
if health <= 0:
print('Dead')
health -= 4
Monster.decreaseHealth()
The issue is that you're calling decreaseHealth() on the class itself, whereas you should be calling it on an instance of the class:
m = Monster()
m.decreaseHealth()
This will automatically bind self to m.
P.S. To refer to health inside the method, use self.health.
Here is a version that fixes a couple of other (mainly stylistic) issues:
class Monster(object):
def __init__(self):
self.name = "Snake"
self.health = 100
def decreaseHealth(self):
if self.health <= 0:
print('Dead')
else:
self.health -= 4
m = Monster()
m.decreaseHealth()
If you want a class method, better make it one:
#classmethod
def decreaseHealth(cls):
...
Then you can call Monster.decreaseHealth, and you can access the class variables with cls. (e.g. cls.health). But, then, you are operating on "global" state associated with the class itself.
You probably want to make an instance of your monster instead:
class Monster:
''' Base class for monsters '''
class Snake(Monster):
def __init__(self):
self.name = "Snake"
self.health = 100
def decreaseHealth(self):
self.health -= 4
if self.health <= 0:
print("dead")
mysnake = Snake()
mysnake.decreaseHealth()
That's because the way you are calling decreaseHealth() there is no self argument. self refers to the object on which a method was called. Here you have no object, you are trying to call the method on the class name.
You need to create a Monster object, then call your method:
monster = Monster();
monster.decreaseHealth()
I am new to Python and this is my first time asking a stackOverflow question, but a long time reader. I am working on a simple card based game but am having trouble managing instances of my Hand class. If you look below you can see that the hand class is a simple container for cards(which are just int values) and each Player class contains a hand class. However, whenever I create multiple instances of my Player class they all seem to manipulate a single instance of the Hand class. From my experience in C and Java it seems that I am somehow making my Hand class static. If anyone could help with this problem I would appreciate it greatly.
Thank you,
Thad
To clarify: An example of this situation would be
p = player.Player()
p1 = player.Player()
p.recieveCard(15)
p1.recieveCard(21)
p.viewHand()
which would result in:
[15,21]
even though only one card was added to p
Hand class:
class Hand:
index = 0
cards = [] #Collections of cards
#Constructor
def __init__(self):
self.index
self.cards
def addCard(self, card):
"""Adds a card to current hand"""
self.cards.append(card)
return card
def discardCard(self, card):
"""Discards a card from current hand"""
self.cards.remove(card)
return card
def viewCards(self):
"""Returns a collection of cards"""
return self.cards
def fold(self):
"""Folds the current hand"""
temp = self.cards
self.cards = []
return temp
Player Class
import hand
class Player:
name = ""
position = 0
chips = 0
dealer = 0
pHand = []
def __init__ (self, nm, pos, buyIn, deal):
self.name = nm
self.position = pos
self.chips = buyIn
self.dealer = deal
self.pHand = hand.Hand()
return
def recieveCard(self, card):
"""Recieve card from the dealer"""
self.pHand.addCard(card)
return card
def discardCard(self, card):
"""Throw away a card"""
self.pHand.discardCard(card)
return card
def viewHand(self):
"""View the players hand"""
return self.pHand.viewCards()
def getChips(self):
"""Get the number of chips the player currently holds"""
return self.chips
def setChips(self, chip):
"""Sets the number of chips the player holds"""
self.chips = chip
return
def makeDealer(self):
"""Makes this player the dealer"""
self.dealer = 1
return
def notDealer(self):
"""Makes this player not the dealer"""
self.dealer = 0
return
def isDealer(self):
"""Returns flag wether this player is the dealer"""
return self.dealer
def getPosition(self):
"""Returns position of the player"""
return self.position
def getName(self):
"""Returns name of the player"""
return self.name
From my experience in C and Java it seems that I am somehow making my Hand class static.
Actually, that is basically what you're doing. Well, not really making the class static, but making the variable static.
When you write declarations like this:
class Hand:
cards = []
that variable (cards) is associated with the class, not with the instance. To make an analogy to Java, every statement in a Python class that isn't part of a method of that class basically runs in a static initializer. You could almost think of it like this:
class Hand {
static {
cards = new object[];
}
}
(merely a rough analogy, of course)
To create an instance variable in Python, you have to set it as an attribute of the instance, which requires you to wait until you have a reference to the instance. In practice, this means you initialize it in the constructor, like so:
class Hand:
def __init__(self):
self.cards = []
Your problem is quite simple
if you assign lists to the body of python classes, when you append items to it, they will be store at Class level, not at instance level.
you can solve this problem by adding the line:
def __init__(self):
self.cards = []
this is a very known case of python pitfall, and I recommend you the reading:
http://zephyrfalcon.org/labs/python_pitfalls.html
As other answers noted, you were confused about class variables vs. instance variables. I suggest you review the basics of how Python classes work. Here is an answer I wrote for another question; reading this might help you.
How to define a class in Python