I am creating a text based adventure in python. I have ready two books on python and taken an online course, so I think I really have all the basics down.
Now I am creating my items currently. My setup is
Item->Weapon->(specific weapon here).
All classes inherit the previous.
I am unable to print the values of the items such as Holy_Sword and Stick. I am able to print them if I don't create them as classes and just use a variable to create the instance of weapon. However, due to what I want to do further down the line, I really would like them to be classes.
The error I am getting is:
unbound method str() must be called with Holy_Sword instance as first argument (got nothing instead)
My code is:
class Item(object):
def __init__(self, name, value, description):
self.name = name
self.value = value
self.description = description
def item_description(self):
return "Your %s is worth %d gold and is a %s" % (self.name, self.value, self.description)
class Weapon(Item):
def __init__(self,name, value,description, attack):
self.attack = attack
super(Weapon, self).__init__(name, value, description)
def __str__(self):
return "Your %s is worth %d gold and has an Attack Damage of %d, it is %s" % (self.name, self.value, self.attack, self.description)
class Stick(Weapon):
def __init__(self, name, value, description, attack):
super(Stick, self).__init__(name = "Stick", value= 1, description = "A stick...there may be potential here....or not.", attack = 1)
class Holy_Sword(Weapon):
def __init__(self, name, value, description, attack):
super(Holy_Sword, self).__init__(name = "The Holy Sword of Antioch", value= 20, description = "A Sword whose potential far outweighs it's lack of stylishness ", attack = 20)
class Sword(Weapon):
def __init__(self, name, value, description, attack):
super(Sword, self).__init__(name = "Sword", value= 3, description = "A Wooden Sword.", attack = 5)
print Holy_Sword.__str__()
Keep in mind that, in the code you have here, Holy_Sword refers to a class. It is not itself an instance of Item.
Holy_Sword.__str__ is an instance method. It can't be called on its own like you're trying to do here; it must be called through an instance of the Holy_Sword class.
(Note that it's usually better to not invoke __str__ directly. This method should usually only be called through the str() function, e.g. str(Holy_Sword).)
What you can do is create an instance of Holy_Sword and print the string value of that:
sword = Holy_Sword()
print str(sword)
However, you may want to instead consider making Holy_Sword be a instance of Weapon with specific attributes, rather than being a subclass. If the only way it needs to differ from other weapons is in its attributes, there's no need for it to be a separate class.
You need to instantiate the class first:
my_sword = Holy_sword(...)
print my_sword.__str__()
Related
Is it a good idea to handle all the arguments in the constructor? instead of handling them in the particular methods where the arguments are actually needed?
Method 1:
def __init__(self,name,rollno,dob,city,state,zip):
self.name=name
..
..
self.zip = zip
def address(self):
return self.city+self.state+self.zip
def unique_identifier(self):
return self.name+self.rollno
test.py
example = Example("Programming","941","1997-09-07","Nashville","TN","37311")
print(example.address())
print(example.unique_identifier())
Method 2:
Class Example:
def address(self,city,state,zip):
return self.city+self.state+self.zip
def unique_identifier(self,name,rollno):
return self.name+self.rollno
test.py
example = Example()
print(example.address("ab","cd","111")
print(example.unique_identifier("Programmer","123")
Any explanation/reasoning to help understand Which method is more preferable for best practices.
Either is fine, it just depends on if the data belongs to the object (method 1) or if the data comes from outside the object (method 2). It can also be a mix of both. A short example:
class Person:
# store data specific to the instance
def __init__(self, name, birthdate, hometown):
self.name = name
self.birthdate = birthdate
self.hometown = hometown
# here I only need data from the instance
def introduce(self):
print("Hello, I am", self.name,
", I come from", self.hometown,
" and was born on ", self.birthdate,
".")
# food shouldn't be part of the Person,
# so it is passed in as an argument
def order_food(self, food):
print("I am ", self.name,
" and would like some ", food, " please.")
i am begineer in python and i am creating a employee managment system in which class employer should have a method to delete a object but it seems impossible in python. i have tried many ways to do that but none of them worked for me. the only way it worked when i used del obj_name outside a class body which i clearly dont want
class Employee:
bonus = 1000
def __init__(self,name ,salary,lang,post):
self.name = str(name)
self.salary = int(salary)
self.lang = str(lang)
self.post = str(post)
def deleteAttr(self,attr):
delattr(self, attr)
def getInfo(self):
print(f"Name of the person is {self.name}")
print(f"Language of the person is {self.lang}")
print(f"Post of the person is {self.post}")
def getSalary(self):
print(f"The salary for {self.name} is {self.salary} ")
def inc(self,inc):
self.salary = int(inc) + self.salary
print(f"Incremented salary is {self.salary}")
def dec(self,dec):
self.salary = self.salary - int(dec)
print(f"Decremented salary is {self.salary}")
class Employer(Employee):
#staticmethod
def fired(a):
atr = a.__dict__
for i in list(atr):
delattr(a, i)
del a
def recruit(self,s,name, salary, lang, post):
s = Employee(name, salary, lang, post)
def __init__(self,name,salary,lang,post):
super().__init__(name,salary,lang,post)
def setBonus(self,incr):
self.__class__.bonus += incr
print(f"Bonus increased to {self.__class__.bonus}")
def incBonus(self):
self.bonussalary = self.salary + self.bonus
in this fired is the method i am trying to define where a is the object that i am willing to delete. i read somewhere that deleting all the attributes of an object can help in deleting it but even that is not working.please help me.Thanks in advance
This screams of an XY problem, so I'm not going to answer the question asked, and instead make notes on your design:
There is no reason for an Employer to be a subclass of Employee. Subclass relationships should follow an "is-a" relationship; unless an employer is an employee, it makes no sense to model the relationship that way (Dog can subclass Animal because a dog is an animal, but this doesn't apply to your scenario).
Deleting objects is easy. Just let the last name referring to the object go out of scope, directly or indirectly (or del it if you must), and the object goes away.
But you don't want to delete it, you want them to be fired and removed from the collection of employees from that employer. So don't model employers as employees, make them their own class that contains employees. And don't make fired a static method; that implies an employee is fired by all possible employers at once, not fired by a particular employer.
A reasonable model for Employer might be:
class Employer:
def __init__(self, bonus=1000):
self.employees = []
self.bonus = bonus # bonus argument and attribute only used if bonus is same for all employees of this employer, see below
def recruit(self, name, salary, lang, post): # Remove s, assignment won't work
self.employees.append(Employee(name, salary, lang, post))
return self.employees[-1] # Give caller reference to new employee if they need it
def fire(self, employee):
self.employees.remove(employee) # Will raise exception if employee doesn't work for this employer
def setBonus(self, employee, incr): # If this applies to one employee at a time
employee.bonus += incr
print(f"Bonus increased to {employee.bonus}")
def setBonus(self, incr): # If this applies to all employees for this employer
self.bonus += incr
print(f"Bonus increased to {self.bonus}")
def incBonus(self, employee):
# Little unclear what this was supposed to do; bonussalary wasn't an attribute for
# anything except here in original code; I'll interpret it as returning the salary
# inc(luding) bonus for the year for a given employee
return employee.salary + self.bonus # If bonus applies to all employees
return employee.salary + employee.bonus # If bonus applies per-employee
If you want to hide the Employee objects from the caller, you can have self.employees be a dict mapping a unique ID (e.g. generated via an itertools.count initialized in the constructor), and have recruit insert the new employee keyed by the unique ID, then return only the unique ID, and all other methods would accept that ID instead of the Employee object, look up the correct employee, and perform the work; this way, a given employee object is not directly exposed to the caller; when the employer fires them, they disappear. It's weird (people aren't supposed to live or die by their employment status), but you do you.
Just for completeness, a cleaned up Employee that matches the design for Employer, with the assumption that bonuses are company-wide (not per-employee):
class Employee:
def __init__(self, name, salary, lang, post):
self.name = str(name)
self.salary = int(salary)
self.lang = str(lang)
self.post = str(post)
def print_info(self): # Not named get; get implies you *return* the info; use snake_case over camelCase per Python's PEP8 style guide
print(f"Name of the person is {self.name}")
print(f"Language of the person is {self.lang}")
print(f"Post of the person is {self.post}")
def print_salary(self): # See above for name change reason
print(f"The salary for {self.name} is {self.salary}")
def give_raise(self, amount_raised): # Much more explanatory name than "inc"
self.salary += int(amount_raised) # Avoid repeating self.salary using +=
print(f"Incremented salary is {self.salary}") # Disagree with printing when this happens, but you do you I guess
def cut_pay(self, amount_lost): # Again, explanatory names are good (makes it clear value expected to be positive
self.salary -= int(dec) # Avoid repeating self.salary using -=
print(f"Decremented salary is {self.salary}")
# If not for the prints in each, I'd just implement this as:
return self.give_raise(-amount_lost)
# to reduce code duplication, or replace both functions with a single
# function, "adjust_salary" that takes a positive value for raises,
# negative for cuts, but leaving it separate due to prints contradicting
I've tried to make an OOP based program in python. I gave it an object to work with and tried to make it print the name, but its not working.
class human:
def __init__(self, name):
print("this is a human")
def name(self, name):
print("this is {}".format(bob.name))
bob = human("bob")
Anyone know what the problem could be?
Beyond the answers you already received (which solve your problem), I'd suggest not having a method that prints the name. Rather, you should have a __str___ dunder method that defines the object's behavior when an instance is printed.
class human:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
person = human("bob")
print(person)
'bob'
You can also define the object's behavior when the instance name is entered in the console, for instance just running the line
>>> person
You can do it with __repr__:
def __repr__(self):
return f'when entering the instance name in the console: {self.name}'
This will print:
when entering the instance name in the console: bob
This appears more pythonic to me than having a method that simply prints the name.
You're never storing the name on the instance, where would it get the name from? Your __init__ needs to do something along the lines of self.name = name
the name method and attribute are going to conflict, the latter will shadow (hide) the former, and it should look up whatever attribute its using on self
You never assigned the passed name to the object. Try:
class human:
def __init__(self, name):
print("this is a human")
self.name = name
def print_name(self):
print("this is {}".format(self.name))
bob = human("bob")
bob.print_name()
there are couple of things to update in the code:
bob is an instance which is not defined at human class
notice that init, name functions expect external param but you never use it in the function. (in self. = name)
in order to use it:
define a var in the class named 'name' and update you function to:
class human:
_name = ""
def __init__(self, name):
print("this is a human")
self._name = name
def name(self):
print("this is "+ self._name)
bob = human("bob")
bob.name()
bob = human("bob") only init function and you should call bob.name() in order to call the print-name function
I have a question to ask, please. Given the code below, can you please let me know why in manager (or in the worker) class why
self.FirstName
gives the same result as
self._firstName
I would have thought that self._firstName would not be accessible in either of the classes (Manager/Worker) since it local to the Employee class and should not be accessible outside it, no ?
Please suggest.
import gc
class Employee(object):
"""Employee Base Class"""
def __init__(self, FirstName, LastName,Age, Role):
super(Employee, self).__init__()
self._firstName = FirstName
self._lastName = LastName
self._age = Age
self._role = Role
#property
def FirstName(self):
return self._firstName
#property
def Age(self):
return self._age
#property
def Role(self):
return self._role
#FirstName.setter
def FirstName(self, value):
self._firstName = value;
pass
#Role.setter
def Role(self, value):
self._role = value;
pass
class Manager(Employee):
"""Manager class"""
def __init__(self, FirstName,LastName,Age):
Employee.__init__(self,FirstName, LastName, Age, 'Manager')
# super(Manager, self).__init__()
def getParents(self):
"""Get parents of the class"""
print(gc.get_referrers(self))
pass
def ManagerInfo(self):
print("FirstName : " + self.FirstName)
print("Role : " + self.Role)
print("Age : " + str(self.Age))
class Worker(Employee):
"""docstring for Worker"""
def __init__(self, FirstName, LastName, Age):
Employee.__init__(self,FirstName, LastName, Age, 'employee')
def getParents(self):
"""Get parents of the class"""
print(gc.get_referrers(self))
pass
def WorkerInfo(self):
print("FirstName : " + self.FirstName)
print("Role : " + self.Role)
print("Age : " + str(self.Age))
pass
# manager = Employee('John','Doe' , 40, 'Manager')
# print("{0}'s age is {1} years.".format(manager.FirstName, manager.Age))
anEmp = Worker('WorkerName', 'LastName', 20)
aManager = Manager('John', 'Doe', 40)
print(anEmp.WorkerInfo())
print(anEmp.getParents())
print("----------------------------")
print(aManager.ManagerInfo())
print(aManager.getParents())
Thanks
why self.FirstName gives the same result as self._firstName
Because you defined FirstName as a property returning self._firstname. What did you expect actually ?
I would have thought that self._firstName would not be accessible in either of the classes (Manager/Worker) since it local to the Employee class
It's not 'local to the Employee class', it's an attribute of Employee instances (it doesn't exist in the Employee class itself).
and should not be accessible outside it, no ?
While prefixing a name with a single underscore denotes an implementation attribute (IOW something that is NOT part of the public API - the equivalent of 'protected' in most mainstream languages), it doesn't prevent access to the attribute. Actually there's absolutely NO enforcement of access restriction in Python, it's all convention (and eventually name mangling for __pseudoprivates names).
Python's philosophy is that we are all consenting adults and are wise enough to not do stupid things like messing with what is clearly labelled as an implementation attribute without accepting full responsability for breaking encapsulation.
can you please let me know what I should be doing in order to make sure that the user can only set the value using the setters and not by doing self._firstName
Nothing more than you already did actually. Re-read the above paragraphs, I already mentionned that Python did NOT enforced access restriction of any kind. self._firstname is prefixed with a single leading underscore, which is the way to tell "this is an implemention detail and not part of the API, you should not be messing with this attribute, you should not even know it exists, so if you break something by messing with it well too bad for you dude, but you're on your own".
so if in case, I have some arbitrary logic that manipulates the value in the setter before setting it, the updated value will not be available if the user just does self._firstName instead of self.FirstName
The chances this would happen are rather low actually (and that's an understatement) but theoritically yes this could happen. But this is totally unrelated since you'd have the very same problem if the user used self.FirstName instead since it would still return the stale value...
I am having trouble figuring out why I am getting this error . My code is this
#define the Animal Class
class Animal:
def __init__ (self, animal_type, age, color):
self.animal_type = animal_type
self.age = age
self.color = color
def makeNoise():
pass
def __str__(self):
print ("% is % years old and is %" % animal_type,age, color)
#define child classes of Animal
class Wolves(Animal):
def __init__(self, animal_type, age, color, wild):
Animal.__init__(self, animal_type, age, color)
self.wild = wild
def __str__(self):
print ("% is % years old and is % and is %" % (animal_type, age, color, wild))
class Bear(Animal):
def __init__ (self, animal_type, age, color, sex):
self.sex = sex
Animal.__init__(self,animal_type, age, color)
class Moose(Animal):
def __init__(self, animal_type, age, color, antlers):
self.antlers = antlers
Animal.__init__(self, animal_type, age, color)
#add items to each class
wally = Wolves("wolf", 4, "grey","wild")
sally = Wolves("wolf", 3, "white", "tame")
print (str(sally))
print (str(wally))
and the full trace-back is
Traceback (most recent call last):
File "//mgroupnet.com/RedirectedFolders/SBT/Documents/bear51.py", line 41, in <module>
print (str(sally))
File "//mgroupnet.com/RedirectedFolders/SBT/Documents/bear51.py", line 24, in __str__
print ("% is % years old and is % and is %" % (animal_type, age, color, wild))
NameError: name 'animal_type' is not defined
What am I doing wrong?
Oh - well basically you just forgot to use self.animal_type in your __str__ method. Like so:
def __str__(self):
print ("%s is %s years old and is %s" % self.animal_type,self.age, self.color)
Just like in __init__, to use variables from your instantiated class, you need to use "self", as in "from this animal instance that I'm working on".
In Python methods are just normal functions. Therefore, you cannot access a local variable from one method in another method. The typical way to share information between methods is via self. To get animal_type in __str__, you need use self.animal_type. There is no special name space for methods in a class. This means in terms of visibility of names it does not matter if you write functions in a module or methods in a class.
In Python, self is not a keyword like this in Java. It is just a parameter like any other, which, by convention, is usually called self.
When you call a method, like some_animal.__str__()1, this is actually just syntactic sugar for Animal.__str__(some_animal), where some_animal is bound to the self parameter.
Thus, in Java (and many other languages) this means "look at the current instance for this attribute" and is optional, when unambiguous (i.e. when there is no local variable of the same name), but Python's self is not optional. It's just a regular method parameter.
1 __str__ is not a good example, as you never call it in this way, but rather str(some_animal), but you know what I mean