How do I use Class Attributes, Arguments and "self." effectively in Python? - python

I am creating a text-based adventure game (as mentioned in this post), and I am stuck on how to use Classes and their attributes, arguments related to classes, and the pre-defined keyword self.. I have looked around for how to use them, but to no avail. I will give an example of each, with a question attached to them:
class Player:
def __init__(self, name):
self.name = name
self.maxhealth = 100
self.health = self.maxhealth
self.attack = 15
self.money = 0
def display(self, name):
print("Name:",self.name,"\nHealth:",self.health,"/",self.maxhealth,"\nAttack Damage:",self.attack,"\nMoney:",self.money)
Someone from the answers suggested changing self.name = name to self.name = None, but they didn't explain why or how it would help. If anyone could tell me how to define self.name in the correct or most efficient way, please do. I would also like to know how to call it in later functions.
I am confused on how class attributes work (related to previous question), and how you know if they are enabled, and how to call them.
I am also unsure of the arguments that would go into class Player(#here):, and how they could be used. I'm not sure if there are any uses to it, but I have seen people do (object) and (Edum #or something like that) and I don't know what they add, how to call them etc.
import time
import random
import sys
import pickle
class Zombie:
def __init__(self, name):
self.name = name
self.maxhealth = 50
self.health = self.maxhealth
self.attack = 5
self.golddrop = random.randint(5,10)
class Skeleton:
def __init__(self, name):
self.name = name
self.maxhealth = 75
self.health = self.maxhealth
self.attack = random.randint(5,10)
self.golddrop = random.randint(5,10)
class Friend:
def __init__(self, name):
self.name = name
self.maxhealth = 100
self.health = self.maxhealth
self.attack = random.randint(7,10)
class DungeonBoss:
def __init__(self, name):
self.name = name
self.maxhealth = 150
self.health = self.maxhealth
self.attack = random.randint(15, 25)
Those are the classes I want in my game. I am wondering whether I can make a class just called "enemies" and then maybe make sub-sets/classes that can then be called from that class (once again, any help with how to call attributes from classes will be much appreciated), so it makes the code a lot cleaner.
Please leave a comment if you are unsure about anything I just said, or if you need some more clarification with the questions. Thank you in advance.

Ok so quick lesson in Python Classes. First, lets cover self. Self refers to the Object you create for that class. So lets say:
zombie1 = Zombie("bob")
self in this instance refers to the object "zombie1"
Now, to use attributes of methods. Think of a class as something that encapsulates some generic data. You have that part down it seems already. Now the attributes are those generic data types that the class contains. So for instance, your zombies name, attack, etc. To access them, we simply do as such:
zombie1.name
'bob'
zombie1.attack
5
So on and so forth. This will give you the data that is attached to those attributes.
Now to make sub classes, you could do something like this.
class Enemies(object):
def __init__(self):
self.maxhealth = 100
class Zombies(Enemies):
def __init__(self, name):
super().__init__()
self.name = name
self.health = self.maxhealth
self.attack = 5
self.golddrop = random.randint(5, 10)
You would assign an object to it like so:
zombie2 = Zombie("Mike")
The output such as this, will give you the data from the Zombie class and the Enemies Class:
zombie2.maxhealth
100
zombie.name
'Mike'
zombie2.attack
5
So on and so forth. If you look carefully, you will see that zombie2 has the attribute maxhealth, even though that is initialized and defined under Enemies. Hope this helps some!
Ill leave the enemies class up to you as far as how you wish to create generic enemy data to be used by individual monsters. I just wanted to use maxhealth as an example to show it can pull from the parent class in a sub class.
Response to comment question:
To get a players name, you can go one of two ways, create a method, or ask for it when programming it out. I will show you both ways.
class Player(object):
def __init__(self):
self.name = None
self.gold = None
def getName(self):
self.name = input("Please enter your name: ")
print(self.name)
player1 = Player()
player1.getName()
When you call player1.getName() it will ask for their name and store it to the name variable. You can then call there name via:
player1.name
'Peter'
You could also do:
class Player(object):
def __init__(self, name):
self.name = name
self.gold = None
This way you can call the players name on the object creation such as:
player1 = Player(input("Please enter your name here: "))
player1.name
'Peter'
This way allows you to specifically code a name, or ask the user for one.
Last edit for the gold bit here:
class Player(object):
def __init__(self, name):
self.name = name
self.gold = None
def giveGold(self):
print("Since you are new, 100 gold dubloons have been given to you!")
self.gold = 100
So this allows you to call Player() how ever you wish. You can hardcode a name, or ask for user input. Then run the method giveGold() on the Player() object to grant them 100 gold Dubloons.
player1 = Player("Peter")
player1.giveGold()
Since you are new, 100 gold dubloons have been given to you!
player1.gold
100
Hope that makes sense. I think I have helped get you started quite well. I will leave the rest of the game making to you :)

Related

How to initialize subclasses of an abstract class?

I'm trying to create a dark souls style text-based game. I've created an abstract class which outlines the characteristics of a dark souls class/character type. There are a couple of ways I have initialized it and I'm not sure if one is better than the other.
One important note is that in all of the subclasses, the only parameter I want is the name parameter, while all other variables will be set equal to values specific to that class/character type.
Here is one of the abstract classes I created and its subsequent subclass:
class Character(ABC):
def __init__(self, name, description, health, endurance, strength) -> None:
self.name = name
self.description = description
self.health = health
self.endurance = endurance
self.strength = strength
class Giant(Character):
def __init__(self, name) -> None:
super().__init__(name, description="giant", health=500, endurance=20, strength=100)
Here is the 2nd version:
class Character(ABC):
def __init__(self, name) -> None:
self.name = name
self.description = ''
self.health = 0
self.endurance = 0
self.strength = 0
class Giant(Character):
def __init__(self, name) -> None:
super().__init__(name)
self.description = "giant"
self.health = 500
self.endurance = 20
self.strength = 100
Is one way better than the other? Is there a totally different way which would be better? I'm pretty new to inheritance and abstract classes and I'd appreciate any help you'd be able to provide. Thanks!
I would indeed use neither approach, at least for what you've described here so far in this example.
Is the only way that different subclasses of Character are different that their stats are different? Or would they actually have different behavior?
Because if it's really only about different values, I'd instead just make Character a concrete rather than abstract class and then provide certain methods:
class Character:
def __init__(self, name, description, and so on):
set the values here
#classmethod
def create_giant(cls, name):
return cls(name=name, description="giant", health=500, and so on)
And then you'd make a giant like so:
my_giant = Character.create_giant(name="Olbrzym")
For your versions, they have slightly different semantics. In your version 1, someone calling super().__init__ will be forced to provide concrete values, whereas in version 2, they can just rely on the default values. Given that a character with health=0 probably doesn't make sense, I'd favor version 1.
You see that my version doesn't use inheritance. When would I use inheritance? When I can't easily differentiate the various character types (Giant, Dwarf, Elf?) through their health and endurance and strength values alone but actually need different behavior.
Like, if you imagine keeping with the simple approach and you end up with code that uses a lot of constructs like
if self.description == 'Giant':
do_giant_stuff()
elif self.description == 'Dwarf':
do_dwarf_stuff()
elif AND SO ON
that's a good sign you should be using inheritance instead.
EDIT:
So, to have the classes different behavior, version 1 or 2? Either would work, honestly. But there's a third way. Might be overkill but might come in handy: Hook methods.
Here's how that goes: Write things so that subclasses don't have to call super().__init__. Instead, write the init in the abstract class but have it call abstract methods to fill in the default values.
class Character(ABC):
def __init__(self, name):
self.name = name
self.description = self._get_class_description()
self.health = self._get_class_health()
...
#abstractmethod
def _get_class_description():
pass
... same for the other attributes
class Giant(Character):
def _get_class_description(self):
return "giant"
def _get_class_health(self):
return 500
...
It's called the hook method because the abstract base class describes the methods that a subclass should specify (the hooks) in order to fill in the gaps in behavior.

simple taming calculator project

class tame_dilo:
torpor = 250
def __init__(self, name, effect):
self.name = name
self.effect = effect
def attack(self):
self.torpor = self.torpor - self.effect
dilo = tame_dilo('dilo', 25)
dilo.attack()
print(dilo.torpor)
class tame_sable(tame_dilo):
torpor = 500
sable = tame_sable('sable', 25)
sable.attack()
print(sable.torpor)
I just started learning some oop on python and I decide to do this little project to practice a little.
What I want to know is, if Im using the proper way to relate the name of the creature with its torpor by using inheritance and some polymorphism to define a diferent torpor according to the creatur class.
And also i want to know what would be the proper method so the user can change the effect of the attack method like if you were using better equitment to knock the creature.
A dilo and a sable are a type of tame. They are instances, not classes.
Therefore, you need one class capable of holding different attributes.
Also, assuming torpor is health, or energy, I'm not sure why the attack function is affecting itself. Shouldn't an instance be attacking something else?
class Tame:
def __init__(self, name, effect, torpor):
self.name = name
self.effect = effect
self.torpor = torpor
def attack(self, other):
other.torpor -= self.effect
Now you create named instances
dilo = Tame('dilo', 25, 250)
sable = Tame('sable', 25, 500)
dilo.attack(sable)
print(sable.torpor)
To change the effect of a tame, just update it
dilo.effect += 10

How to share properties and methods between classes?

Having been here: Python class inherits object, and here What is a metaclass in Python? I'm still unsure of how to get my code working. I'll be honest those explanations were a bit complicated for me. (BTW This is all in Python 3.4).
I'm trying to make Objects for my game in the form of creatures. Example: I want an Object called Dragon, but I want Dragon to inherit the class Entity, and the class Monster.
Here's what I've got:
class Entity:
id = 0
xLocation= 0
yLocation = 0
name = ''
description = ''
def __init__(self, id, xLocation, yLocation, name, description):
self.xLocation = xLocation
self.yLocation = yLocation
self.id = id
self.name = name
self.description = description
class Monster:
life = 0
pierce = 0
slash = 0
blunt = 0
pierceReduction = 0
slashReduction = 0
bluntReduction = 0
defenseBonus = 0
score = 0
def __init__(self, pierceReduction, bluntReduction, slashReduction, price, name, score):
self.pierceReduction = pierceReduction
self.bluntReduction = bluntReduction
self.slashReduction = slashReduction
self.price = price
self.name = name
self.score = score
class Structure:
pass
Monster = Entity
Dragon = Monster
I don't know how I can give Dragon all of the values of both an entity and a Monster? Obviously setting Dragon directly to monster doesn't work.
*****I've now tried this*****:
class Structure:
pass
class Dragon(Entity, Monster):
pass
Dragon(10, 10, 10, 1000, 'Dragon', 1000)
The Dragon is saying it doesn't have all the parameters of both classes though?
You can inherit from Entity class: class Monster(Entity): in declaration. You can find detailed information in documentation
Python can have classes inheriting from multiple parents. You can simply do:
class Dragon(Monster, Entity):
# class details
Just make sure that the resolution order between those classes is what you expect. Search for "python mro" for more details about it.

How should I handle Python list properties with respect to getters/setters?

It is my understanding that one aspect of the Pythonic way is to use direct member variable access of classes until 'getters/setters' are needed. Code is available on Ideone
class Person():
def __init__(self, name, age=None, friends=None):
self.name = name
self.age = age
if friends is None:
self.friends = []
else:
self.friends = friends
me = Person('Mr. Me')
you = Person('Ms. You')
me.age = 42
me.friends.append(you)
Because of the #property decorator approach this access to member variable age can be 'converted' to a 'getter/setter' interface in the future without rewriting the line that sets it to 42. But what about the last line where I add you to my friends list? Is it possible for the Person class to intercept the append() call and take other actions? Perhaps in the future I would decide to add the feature that you would get notified that they have been added to me's friends list.
Of course, once I ask the question my brain turns on and comes up with a solution. Let me know if this is good or not. Instead of intercepting the .append() call in Person, create a class PersonFriendList(List) and override append() with the desired functionality. Then, instead of assigning [] to self.friends assign PersonFriendList(). The .friend value should probably also get decorated as a #property so that assignment can be intercepted by Person to avoid .friend being written to the wrong kind of list.
Code available on Ideone.
class Person():
def __init__(self, name, age=None, friends=None):
self.name = name
self.age = age
if friends is None:
friends = []
self.friends = PersonFriendList(friends)
class PersonFriendList(list):
def __init__(self, *args):
super(PersonFriendList, self).__init__(*args)
self.DebugPrint('constructed with {}'.format(str(*args)))
def DebugPrint(self, string):
print('{}(): {}'.format(self.__class__.__name__, string))
def append(self, *args):
super(PersonFriendList, self).append(*args)
self.DebugPrint('appending {}'.format(str(*args)))
me = Person('Mr. Me')
you = Person('Ms. You')
me.age = 42
me.friends.append(you)

__init__ and the setting of class variables

Im having some trouble understanding Inheritance in classes and wondering why this bit of python code is not working, can anyone walk me through what is going wrong here?
## Animal is-a object
class Animal(object):
def __init__(self, name, sound):
self.implimented = False
self.name = name
self.sound = sound
def speak(self):
if self.implimented == True:
print "Sound: ", self.sound
def animal_name(self):
if self.implimented == True:
print "Name: ", self.name
## Dog is-a Animal
class Dog(Animal):
def __init__(self):
self.implimented = True
name = "Dog"
sound = "Woof"
mark = Dog(Animal)
mark.animal_name()
mark.speak()
This is the output through the terminal
Traceback (most recent call last):
File "/private/var/folders/nd/4r8kqczj19j1yk8n59f1pmp80000gn/T/Cleanup At Startup/ex41-376235301.968.py", line 26, in <module>
mark = Dog(Animal)
TypeError: __init__() takes exactly 1 argument (2 given)
logout
I was trying to get animal to check if an animal was implemented, and then if so, get the classes inheriting from animal to set the variables that Animals would then be able to manipulate.
katrielalex answered your question pretty well, but I'd also like to point out that your classes are somewhat poorly - if not incorrectly - coded. There seems to be few misunderstandings about the way you use classes.
First, I would recommend reading the Python docs to get the basic idea: http://docs.python.org/2/tutorial/classes.html
To create a class, you simply do
class Animal:
def __init__(self, name, sound): # class constructor
self.name = name
self.sound = sound
And now you can create name objects by calling a1 = Animal("Leo The Lion", "Rawr") or so.
To inherit a class, you do:
# Define superclass (Animal) already in the class definition
class Dog(Animal):
# Subclasses can take additional parameters, such as age
def __init__(self, age):
# Use super class' (Animal's) __init__ method to initialize name and sound
# You don't define them separately in the Dog section
super(Dog, self).__init__("Dog", "Woof")
# Normally define attributes that don't belong to super class
self.age = age
And now you can create a simple Dog object by saying d1 = Dog(18) and you don't need to use d1 = Dog(Animal), you already told the class that it's superclass is Animal at the first line class Dog(Animal):
To create an instance of a class you do
mark = Dog()
not mark = Dog(Animal).
Don't do this implimented stuff. If you want a class that you can't instantiate (i.e. you have to subclass first), do
import abc
class Animal(object):
__metaclass__ = abc.ABCMeta
def speak(self):
...
Since age in the given example is not part of the parent (or base) class, you have to implement the the function (which in a class is called method) in the class which inheritted (also known as derived class).
class Dog(Animal):
# Subclasses can take additional parameters, such as age
def __init__(self, age):
... # Implementation can be found in reaction before this one
def give_age( self ):
print self.age

Categories