Initialise child class with instance of parent class - python

Suppose I have a class:
class Person(object):
def __init__(self, name, hobbies):
self.name = name
self.hobbies = hobbies
... (and so on)
Now I want to initialise a child class, Employee, which extends person. I would like to initialise that class with an instance of the Person class. So I would like to do:
class Employee(Person):
def __init__(self, person, salary):
# Initialise the superclass from the given instance somehow
# I know I could do:
super(Employee, self).__init__(person.name, person.hobbies)
# But could I somehow do something like:
super(Employee, self).__init__(person)
# (In this case the difference is small, but it could
# be important in other cases)
# Add fields specific to an "Employee"
self.salary = salary
So that I can then call:
p1 = Person('Bob', ['Bowling', 'Skiing'])
employed_p1 = Employee(p1, 1000)
Is there any way I can do this, or do I explicitly have to call the parent class's constructor again?
Thanks a lot!

I thnk you want something like this:
class Person(object):
def __init__(self, name, hobbies):
self.name = name
self.hobbies = hobbies
def display(self):
print(self.name+' '+self.hobbies[0])
class Employee(Person):
def __init__(self, a, b =None,salary=None):
if b is None:
self.person = a
else:
self.person = Person(a,b)
self.name = self.person.name
self.hobbies = self.person.hobbies
self.salary = salary
bob = Employee('bob',['Bowling', 'Skiing'])
bob.display()
sue1 = Person('sue',['photography','music'])
sue2 = Employee(sue1,salary=123)
sue2.display()
I've added in the 'display' function just to make it easier to follow. Hope this helps.

Related

What's the point of method inheritance and calling Parent.method()?

I came across this example of method inheritance:
The child Manager class inherits from the parent Employee class, and modifies its give_raise() method, while also calling Employee.give_raise() in the new implementation.
# Parent class
class Employee:
def __init__(self, name, salary=30000):
self.name = name
self.salary = salary
def give_raise(self, amount):
self.salary += amount
# Child class
class Manager(Employee):
def display(self):
print("Manager ", self.name)
def __init__(self, name, salary=50000, project=None):
Employee.__init__(self, name, salary)
self.project = project
# Modify the give_raise method
def give_raise(self, amount, bonus=1.05):
new_amount = amount * bonus
# Call the parent method
Employee.give_raise(self, new_amount)
mngr = Manager("John Smith", 80000)
mngr.give_raise(5000)
print(mngr.salary)
My question is: isn't this a bit convoluted?
I get class inheritance. But calling a parent method within a child method of the same name?
Wouldn't it be better to write give_raise() in the Manager class as:
def give_raise(self, amount, bonus):
new_amount = amount * bonus
self.salary += amount
To me, it only makes sense to call Parent.method() if it's a completely different method that requires a lot of lines of code
I agree with you initial question in that the implementations are a bit convoluted and don't help to clearly convey the intended usage. The main goal of method inheritance is to encourage reusable, encapsulated behavior within the class hierarchy. That way the derived class could add some functionality or override the underlying functionality (or leave it be and add other functionality).
Parent.give_raise could be defined in a way that doesn't require it to be overriden in order to customize what raise different employee types get.
For example,
class Employee:
default_salary = 30000
def __init__(self, name, salary=None, bonus=1, **kwargs):
super().__init__(**kwargs)
if salary is None:
salary = self.default_salary
self.name = name
self.salary = salary
self.bonus_multiplier = bonus
def give_raise(self, amount):
self.salary += amount * self.bonus_multiplier
class Manager(Employee):
default_salary = 50000
def display(self):
print("Manager ", self.name)
def __init__(self, *, project=None, **kwargs):
if 'bonus' not in kwargs:
kwargs['bonus'] = 1.05
super.__init__(**kwargs)
self.project = project
mngr = Manager(name="John Smith", salary=80000)
mngr.give_raise(5000)
print(mngr.salary)

Change a inherited class to another inherited class keeping the attributes

I need to change a inherited class to another inherited class where only one of the attributes has changed
i need to "Promote" a Cashier to a Manager, the only thing that is suppose to change is the salary
both Cashier and Manager are inherited classes of Employee (where I'm not sure if I'm using the "hasattr" function the right way)
class Employee:
def __init__(self,name):
self.name=name
if(hasattr(self,'shifts')==False):
self.shifts=[]
class Manager(Employee):
def __init__(self,name,salary):
Employee.__init__(self,name)
self.salary=salary
class Cashier(Employee):
def __init__(self,name,salarey_per_hours):
Employee.__init__(self,name)
self.salery_per_hours=salarey_per_hours
def promote(self,salary):
return Manager(self.name,salary)
P.s It's my first time uploading a question
What you could do is create the addition method of your class and add self to the manager class you are returning like so:
class Employee(object):
def __init__(self, name):
self.name=name
if not hasattr(self, 'shifts'):
self.shifts = []
def __add__(self, other):
if isinstance(other, Employee):
for key, value in other.__dict__.items():
if key == 'salary':
continue
self.__setattr__(key, value)
return self
class Manager(Employee):
def __init__(self, name, salary):
super().__init__(name)
self.salary = salary
class Cashier(Employee):
def __init__(self,name,salary):
super().__init__(name)
self.salary = salary
def promote(self, salary):
manager = Manager(self.name, salary)
manager += self
return manager
cashier = Cashier('hank', 22)
cashier.shifts = [1, 2, 3, 4]
print(cashier.shifts)
promoted_cashier = cashier.promote(30)
print(promoted_cashier.shifts)
Here you make sure that everything except the "salary" is transferred to the promoted class. And since both the Manager and the Cashier are an Employee this should work nicely. I changed your code a bit to what I'm used to since there was some unusual coding with you Calling Employee in the init which I assumed you did not explicitly needed. Sorry if that was not the case.
You can change the object's class by obj.__class__ to the another class by
doing obj.__class__ = SomeClass
Beware that is can lead to strange behaviours if it is handled incorrectly.
by modifying your code
class Employee:
def __init__(self,name):
self.name=name
if(hasattr(self,'shifts')==False):
self.shifts=[]
class Manager(Employee):
def __init__(self,name,salary):
Employee.__init__(self,name)
self.salary=salary
class Cashier(Employee):
def __init__(self,name,salarey_per_hours):
Employee.__init__(self,name)
self.salery_per_hours=salarey_per_hours
def promote(self,salary):
self.__class__ = Manager
# return Manager(self.name,salary)
You can also take a look at this post changing the class of a python object (casting)

Python: How to declare an object of class from another object which is also variable in this class?

class Apple:
def print_my_tree_name(self):
print('I want to use name of Tree on which I\'m hanging')
class Tree:
def __init__(self, name):
self.name = name
self.apple = Apple()
a = Tree('test')
a.apple.print_my_tree_name()
Is it possible to access the name variable without passing self to the Apple class e.g. a.apple.print_my_tree_name()?
You can specify the name of the tree as an attribute of the apple in the tree constructor
class Apple:
def print_my_tree_name(self):
print('I am hanging on tree: %s'%self.tree_name)
class Tree:
def __init__(self, name):
self.name = name
self.apple = Apple()
self.apple.tree_name = name
a = Tree('test')
a.apple.print_my_tree_name()
Perhaps something like this, using a #staticmethod
class Tree:
def __init__(self, name):
self.name = name
self.apple = Apple()
class Apple():
#staticmethod
def print_my_tree_name():
print(f'Hanging on {a.name} tree.')
a = Tree('test')
a.apple.print_my_tree_name()
# Hanging on test tree.
I am not sure why you want to access name in Apple class but if I had to do this, I will implement it something as below
class Tree:
def __init__(self, name):
self.name = name
class Apple:
def __init__(self, name):
self.tree = Tree(name)
def print_my_tree_name(self):
print('I want to use %s'%self.tree.name)
a = Tree('test')
a.print_my_tree_name()
See composition in python that is what you need basically.
http://blog.thedigitalcatonline.com/blog/2014/08/20/python-3-oop-part-3-delegation-composition-and-inheritance/

Mutable variable in a class

If I have a class like this.
class Person():
def __init__(self, name):
self._name = name
self._name_list = []
if(self._name not in self._name_list):
self._name_list.append(self._name)
father = Person("Michael")
mother = Person("Sharon")
>>>self._name_list
["Michael", "Sharon"]
How can I do this without creating a global variable? Everytime I instantiate a new person it creates their own list. But I need a list inside the scope of the class that appends a name everytime a new person is created.
You can save it inside the class itself, like this:
class Person():
_name_list = []
def __init__(self, name):
self._name = name
if self._name not in self._name_list:
self._name_list.append(self._name)
father = Person("Michael")
mother = Person("Sharon")
print(Person._name_list)
outputs:
['Michael', 'Sharon']
You can try this:
people = []
class Person():
def __init__(self, name):
self._name = name
if self._name not in people:
global people
people.append(self._name)
person = Person('name1')
person1 = Person('name2')
print(people)
Output:
['name1', 'name2']

Subclass not inheriting parent class

I'm having trouble with my code. I'm trying to create a subclass which inherits the parent class's attributes and methods but it doesn't work. Here's what I have so far:
class Employee(object):
def __init__(self, emp, name, seat):
self.emp = emp
self.name = name
self.seat = seat
Something is wrong with the block of code below - the subclass.
Do I have to create the __init__ again? And how do I create a new attribute for the subclass. From reading questions, it sounds like __init__ in the subclass will override the parent class - is that true if I call it to define another attribute?
class Manager(Employee):
def __init__(self, reports):
self.reports = reports
reports = []
reports.append(self.name) #getting an error that name isn't an attribute. Why?
def totalreports(self):
return reports
I want the names from the Employee class to be in the reports list.
For example, if I have:
emp_1 = Employee('345', 'Big Bird', '22 A')
emp_2 = Employee('234', 'Bert Ernie', '21 B')
mgr_3 = Manager('212', 'Count Dracula', '10 C')
print mgr_3.totalreports()
I want reports = ['Big Bird', 'Bert Ernie'] but it doesn't work
You never called the parent class's __init__ function, which is where those attributes are defined:
class Manager(Employee):
def __init__(self, reports):
super(Manager, self).__init__()
self.reports = reports
To do this, you'd have to modify the Employee class's __init__ function and give the parameters default values:
class Employee(object):
def __init__(self, emp=None, name=None, seat=None):
self.emp = emp
self.name = name
self.seat = seat
Also, this code will not work at all:
def totalreports(self):
return reports
reports's scope is only within the __init__ function, so it will be undefined. You'd have to use self.reports instead of reports.
As for your final question, your structure won't really allow you to do this nicely. I would create a third class to handle employees and managers:
class Business(object):
def __init__(self, name):
self.name = name
self.employees = []
self.managers = []
def employee_names(self);
return [employee.name for employee in self.employees]
You'd have to add employees to the business by appending them to the appropriate list objects.
You need to run the superclass's init() in the appropriate place, plus capture the (unknown to the subclass) arguments and pass them up:
class Manager(Employee):
def __init__(self, reports, *args, **kwargs):
self.reports = reports
reports = []
super(Manager, self).__init__(*args, **kwargs)
reports.append(self.name) #getting an error that name isn't an attribute. Why?

Categories