I'm playing around with OOP in Python and I am trying to figure out some stuff related to inheritance. . I have some code here that has a few classes. A class called Blacksmith which behaves as expected and a class called Hero which I am trying to call a function from but I recieve an unexpected output.
class Character(object):
def __init__(self,name):
self.health=100
self.name = name
# self.player = player
def printName(self):
print self.name
#def printPlayerName(self):
# print self.player
class Blacksmith(Character):
def __init__(self,name, forgeName):
super(Blacksmith, self).__init__(name)
#self.name = "Billy"
self.forge = Forge(forgeName)
class Hero(Character):
playerName = "Player"
def __init__(self,name):
super(Hero, self).__init__(name)
def setplayername(self,inputplayername):
playerName = inputplayername
class Forge:
def __init__(self,forgeName):
self.name = forgeName
bs = Blacksmith("Billy", "Billy's Forge")
print bs.health
bs.printName()
print bs.forge.name
player1 = Hero("Methos")
print player1.name
player1.setplayername("Chris")
#print playher1.playerName
print player1.playerName
Output is:
raina#DESKTOP-291MTC0 ~/python
$ python learningoopclasses01.py
100
Billy
Billy's Forge
Methos
Player
Can anyone explain why this output says "Player" and not "Chris". Another question I have is I am not entirely sure how the init methods work. What does super do in these cases? What does calling init with a name value do exactly? Thanks.
__init__ is called when an object of that Class is created. With this method, we will also use the self variable to represent the instance of the object itself. It has to be explicitly declared in Python to be defined on an object.
For example,
class Student():
def __init__(self, score1, score2, score3):
self.scores = [score1, score2, score3]
If you want to assign scores to Student 1, you would only need to use because stu_1 already has score as an attribute in it:
stu_1 = Student(80, 90, 85)
In addition, __init__ also will notify you if any parameters are entered incorrectly according to what it has been set up.
super() is used to first call the parent(super) class of Blacksmith, which is Character, and allows you access Character's property.
The call to super() in Blacksmith's __init__ method is equal to its superclass, which in this case is Character.
You could also replace super(Blacksmith, self).__init__(name) with Character.__init__(self, name). The two are equivalent.
A slight adjustment to
def setplayername(self,inputplayername):
self.playerName = inputplayername
In the Hero class will fix it, if you don't want to change anything else.
Related
I'm a beginner. I'm doing my best. Please go easy on me. My task is to create a class called "person" with one method "hello" and one attribute "name" which represents the name of a person. In the end it should print "My name is X and I am a Y, where X is the sys.argv[1] name and Y is the name of the class. I'm supposed to instantiate an object of the class, run the hello method and print the name of the class. My brain is a bit fried and I'm at a loss. Please help. I feel like I'm moving in circles and getting no where. Here's what I've got so far:
import sys
class person():
def __init__(self, name):
self.name = name
def hello(self):
print(f'My name is {self.name} and I am a {__class__.__name__}.')
print(person1.hello())
person(sys.argv[1])
person1=person(sys.argv[1])
print(str(person.__class__))
So far its not printing anything at all.
This one is working.
class Person():
def __init__(self, name):
self.name = name
def hello(self):
print(f'My name is {self.name} and I am a {__class__.__name__}.')
my_person = Person('John')
my_person.hello()
The Output:
My name is John and I am a person.
Suggestion:
For convention classes are named with first letter Capital to distinguish of the instances.
So I've got this class:
class Student(object):
def __init__(self, studentID, name):
self.__studentID = studentID
self.__name = name
def set_studentID(self, value):
self.__studentID = value
def get_name(self):
return self.__name
and running this code:
x = Student
x.set_name(x, input("Name: "))
x.set_studentID(x, len(students))
students.append(copy.deepcopy(x))
x.set_name(x, input("Name: "))
x.set_studentID(x, len(students))
students.append(copy.deepcopy(x))
for i in (students):
print(i.get_name(i))
gives an unexpected output:
For the input:
a
b
the output is:
b
b
The expected output is:
a
b
If you answer please give me a short explanation of why it doesn't work
The reason your code isn't working is because you never instantiate your class, instead, you assign the class object itself to the name x
x = Student
When you really needed
x = Student()
Then you call the methods on the class object, whilst passing the class object itself as the first parameter, thus your getters and setters act on the class object.
Finally, classes are meant to be singletons, and the copy module special cases them. So if x is a class
copy.deepcopy(x) is x
Is always True, thus you never actually make a copy.
As a side note, your class definition looks like it was written by a Java developer using Python for the first time. The Pythonic way to do it is not to use getters and setters use properties, and only when you need to. Also, don't use double-underscores name-mangling unless you actually want that, which in this case, you dont.
The other answer explains why your code doesn't work as you expect it to. Here's how you could rewrite your code in a more pythonic way.
class Student(object):
def __init__(self, studentID, name):
self.studentID = studentID
self.name = name
students = []
name = input("Name: ")
students.append(Student(len(students), name))
name = input("Name: ")
students.append(Student(len(students), name))
for student in students:
print(student.name)
You don't need to write getter and setter methods unless you have to do some special processing.
I have two classes. A vehicle class and a car class. My vehicle class does not have any attributes so I can call it without any arguments. Same for my car class. The car class is a sub class for vehicle class.
In my vehicle class I have a variable assigned a string with some text. How can my sub class car inheritance that variable?
Code:
class Vehicle(object):
def __init__(self):
self.__astring = 'Hello'
def get_string(self):
print self.__astring
class Car(Vehicle):
def __init__(self):
Vehicle.__init__(self)
# Here I need to make a working variable
self.__car_string = self.__astring
self.__car_string2 = ' Again'
self.__big_string = self.__car_string + self.__car_string2
# This method should print 'Hello Agan'
def get_car_string(self):
print self.__big_string
string1 = Vehicle()
string1.get_string() # This prints Hello
string2 = Car()
string2.get_car_string() # This should print Hello Again
When I run the code, I get:
AttributeError: 'Car' object has no attribute '_Car__astring'
I do understand why, but I do not know how to inherit that variable with the string.
The correct way to mark an attribute as private (meaning it should not be used directly outside of a method of that class, not that it cannot), is to prefix it with a single underscore.
A getter method should return the value, not print it. If you need to print the value, you can always print the return value of get_string; you cannot (easily) access a value that is directly printed by a method.
class Vehicle(object):
def __init__(self):
self._astring = 'Hello'
def get_a_string(self):
return self._astring
class Car(Vehicle):
def __init__(self):
Vehicle.__init__(self)
# Here I need to make a working variable
self._car_string = self.get_a_string()
self._car_string2 = ' Again'
self._big_string = self._car_string + self._car_string2
def get_car_string(self):
print self._big_string
The language itself will not stop you from accessing Vehicle._astring directly outside of the Vehicle class, but it should be considered a bug to do so.
I might be missing something stupid, or I am simply trying to walk through a steel wall instead of going around. Basically I have created turtle class and I use it in different script for drawing L-systems. I thought I could create a function outside the turtle class, which will accept:
turtle - the instance of from my turtle class
a string from L-system
dictionary of rules/instructions of how to interpret different symbols in the string above, that is for which symbol call which method from the turtle class
But it all crashes on trying to pass the method to the function - I think it does not see the method, since it is defined inside the class. To simplify the matters I have created a basic example, which fails at the same place:
class Person():
def __init__(self, age):
self.age = age
def birthday(self):
self.age += 1
def foo(person, method):
person.method()
jane = Person(20)
foo(jane, birthday)
#Traceback (most recent call last):
# File "passmethod.py", line 14, in <module>
# foo(jane, birthday)
#NameError: name 'birthday' is not defined
That is:
the only variable in Person class instance is age, the only method birthday raises the age by 1.
jane is Person class instance, initialized at 20 years old
the by function foo I am trying to call birthday method on her
script does not see birthday method and crashes
So, my question(s) is(are):
Is there a way, how to do it? If so, how?
If not or if it would not be advisable to do so, what should I use?
Update
Thanks for those quick and nice answers! The additional question which naturally follows - is any of those ways preferred? I would guess, that
__getattribute__ and getattr are pretty much the same, although for the first one, the inheritance is probably necessary.
I don't see any great difference in this case between using jane.birthday or Person.birthday, although in general it could be useful to be able to call the method for different Person instances, e.g. created in the foo function.
Here the working code:
class Person():
def __init__(self, age):
self.age = age
def birthday(self):
self.age += 1
def foo(person, method):
getattr(person, method)()
Test:
>>>
>>> jane = Person(20)
>>> foo(jane, 'birthday')
>>> jane.age
21
>>>
Well, there are ways to do that.
First way: just pass method bound to a particular object:
def foo(person, method):
method() # calls jane.birthday()
jane = Person(20)
foo(jane, jane.birthday)
Second way: pass a class method and apply it to a particular object:
def foo(person, method):
method(person) # calls Person.birthday(jane), which is the same thing
jane = Person(20)
foo(jane, Person.birthday)
You can use the __getattribute__ method (inherited from object):
class Person(object):
def __init__(self, age):
self.age = age
def birthday(self):
self.age += 1
def foo(person, method):
person.__getattribute__(method)()
jane = Person(20)
foo(jane, "birthday")
As I suggested in the comments, you could sub-class your Turtle to add a rule-following method. To demonstrate a trivial example:
class InstructableTurtle(Turtle):
def follow_instructions(self, instructions):
for instruction in instructions:
if instruction == "MOVE_LEFT":
self.move_left()
...
But you could also have the rules provided as an additional argument to the new instance:
def __init__(self, ..., rules): # '...' represents args to base Turtle
super().__init__(...) # or 'super(InstructableTurtle, self)' on Python 2.x
self.rules = rules
As an example:
>>> class Turtle():
def __init__(self, name):
self.name = name
def move_left(self):
print("{0.name} is moving left...".format(self))
>>> class InstructableTurtle(Turtle):
def __init__(self, name, rules):
super().__init__(name)
self.rules = rules
def follow_instruction(self, instruction):
self.rules[instruction](self)
>>> tommy = InstructableTurtle("Tommy", {"LEFT": Turtle.move_left})
>>> tommy.follow_instruction("LEFT")
Tommy is moving left...
I have no idea what is wrong! This is a very simple program and I have done a lot head banging! Please someone enlighten me!
This a lab problem from the CSE 111 - Programming Language II course. They teach Java at the university and the code I wrote in Java works fine.
I just have to create a Student class with some fields to hold the basic information about a student with methods to get and set the attributes. Then create an instance of that class and tryout the methods.
But every time I run this program the following error occurs:
TypeError: set_name() takes exactly 1 positional argument (2 given)
Here is the code I wrote.
class Student:
'''Student class'''
name = None
id = 0
address = None
cgpa = None
def get_name():
return name
def set_name(n):
name = n
def get_id():
return id
def set_id(i):
id = i
def get_address():
return address
def set_address(a):
address = a
def get_cgpa():
return cgpa
def set_cgpa(c):
cgpa = c
#An object of Student class
jack = Student()
jack.set_name('jacky')
print(jack.get_name())
You're not accepting a reference to your instance as the first argument to that method, i.e. your set_name() should be written:
def set_name(self, n):
self.name = n
This is somewhat different from other languages where there is a built-in keyword (such as this) that refers to the current object. Python passes that reference explicitly, as an argument to the method.
All your other methods must be modified similarly.
Note that just setting name = n sets a local variable name which goes away when the method ends; it does not set anything on the instance. You have to explicitly set self.name if you want an instance attribute.
Also, and this is a matter of style, but you do not usually write set and get methods in Python. It is normal practice to set and get attributes directly. If you want to do validation of values, use a property instead. So basically, none of your methods are actually necessary in good style.
However, you don't have an __init__() method. Usually you would pass the desired attributes of the instance when instantiating the class and save these on the instance.
class Student:
def __init__(self, name, id, address, cgpa):
self.name = name
self.id = id
self.address = address
self.cgpa = cgpa
herman = Student("Herman Munster", 12345, "1313 Mockingbird Lane", 4.0)
Try this:
import sys
class Student:
'''Student class'''
self.name = None
self.id = 0
self.address = None
self.cgpa = None
def get_name(self):
return self.name
def set_name(self, n):
self.name = n
def get_id(self):
return self.id
def set_id(self, i):
self.id = i
def get_address(self):
return self.address
def set_address(self, a):
self.address = a
def get_cgpa(self):
return self.cgpa
def set_cgpa(self, c):
self.cgpa = c
You need to pass self as the first argument to each member function of the class. Member variables must then be referred to with self, i.e. self.name. Furthermore, you may wish to include an __init__() function; this serves usually to initialize any member variables, and is called at the instantiation of the class.
Take a look at the Python documentation here for some examples on well-formed classes: http://docs.python.org/tutorial/classes.html#random-remarks
In Python, you need to pass in self for each of your member functions. You also need to reference class variables as self.x, if you want them to take an effect.
Here are a couple examples that you need to apply to the rest of your code.
def set_name(self, n):
self.name = n
def get_cgpa(self):
return self.cgpa
There is some explanation for why this is the case in the documentation.
This is because first argument of methods is self - the class instance.
See What is the purpose of self?
and http://docs.python.org/tutorial/classes.html#class-objects