Python 3 OOP - where does "super().__init__()" go exactly? - python

I am trying to make my sub-class work, but something is wrong with the inheritance. The number of args passed in should be 5: name, age, gender, title & salary
However, Python is saying
TypeError: __init__() takes 4 positional arguments but 6 were given
and I don't know why or how to fix it. Here is my code:
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Employee(Person):
def emp_function(self, title, salary):
self.title = title
self.salary = salary
super().__init__()
#Is this wrong? Where should this 'super()' go?
George = Employee("George", 30, "male", "Manager", 50000)

super().__init__() should be in def __init__ of Employee class
You need to create constructor for Employee class too.
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Employee(Person):
def __init__(self,name,age,gender,title,salary):
self.title = title
self.salary = salary
super().__init__(name, age, gender)
George = Employee("George", 30, "male", "Manager", 50000)

Related

How to create instance of multiple inherited class?

I have this code:
class Person:
def __init__(self, name, last_name, age):
self.name = name
self.last_name = last_name
self.age = age
class Student(Person):
def __init__(self, name, last_name, age, indexNr, notes):
super().__init__(name, last_name, age)
self.indexNr = indexNr
self.notes = notes
class Employee(Person):
def __init__(self, name, last_name, age, salary, position):
super().__init__(name, last_name, age)
self.salary = salary
self.position = position
class WorkingStudent(Student, Employee):
def __init__(self, name, last_name, age, indexNr, notes, salary, position):
Student.__init__(name, last_name, age, indexNr, notes)
Employee.__init__(name, last_name, age, salary, position)
I want to create a WorkingStudent instance like this:
ws = WorkingStudent("john", "brown", 18, 1, [1,2,3], 1000, 'Programmer')
but it's not working, I get this error:
TypeError: __init__() missing 1 required positional argument: 'notes'
Or what I am doing wrong here? Also, I have already tried super() in WorkingStudent class but it calls only the constructor of the first passed class. i.e in this case Student
Note: I have already gone through multiple StackOverflow queries but I couldn't find anything that could answer this. (or maybe I have missed).
Instead of explicit classes, use super() to pass arguments along the mro:
class Person:
def __init__(self, name, last_name, age):
self.name = name
self.last_name = last_name
self.age = age
class Student(Person):
def __init__(self, name, last_name, age, indexNr, notes, salary, position):
# since Employee comes after Student in the mro, pass its arguments using super
super().__init__(name, last_name, age, salary, position)
self.indexNr = indexNr
self.notes = notes
class Employee(Person):
def __init__(self, name, last_name, age, salary, position):
super().__init__(name, last_name, age)
self.salary = salary
self.position = position
class WorkingStudent(Student, Employee):
def __init__(self, name, last_name, age, indexNr, notes, salary, position):
# pass all arguments along the mro
super().__init__(name, last_name, age, indexNr, notes, salary, position)
# uses positional arguments
ws = WorkingStudent("john", "brown", 18, 1, [1,2,3], 1000, 'Programmer')
# then you can print stuff like
print(f"My name is {ws.name} {ws.last_name}. I'm a {ws.position} and I'm {ws.age} years old.")
# My name is john brown. I'm a Programmer and I'm 18 years old.
Check mro:
WorkingStudent.__mro__
(__main__.WorkingStudent,
__main__.Student,
__main__.Employee,
__main__.Person,
object)
When you create an instance of WorkingStudent, it's better if you pass keyword arguments so that you don't have to worry about messing up the order of arguments.
Since WorkingStudent defers the definition of attributes to parent classes, immediately pass all arguments up the hierarchy using super().__init__(**kwargs) since a child class doesn't need to know about the parameters it doesn't handle. The first parent class is Student, so self.IndexNr etc are defined there. The next parent class in the mro is Employee, so from Student, pass the remaining keyword arguments to it, using super().__init__(**kwargs) yet again. From Employee, define the attributes defined there and pass the rest along the mro (to Person) via super().__init__(**kwargs) yet again.
class Person:
def __init__(self, name, last_name, age):
self.name = name
self.last_name = last_name
self.age = age
class Student(Person):
def __init__(self, indexNr, notes, **kwargs):
# since Employee comes after Student in the mro, pass its arguments using super
super().__init__(**kwargs)
self.indexNr = indexNr
self.notes = notes
class Employee(Person):
def __init__(self, salary, position, **kwargs):
super().__init__(**kwargs)
self.salary = salary
self.position = position
class WorkingStudent(Student, Employee):
def __init__(self, **kwargs):
# pass all arguments along the mro
super().__init__(**kwargs)
# keyword arguments (not positional arguments like the case above)
ws = WorkingStudent(name="john", last_name="brown", age=18, indexNr=1, notes=[1,2,3], salary=1000, position='Programmer')
Problem: we have a lot of arguments for our most derived class, that need to be used to initialize all the bases. However, in Python's multiple inheritance system with super(), the class that will be initialized next depends on an MRO (method resolution order) that may have been determined in another class. Therefore, when we use multiple inheritance, we don't know which class will have its __init__ called when we use super().
Solution: use consistent names for the parameters, and then take advantage of **kwargs, so that each class takes in the (explicitly named) parameters it cares about, and forwards the rest.
That looks like:
class Person:
def __init__(self, name, last_name, age):
self.name = name
self.last_name = last_name
self.age = age
class Student(Person):
def __init__(self, indexNr, notes, **kwargs):
super().__init__(**kwargs)
self.indexNr = indexNr
self.notes = notes
class Employee(Person):
def __init__(self, salary, position, **kwargs):
super().__init__(**kwargs)
self.salary = salary
self.position = position
class WorkingStudent(Student, Employee):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Forcing the client code to use keyword arguments is more work for the clients, but it also helps guard against errors from mistaking the order of positional arguments.
This is the easiest way to reach your goal.
If your WorkingStudent class inherite Student and Employee class like this ,
class WorkingStudent(Student, Employee):
def __init__(self, name, last_name, age, indexNr, notes, salary, position):
Student.__init__(self, name, last_name, age, indexNr, notes)
Employee.__init__(self, name, last_name, age, salary, position)
ws = WorkingStudent("john", "brown", 18, 1, [1, 2, 3], 1000, 'Programmer')
print(ws)
print(ws.name)
print(ws.age)
your output will be...
Output:
<main.WorkingStudent object at 0x7fc6c4d8ba10>
john
18
[1, 2, 3]

How to get the value of an instance stored in a list

I want to know how to get all the values ​​of student0 instance without using the print(student0.name, student0. age) method when I have the code below.
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
student0 = Student("Lee", "22")
student1 = Student("Kim", "23")
You can use the following code :
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return "% s % s" % (self.name, self.age)
student0 = Student("Lee", "22")
student1 = Student("Kim", "23")
print(student0)

How would I print "bark" using python classes in this situation?

How would I print "bark" using python classes.
class pet:
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self):
return self.name
def get_age(self):
return self.age
class dog(pet):
def __init__(self, name, age):
super().__init__(name, age)
def bark(self):
print("bark")
max = pet("max", 5)
max.dog.bark()
To call the dog class's bark method, you need an instance of dog.
max = dog("max", 5)
max.bark()
Here you go.
class pet:
def __init__(self, name, age):
self.name = name
self.age = age
def get_name(self):
return self.name
def get_age(self):
return self.age
class dog(pet):
def __init__(self, name, age):
super().__init__(name, age)
def bark(self):
print("bark")
my_pet = dog("max",3)
my_pet.bark()

Simple Python Class Not Displaying/Printing Anything

I am trying to create this class that would display an Employee's name and his yearly salary. Everything seems to be working and I haven't encountered any errors, but when I run the program, nothing is printed.
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def Func(self):
print("Employee name is" + self.name)
employee1 = Employee("Adam Smith", "$47,000")
print(employee1.salary)
What am I doing wrong?
It is a indentation error, Use :
class Employee:
# Error is here
def __init__(self, name, salary):
self.name = name
self.salary = salary
def Func(self):
print("Employee name is" + self.name)
employee1 = Employee("Adam Smith", "$47,000")
print(employee1.salary)

Trying to create a object from a class by calling a function

I am working on a project that I need to create some objects dynamically from a class. I am not asking for anyone to solve it but just point me in the right direction. An example would be if I was working with Dogs.
class Dog(object):
"""Creating Dogs"""
def __init__(self, name, age, gender):
super(Dog, self).__init__()
self.name = name
self.name = age
self.name = gender
I would like however to have a function that I can pass this information into that would create a global object. The function would look like this:
def create_dog(name, age, gender):
name = Dog(name,age, gender)
return(name)
So theoretically if I passed the name "Jack" to the function I would have a object globally called "Jack" from the class. I am just trying to find a good way to do this if any. If this is completely against python I will figure out another way but I am sitting here stuck. I have also thought about nesting the class within my function but the namespace won't go into global.
you could create a global dictionary
dogs = {}
def create_dog(name, age, gender):
# maybe check if already exists
dogs[name] = Dog(name, age, gender)
With changing locals: (which is still bad, but not as much as changing globals)
def create_dog(name, age, gender, locals_=locals()):
dog = Dog(name, age, gender)
locals_[name] = dog
create_dog("jack", 3, "male")
print(jack)
Maybe you want to make an alternative constructor ?
class Dog(object):
"""Creating Dogs"""
def __init__(self, name, age, gender):
super(Dog, self).__init__()
self.name = name
self.name = age
self.name = gender
#classmethod
def create_dog(name, age, gender):
name = Dog(name,age, gender)
return name
See also discussion Meaning of #classmethod and #staticmethod for beginner?
A global dictionary is fine if you use a single file script, but for a more complex software you'll have to import all the 3 elements:
from dogs import dogs, create_dog, Dog
With class attribute you import just one name space. So you could do this:
class Dog(object):
"""Creating Dogs"""
members = []
def __init__(self, name, age, gender):
super(Dog, self).__init__()
self.name = name
self.name = age
self.name = gender
#classmethod
def create_dog(name, age, gender):
name = Dog(name,age, gender)
Dog.members.append(name)
return name
Now you can simply import Dog, and access the class attribute Dog.members

Categories

Resources