How to call attribute from parent class? - python

I am currently learning how to program in Python I am stuck calling an attribute from a Parent class. In the example below, how can I call the attribute "name" on "daisy" to print the name. I always get an error "'Mammal' object has no attribute 'name'.
class Vertebrate:
spinal_cord = True
def __init__(self, name):
self.name = name
class Mammal(Vertebrate):
def __init__(self, name, animal_type):
self.animal_type = animal_type
self.temperature_regulation = True
daisy = Mammal('Daisy', 'dog')
print(daisy.name)
here I want to print the name which has been defined in the Vertebrate class, but I always get an error
"'Mammal' object has no attribute 'name'"

You need to call super in the __init__ of Mammal, like this:
class Mammal(Vertebrate):
def __init__(self, name, animal_type):
super().__init__(name)
self.animal_type = animal_type
self.temperature_regulation = True
When __init__ of Mammal is called, it doesn't automatically call the __init__ of it's parent class, that's what super does here.

When you assign an init function to the child class, it overrides the default init function of parent class being called. In such a case you need to explicitly call the parent class using the super function. You also need to assign the class Vertebrate to be a child of the class Object to be able to access all of the object's modules within it.
class Vertebrate(object):
def __init__(self, name):
self.name = name
spinal_cord = True
class Mammal(Vertebrate):
def __init__(self, name, animal_type):
super(Mammal, self).__init__(name)
self.animal_type = animal_type
self.temperature_regulation = True
animal = Mammal("Daisy", "dog")
print animal.name

Related

Set and call object instance in Python

Not sure what I am doing wrong here when trying to initiate instance of object and set a name to the instance...
class Person:
def Person(self, name):
def __init__(self, name):
self.name = name
m = Person.Person('James')
m.name
Any help with an explanation?
I've personally not encountered a situation where the init function is nested beneath a parent function...
The problem here is correlated to the function definition. Basically, you are calling Person function that define but doesn't call the init one. So, you can solve like that:
class Person:
def __init__(self, name):
self.name = name
m = Person('James')
m.name

Resolving Diamond Inheritance within Python Classes

Consider the following python code:
class Parent(object):
def __init__(self, name, serial_number):
self.name = name
self.serial_number = serial_number
class ChildA(Parent):
def __init__(self, name, serial_number):
self.name = name
self.serial_number = serial_number
super(ChildA, self).__init__(name = self.name, serial_number = self.serial_number)
def speak(self):
print("I am from Child A")
class ChildB(Parent):
def __init__(self, name, serial_number):
self.name = name
self.serial_number = serial_number
super(ChildB, self).__init__(name = self.name, serial_number = self.serial_number)
def speak(self):
print("I am from Child B")
class GrandChild(ChildA, ChildB):
def __init__(self, a_name, b_name, a_serial_number, b_serial_number):
self.a_name = a_name
self.b_name = b_name
self.a_serial_number = a_serial_number
self.b_serial_number = b_serial_number
super(GrandChild, self).__init_( something )
When running the super function in GrandChild, what is the proper way to format the __init__ arguments so that ChildA and ChildB both get the correct arguments?
Also how do you access the two different versions of the speak method (ChildA's version and ChildB's version) from within the GrandChild class?
so, when you call super from the grandchild, ChildA's __init__ method will be called because super follows the __mro__ property (parents left to right then grandparents left-to-right, then great grandparents, ...)
Since ChildA's init also calls super, then all the super calls will be chained, calling child b's __init__ and eventually the parent init.
For that to work, your interface generally needs to be consistent. That is positional arguments need to mean the same things, and be in the order.
In situations where that's not the case, keyword arguments may work better.
class Parent:
def __init__(self, name, serial, **kwargs):
self.name = name
self.serial = serial
class ChildA(Parent):
def __init__(self, a_name, a_serial, **kwargs):
self.a_name = a_name
self.a_serial = a_serial
super().__init__(**kwargs)
class ChildB(Parent):
def __init__(self, b_name, b_serial, **kwargs):
self.b_name = b_name
self.b_serial = b_serial
super().__init__(**kwargs)
class GrandChild(ChildA, ChildB):
def __init__(self):
super().__init__(name = "blah", a_name = "a blah", b_name = "b blah", a_serial = 99, b_serial = 99, serial = 30)
Also note that in your code name and serial are reused as instance properties between all the classes and that's probably not what you want.
In python, you can explicitly call a particular method on (one of) your parent class(es):
ChildA.__init__(self, a_name, a_serial)
ChildB.__init__(self, b_name, b_serial)
Note that you need to put the self in explicitly when calling this way.
You can also – as you did – use the super() way, which will call the "first" parent. The exact order is dynamic, but by default it will do left-to-right, depth-first, pre-order scans of your inheritance hierarchy. Hence, your super() call will only call __init__ on ChildA.

subclass constructor using super's constructor

Initially this was defined
class Mammal(object):
def __init__(self, name):
self.name = name
def get_name(self):
return self.name
def say(self):
return("What does the " + self.name + " says")
but now we want to create subclasses of Mammals, whose constructor will call the Mammal's constructor with the correct name.
class Dog(Mammal):
def __init__(self):
Dog.self
This is my code. It says type object 'Dog' has no attribute 'self' what's the problem?
when print(Dog().get_name()) I should get Dog.
If you are using Python 2.x, you should write
super(Dog, self).__init__('name')
or, for Python 3:
super().__init__('name')
instead of
Dog.self
See Understanding Python super() with __init__() methods for detail.
If you want Dog().get_name() to return 'Dog', you should call
super(Dog, self).__init__('Dog')
You should write like this:
class Dog(Mammal):
def __init__(self):
super().__init__('dog name')

Python: how to print instance variable of type string

I am trying to print a string variable returned by name() function, which in this case should print "Jim, but Python is printing
`<bound method Human.name of <__main__.Human object at 0x7f9a18e2aed0>>`
Below is the code.
class Human:
def __init__(self):
name = None
def setName(self, _name):
name = _name
def name(self):
return self.name
jim = Human()
jim.setName("Jim")
print(jim.name())
UPDATE:
After reading the answers, i updated the code as shown below, but, now i am getting a new error TypeError: 'str' object is not callable
class Human:
def __init__(self):
self.name = None
def setName(self, _name):
self.name = _name
def name(self):
return self.name
jim = Human()
jim.setName("Jim")
print(jim.name())
self.name is the method itself. You have no attributes storing the name. Nowhere do you actually set the name as an attribute. The following works:
class Human:
def __init__(self):
self.name = None
def setName(self, _name):
self.name = _name
# NOTE: There is no more name method here!
Now you have an actual attribute, and you don't need to call the method here:
jim = Human()
jim.setName("Jim")
print(jim.name) # directly using the attribute
You could even just set the attribute directly:
jim = Human()
jim.name = "Jim"
print(jim.name)
Alternatively, use self._name to store the name on the instance:
class Human:
_name = None
def setName(self, _name):
self._name = _name
def name(self):
return self._name
Here we used a class attribute Human._name as a default, and only set self._name on the instance in the Human.setName() method.
The problem is that name is the name of the internal variable in your object and also the name of the method.
The namespace for variables and methods is the same. Change the name of your method to something other than name. This will fix your getter. On first glance I thought that that would be all you have to do, but the recommendation in Martijn's answer also applies -- you need to assign to self.name and not just name in order to get your setter to work as well.
As an aside, this getter/setter pattern is not usually appropriate for Python. You should ask yourself why you want to use a getter/setter pattern over simply accessing the object's variable directly. See the section on getters and setters in this article for more detail.
You can use setter and getter properties instead of your custom defined methods.
class Human():
def __init__(self):
self._name = None
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
And then, use them:
jim = Human()
jim.name = "Jim"
print(jim.name)

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