Attribute Error in python, object has no attribute - python-3.x

I am new to inheritance in classes and for some reason, the attributes in this code don't seem to be sharing correctly. I'm not sure what the issue is.
class Person:
def __init__(self, name, age, occupation):
self.name = name
self.age = age
self.occupation = occupation
def say_hello(self):
print(f"Hello, my name is {self.name}.")
def say_age(self):
print(f"I am {self.age} years old.")
class Superhero(Person):
def __init__(self, name, age, occupation, secret_identity, nemesis):
self.secret_identity = secret_identity
self.nemesis = nemesis
hero = Superhero("Spider-Man", 17, "student", "Peter Parker", "Green Goblin")
print(hero.name())

It looks like you're not calling the super constructor in your Superhero class.
You should do as follow:
class Superhero(Person):
def __init__(self, name, age, occupation, secret_identity, nemesis):
super().__init__(name, age, occupation)
self.secret_identity = secret_identity
self.nemesis = nemesis
BTW: you didn't define a function named name. If you want to print the name you should remove the (), e.g print(hero.name)

Related

How to remove an object from list by a value

My problem is that I created a list of students with name and number. The task is now to remove a student by his number. My problem is that my code doesn't work.
Another problem is that it always shows the memory address instead of the value of the object.
Thanks in advance
class Student:
def __init__(self, name, number):
self.name = name
self.number = number
from .student import Student
class Course:
def __init__(self, name, code, credit, student_limit):
self.name = name
self.code = code
self.credit = credit
self.student_limit = student_limit
students = []
def add_student(self, new_student):
self.student = new_student
self.students.append(new_student)
print("Student added" +str(self.students))
def remove_student_by_number(self, student_number):
self.student_number = student_number
if student_number in self.students: self.students.remove(student_number)
print("Student removed" + str(self.students))
from .course import Course
class Department:
def __init__(self, name, code):
self.name = name
self.code = code
courses = []
def add_course(self, course):
self.course = course
self.courses.append(course)
print("Course added" +str(self.courses))
from python import *
def main():
alice = Student("Alice", 1336)
bob = Student("Bob", 1337)
math_dept = Department("Mathematics and Applied Mathematics", "MAM")
math_course = Course("Mathematics 1000", "MAM1000W", 1, 10)
math_dept.add_course(math_course)
math_course.add_student(bob)
math_course.add_student(alice)
math_course.remove_student_by_number(alice.number)
if __name__ == "__main__":
main()
self.students is a list of Student instance so it will print the instance's memory address if the method __str__ is not implemented (see here for example). You should try to print each property like student.name or student.number explicitly.
Anyway you are trying to find student_number in list of Student so of course it will never run the remove line. Instead use if student_number in [student.number for student in self.students] which is looking up the student's number list, not the student list itself. However in this case, you also want to remove the student with the student_number as the input so you may need to use a loop like this:
def remove_student_by_number(self, student_number):
for student in self.students:
if student.number == student_number:
print("Student removed" + str(student.name))
self.students.remove(student)
break

Is there a way to dynamically sort variables into classes?

I have these two Classes: "Employee" - the superclass and "Salesman" - a subclasss of "Employee".
And I have eric = ('Eric', 19, 'Salesman', 1700).
Can i use a function to check if Eric is a Salesman and dynamically assign him to either the "Employee" superclass or the "Salesman" subclass?
And how should I go about writing that?
I hope, my description of the problem wasn't too confusing.
class Employee():
'''the employee superclass'''
def __init__(self, name, age, occupation, monthly_pay):
self.isemployee = True
self.name = name
self.age = age
self.occ = occupation
self.pay = monthly_pay
class Salesman(Employee):
'''the Salesman subclass'''
def __init__(self):
self.issalesman = True
After some trial and error, and rewriting, this is what I came up with:
class Employee():
'''The employee superclass'''
def __init__(self, name, age, occupation, monthly_pay):
self.name = name
self.age = age
self.occ = occupation
self.pay = monthly_pay
class Salesman(Employee):
'''The Salesman subclass'''
def issalesman(self):
self.issalesman = True
def class_assigner(person):
if person[2] == 'Salesman':
person = Salesman(person[0], person[1], person[2], person[3])
else:
person = Employee(person[0], person[1], person[2], person[3])
return person
print(class_assigner(eric).occ)
Output:
Salesman
Is this a viable method, or will i run into problems later, if I, say for example start importing employee - data from a .txt or .csv file?

How to extend base class to child class in python and printing child class value?

when i try to extend base class to child class it doesn't work properly
it shows error
b1 = B("adnan", 25, "male")
TypeError: object() takes no parameters
here is my code :
class A:
def letter(self,name,age):
self.name=name
self.age=age
class B(A):
def farhan(self,gender):
self.gender=gender
b1=B("adnan",25,"male")
print(b1.name,b1.age,b1.gender)
None of your classes have an __init__ method, which is used to initialise the class. When you do: B("adnan",25,"male"), it's translated to a call to B.__init__:
B.__init__(<object of type B>, "adnan", 25, "male")
The default implementation of __init__ supplied by the class object takes no parameters, which is exactly what the error is saying. A inherits from object (issubclass(B, object) == True), so its default __init__ method is the same as that of object.
You can try this:
class A:
def __init__(self, name, age):
self.name=name
self.age=age
class B(A):
def __init__(self, name, age, gender):
super().__init__(name, age) # initialise parent
self.gender = gender
When you write something like
b1 = B("adnan", 25, "male")
You are creating a new instance of the class 'B'. When you do that, you're calling the __init__ method of that class. A possible solution would be in the lines of:
class B(A):
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
You need to brush up your Python OOP skills! A nice source is https://realpython.com/python3-object-oriented-programming/

How to access/override defaults on parent's attribute in SQL Alchemy?

I have the following classes: Item, StoneSword, IronSword, Apple, Steak
Item is the parent class, and the Swords and food inherit the Item class. I want to have a bunch of different functions and descriptions for each of these classes.
I completely understand the function side of things, but I am struggling to figure out how to override the default description with the children classes.
I am currently using single table inheritance with SQLAlchemy.
Credit goes to Mike Bayer for helping me figure out how to override __init__() to suit my needs. If anybody can find a more elegant solution, I will be glad to accept that answer instead.
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String, default="User")
fullname = Column(String)
email = Column(String)
type = Column(String)
__mapper_args__ = {
'polymorphic_on': type,
'polymorphic_identity': 'user'
}
def __init__(self, **kwargs):
super().__init__(**kwargs)
def __repr__(self):
return f"<User(id={self.id}, name='{self.name}', fullname='{self.fullname}', email='{self.email}')>"
def is_admin(self):
print(f"I, {self.name}, am NOT an admin")
class Admin(User):
def __init__(self, **kwargs):
kwargs.setdefault("name", "Admin")
super().__init__(**kwargs)
__mapper_args__ = {
'polymorphic_identity': 'admin'
}

Why do i get a type error when using super()?

I just started learning about classes and inheritance in Python 3. I want to print the name of a student, which is inherited from the superclass Person. Unfortunately I keep getting a TypError.
code:
class Person(object):
def __init__(self, name="Mike", age = 25, place_of_birth="Stockholm"):
self.age = age
self.name = name
self.place_of_birth = place_of_birth
class Student(Person):
def __init__(self, name, age, university = "University of Stockholm", gpa = 8):
super().__init__(name, age)
self.university = university
self.gpa = gpa
I then like to print the name of the student by calling:
student1 = Student()
print(student1.name)
But I keep getting this error message:
Traceback (most recent call last):
TypeError: init() missing 2 required positional arguments: 'name' and 'age'
If you want Student to always default to the name and age of the Parent class then you don't want Student to take a name and age value.
class Student(Person):
def __init__(self, university = "University of Stockholm", gpa = 8):
super().__init__() # runs parent __init__ taking no values
self.university = university
self.gpa = gpa
>>> student1 = Student()
>>> student1.name
'Mike'
>>> student1.age
25
When you use super().__init__(name, age) you are wanting to pass the name and age given to the Student class to the Parent class. But since you don't want to pass anything it is getting errors.
Now, if you want the Student class to be able to take values as well as default to the ones provided by the parent class you can do this.
class Student(Person):
def __init__(self, name = None, age = None, university = "University of Stockholm", gpa = 8):
if name is None and age is None:
super().__init__()
else:
super().__init__(name, age)
self.university = university
self.gpa = gpa
What happens here is if no name or age is provided if name is None and age is None then it defaults to the values from Person class. However if both the name and age are provided, then it will use those values.
>>> student1 = Student()
>>> student1.name
'Mike'
>>> student1.age
25
>>> student2 = Student('Bill', 19)
>>> student2.name
'Bill'
>>> student2.age
19
The __init__() method of Student takes 2 positional arguments: name and age. You need to specify those arguments when creating a new instance:
student1 = Student('eppe2000', 20)
print(student1.name)
If you instead want the class Student to default to class Person default arguments, in case they have not been specified, you can do it like this:
class Person(object):
def __init__(self, name="Mike", age=25, place_of_birth="Stockholm"):
self.age = age
self.name = name
self.place_of_birth = place_of_birth
class Student(Person):
def __init__(self, university="University of Stockholm", gpa=8, **kwargs):
super().__init__(**kwargs)
self.university = university
self.gpa = gpa
>>> s = Student()
>>> s.name
'Mike'
>>> s = Student(name="Daniele")
>>> s.name
'Daniele'
Basically you forward all the keywords arguments that are unknown to the class Student to its parent class. Not that if you specify an invalid keyword (i.e: 'surname') you will get a TypeError because neither Student or Person specify a keyword argument with key 'surname'.
If you need info about **kwargs check this post: https://stackoverflow.com/a/36908/3477005

Resources