I am a beginner in python and I am having trouble understanding classes. I have a task that requires me to create a class that should return a students information e.g. name, id, age and marks. I have made a class but am having trouble with the output and keep on getting an attribute error:
print("Student: " + self.name + " ID: " + self.ID + " Age: " + self.age + " Mark: " + self.mark)
AttributeError: 'Student' object has no attribute 'age'
I was wondering if someone could explain what I am doing wrong here as I am quite lost.
Rest of the code:
import random
class Student:
def __init__(self, name, ID):
self.name = name
self.ID = ID
def setAge(self, age):
self.age = age
self.age = random.randint(0, 100)
def setMarks(self, marks):
self.marks = marks
self.marks = random.randint(0, 100)
def Display(self):
print("Student: " + self.name + " ID: " + self.ID + " Age: " + self.age + " Mark: " + self.mark)
student = Student("John", "ID123")
student.Display()
You didn't call student.setMarks() and student.setAge() , so marks and age attributes are not created in object yet.
The solution is to call these two methods before calling student.Display()
Python objects are a container that has attributes you can set. If you don't set an attribute but try to read it, you get an AttributeError, meaning that the attribute you are looking for does not exist.
Currently, student = Student(...) calls Student.__init__, which assigns the name and ID attribute of the object. You never call student.setAge or student.setMarks, so your object's age and marks attributes are never set and can not be accessed.
It is traditional to assign default values in the __init__ method if you want to generally avoid unexpected crashes like that.
Another thing is that rather having getter and setter methods, as Java would, for example, Python encourages the use of properties. Properties are objects in the class template that can be accessed like a normal attribute, but allow you to run arbitrary code in place of the access and assignment operators.
Putting all that together, you could write something like
class Student:
def __init__(self, name, ID, age=None, marks=None):
self.name = name
self.ID = ID
self.age = random.randint(0, 100) if age is None else age
self.marks = random.randint(0, 100) if marks is None else marks
#property
def marks(self):
return self._marks
#marks.setter
def marks(self, value):
# Example of a check you could do
if not isinstance(value, int):
raise TypeError('Marks must be an integer')
In your example, you try to access the variable, before the assignment. You would actually have to call student.setAge and student.setMarks with arguments.
On the other note, in your function setAge you instantly overwrite the value, so consider removing either first or second assignment:
def setAge(self, age):
self.age = age # first assignment
self.age = random.randint(0, 100) # second assignment
The age attribute is not set because it was never assigned:
student = Student("John", "ID123")
student.setAge(30) # John is 30 years old.
student.Display()
def __init__() works like a constructor. Try to include age attribute inside the __init__() function, call setAge() from __init__(), or setAge() explicitly before calling Display().
Good luck :)
A simpler version for your code:
import random
class Student:
def __init__(self, name, ID):
self.name = name
self.ID = ID
self.age = random.randint(0, 100)
self.marks = random.randint(0, 100)
def Display(self):
print("Student: " + str(self.name) + " ID: " + str(self.ID) + " Age: " + str(self.age) + " Mark: " + str(self.marks))
student = Student("John", "ID123")
student.Display()
Related
I am playing around with classes in Python and do not understand how to add extra 'attributes'. For example my simple code that I have come up with below:
class Bird():
def __init__(self, name, age):
self.name = name
self.age=age
def birdsit(self):
print(self.name + ' is a bird that is sitting')
def birdfly(self):
print(self.name + ' is a bird that is flying')
def birdwalk(self):
print(self.name + ' is a bird that is walking')
myBird=Bird('Blue',4)
print(myBird.name)
myBird.birdsit()
myBird.birdfly()
myBird.birdwalk()
I am trying to simply add an attribute eg. the Type or Gender of the bird. I am self studying and the textbook I am using is so confusing and overwhelming and I can't really find a clear explanation.
Here you go. It's the same syntax for setting name or age. Also, watch out for your indents in the original post - the methods (i.e. def birdsit, def birdfly) all need to be indented once more than the class.
class Bird():
def __init__(self, name, age, type, gender):
self.name = name
self.age = age
self.type = type
self.gender= gender
def birdsit(self):
print(self.name + ' is a bird that is sitting')
def birdfly(self):
print(self.name + ' is a bird that is flying')
def birdwalk(self):
print(self.name + ' is a bird that is walking')
myBird = Bird('Blue', 4, 'swallow', 'do birds have genders?')
print(myBird.name, myBird.gender, myBird.type)
myBird.birdsit()
myBird.birdfly()
myBird.birdwalk()
Exactly are you trying to add? You already know how to create a new data attribute: simply assign to it. For instance, if you want a movement attribute for your bird, just do this:
def birdsit(self):
self.movement = "sit"
print(self.name + ' is a bird that is sitting')
def birdfly(self):
self.movement = "fly"
print(self.name + ' is a bird that is flying')
def birdwalk(self):
self.movement = "walk"
print(self.name + ' is a bird that is walking')
If the attribute doesn't exist, then it's created when you first hit one of these assignments. If it already exists, the assignment merely changes its value.
In this respect, it's just like a regular Python variable.
Attributes can be defined in the init() function which is automatically run when an instance of a class is created. To add a species attribute you can add it in the init function.
def __init__(self, name, age, species):
self.name = name
self.age = age
self.species = species
I'm trying to write a program where I am trying to pass **kwargs in init() method. After that
when I m trying to make a instance variable inside the constructor(init() method ) , I cant able to make . How can I do this ?
Here is my code :
class Student:
def __init__(self,**kwargs):
self.name = name
self.age = age
self.salary = salary
def show_name(self):
print("Name is : " + self.name)
def show_age(self):
print("Age is : " + str(self.age))
def show_salary(self):
print(f"Salary of {self.name} is : " + str(self.salary))
st = Student('John',25,15000)
st2 = Student('Doe',25,1500000)
st.show_salary()
st2.show_salary()
**kwargs expects arguments to be passed by keyword, not by position. Once you do that, you can access the individual kwargs like you would in any other dictionary:
class Student:
def __init__(self, **kwargs):
self.name = kwargs.get('name')
self.age = kwargs.get('age')
self.salary = kwargs.get('salary')
def show_name(self):
print("Name is : " + self.name)
def show_age(self):
print("Age is : " + str(self.age))
def show_salary(self):
print(f"Salary of {self.name} is : " + str(self.salary))
st = Student(name='John', age=25, salary=15000)
st2 = Student(name='Doe', age=25, salary=1500000)
st.show_salary()
st2.show_salary()
If you want to pass these arguments by position, you should use *args instead.
kwargs is created as a dictionary inside the scope of the function. You need to pass a keyword which uses them as keys in the dictionary. (Try running the print statement below)
class Student:
def __init__(self, **kwargs):
#print(kwargs)
self.name = kwargs["name"]
self.age = kwargs["age"]
self.salary = kwargs["salary"]
def show_name(self):
print("Name is : " + self.name)
def show_age(self):
print("Age is : " + str(self.age))
def show_salary(self):
print(f"Salary of {self.name} is : " + str(self.salary))
st = Student(name = 'John',age = 25, salary = 15000)
st2 = Student(name = 'Doe',age = 25,salary = 1500000)
st.show_salary()
st2.show_salary()
Though you can do this as some of the answers here have shown, this is not really a great idea (at least not for the code you are showing here). So I am not going to answer the subject line question you have asked, but show you what the code you seem to be trying to write should be doing (and that is not using kwargs). There are plenty of places where using kwargs is the best solution to a coding problem, but the constructor of a class is usually not one of those. This is attempting to be teaching, not preaching. I just do not want others coming along later, seeing this question and thinking this is a good idea for a constructor.
The constructor for your class, the __init__(), generally should be defining the parameters that it needs and expects to set up the class. It is unlikely that you really want it to take an arbitrary dictionary to use as its parameter list. It would be relatively rare that this is actually what you want in your constructor, especially when there is no inheritance involved that might suggest you do not know what the parameters are for some reason.
In your __init__() itself you clearly want the parameters name, age and salary, yet without them in the parameter list it is not clear to the caller that you do. Also, your usage of it does not seem to imply that is how you expect to use it. You call it like this:
st = Student('John',25,15000)
and so you do not even seem to want named parameters.
To handle the call structure you have shown the __init__() would look like this:
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
If you want to be be able to call it without some parameters such that it uses defaults for the ones left out, then it should be like this:
def __init__(self, name=None, age=None, salary=None):
self.name = name
self.age = age
self.salary = salary
It seems very unlikely that the kwargs approach is really what you want here, though obviously you can code it that way as other answers have shown.
Perhaps you are just trying to figure out how to use kwargs, and that is fine, but a different example would be better if that is the case.
I am new to python and I get stuck in this error. I want to print names and years of birth of animals in team in an order by the name. Now I am keeping getting printing years and names but without order. I wanted to use lambda but than error occures. Could you help me please?
class Animal:
def __init__(self, name):
self.name = name
class Team:
def __init__(self, name):
self.name = name
self.year_of_birth = year_of_birth
self.members = []
def add_member(self, member):
self.member = member
self.members.append(team.member)
def print_team(team):
list_members= []
for member in team.members:
list_members.append(member.name)
list_members.append(member.year_of_birth)
print('{} ({})'.format(member.name ,member.year_of_birth) )
print (list_members)
for memeber in list_members:
sorted(list_members, key = lambda member: member.name)
print (list_members)
team = Team('Wolves')
team.add_member(Animal('Josh', 2015))
team.add_member(Animal('Quinn', 2016))
team.add_member(Animal('Peter', 2010))
print_team(team)
line , in
sorted(memberlist, key = lambda member: member.name)
AttributeError: 'str' object has no attribute 'name'
Here is another possible solution:
In order to print an object of any class that you created, you must implement the __str__() method or the __repr__() method as an official string representation of your objects. So, here is the modified Animal class:
class Animal:
def __init__(self, name, year_of_birth):
self.name = name
self.year_of_birth = year_of_birth # Added this field because your created Animal objects had it in the example.
def __str__(self):
return self.name + " " + str(self.year_of_birth)
def __repr__(self):
return self.name + " " + str(self.year_of_birth)
Next thing, I simplified your add_member() method because there was no reason for self.member = member:
def add_member(self, member):
self.members.append(member)
Next, I modified your print_team() function like this:
def print_team(team):
list_members= []
for member in team.members:
list_members.append(member)
print("Unsorted: ")
print (list_members)
list_members.sort(key = lambda animal: animal.name)
print("Sorted by name: ")
print (list_members)
You can simply append any object of type Animal in the list_members list. After that, you can sort your list using sort() and then print it. The code below:
team = Team('Wolves',2015)
team.add_member(Animal('Josh',2015))
team.add_member(Animal('Quinn',2145))
team.add_member(Animal('Peter',3000))
print_team(team)
Produces the following result:
Unsorted:
[Josh 2015, Quinn 2145, Peter 3000]
Sorted by name:
[Josh 2015, Peter 3000, Quinn 2145]
I have this code that stores a person's name, age and funds. I am trying to write a method that can take "age" or "funds", along with a number, and increase the given attribute by that number.
class Actor:
def __init__(self, name, age, funds):
self.name
self.age = age
self.funds = funds
def increase_age(self, increase_amount=1):
self.age = self.age + increase_amount
def increase_attrib(self, attrib, increase_amount=1):
self.attrib = self.attrib + increase_amount
a = Actor("Andrea", 32, 10000)
a.increase_age() works fine: calling it increases the age of Andrea to 33, just as expected. However, a.increase_attrib("age") gives an error, saying AttributeError: 'Actor' object has no attribute 'attrib'. a.increase_attrib("funds") gives similar results.
If I just say a.increase_attrib(age) (without the quotes) I get a NameError, which is what I expected.
By my understanding, giving the parameter "age" to increase_attrib() should mean that the attrib mentioned becomes age, so that increase_attrib() references self.age instead of self.attrib. Apparently, I was wrong.
Now, I could just use increase_age() instead, but then I'd have to make different methods for age and funds, and even more methods once I add other features to Actor, like location, gender, and nationality.
What do I need to do so that I can pass the name of an attribute to a method and have it change that attribute?
You are looking for setattr:
setattr(obj, 'foo', 42)
Is the same as
obj.foo = 42
So for your example:
def increase_attrib(self, attrib, increase_amount=1):
setattr(self, attrib, getattr(self, attrib, 0) + increase_amount)
I am new to Python, and am trying to figure out how to access the global variable count within the repr method in the Student class below:
class Student(object):
count = 0
def __init__(self, **kwargs):
self.name = kwargs.get("name")
self.age = kwargs.get("age")
Student.count += 1
def __repr__(self):
try:
return "name: %s, age: %d" % (self.name, self.age)
except TypeError:
print "student number: %d" % (Student.count)
When I create an instance, such as student = Student, and the try to print the variable student, I get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "school.py", line 23, in __repr__
print "student number: %d" % (Student.count)
NameError: global name 'count' is not defined
Thanks.
You can access class properties as well using self. Not that in your case, your error handling in __repr__ isn’t necessary. In a method, self will always be correct (unless you really mess something up), so you can just assume that you can access self properly. As you initialize name and age in the initializator, you can also assume that both properties exist:
class Student (object):
count = 0
def __init__ (self, **kwargs):
self.name = kwargs['name']
self.age = kwargs['age']
self.count += 1
def __repr__ (self):
return "name: %s, age: %d" % (self.name, self.age)
Instead of accepting just **kwargs, it might be a good idea to actually ask for name and age as proper parameter in the initializator. Since you do expect name and age to be specified, incorrectly calling your constructor will fail early that way:
def __init__ (self, name, age, **kwargs): # **kwargs in case you want to accept more
self.name = name
self.age = age
self.count += 1
That all being said, the error you show shouldn’t happen. There shouldn’t be an exception being thrown in __repr__, and Student.count should be accessible as well. So you are probably calling __repr__ in some weird way. The proper way would be something like this:
a = Student(name='Peter', age=15)
print(repr(a))
You should use self.count instead of Student.count inside the class. You do not need to use Student.count because you are still inside the class, self refers to anything inside the class. It doesn’t need to be inside the __init__ function. For example:
class RandomClass:
random_var = 0
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
another_var = 3
def __str__(self):
print(“Printing variables: %d and %d” % (self.random_var, self.another_var))#using self.random_var, not RandomClass.random_var