How object of parent class is created in Python? [duplicate] - python

This question already has answers here:
Understanding Python super() with __init__() methods [duplicate]
(7 answers)
Closed 4 years ago.
I am not sure how object of a parent class is created in Python. Consider a following scenario.
class Animal():
def __init__(self):
print("Animal is created")
def eat(self):
print("I am eating")
class Dog(Animal):
def __init__(self, breed, name, spots):
self.breed = breed
self.name = name
self.spots = spots
def bark(self):
print("Woof! My name is {}".format(self.name))
my_dog = Dog(breed="lab", name="Sam", spots=False)
This does not print "Animal is created".
class Animal():
def __init__(self):
print("Animal is created")
def eat(self):
print("I am eating")
class Dog(Animal):
def __init__(self, breed, name, spots):
Animal.__init__(self)
self.breed = breed
self.name = name
self.spots = spots
def bark(self):
print("Woof! My name is {}".format(self.name))
my_dog = Dog(breed="lab", name="Sam", spots=False)
Whereas this prints "Animal is created"
But in both the cases I am able to access eat() method of Animal class from Dogs instance (my_dog). This means Animal is created in both the cases. Then why I don't see Animals constructor getting called in case#1?

You should be calling the parent class (Animal) __init__ method in the Dog __init__ method. To get a handle on the parent class you can use super. This is considered better practice than Dog.__init__ since it doesn't explicitly require the name of the parent class.
class Dog(Animal):
def __init__(self, breed, name, spots):
super().__init__()
self.breed = breed
self.name = name
self.spots = spots

Related

composition over inheritance, even is it a Is-a relationship

I try to use composition even the relationship is: is-a.
So I have a Animal class and I have a Zebra class:
class Name:
pass
class Age:
pass
class Zebra():
pass
class Animal:
def __init__(self, name_animal, age_animal) -> None:
self.name_animal = name_animal
self.age_animal = age_animal
self.name = Name()
self.age = Age()
self.zebra = Zebra()
def __repr__(self):
return "My name is {} and I am {} years old".format((self.name_animal), (self.age_animal))
zebra1 = Zebra('Zebra', 37)
print(zebra1)
but then of course it fails because Zebra has no arguments.
So is it possible to use the repr method also for Zebra without inheritcance but with compostion?
Because I get now this error:
TypeError: Zebra() takes no arguments
I don't recommend to use composition in this case. This is a use-case for inheritance. But academic questions also deserve an answer.
Add a constructor to Zebra that initializes and stores an Animal instance and delegate __repr__:
class Animal:
def __init__(self, name_animal, age_animal) -> None:
self.name_animal = name_animal
self.age_animal = age_animal
def __repr__(self):
return "My name is {} and I am {} years old".format((self.name_animal), (self.age_animal))
class Zebra():
def __init__(self, name_animal, age_animal) -> None:
self.animal = Animal(name_animal, age_animal)
def __repr__(self):
return self.animal.__repr__()
zebra1 = Zebra('Zebra', 37)
print(zebra1)

How to change the variable of Parent Class from a Child Class (in Python)? [duplicate]

This question already has an answer here:
Subclass - Arguments From Superclass
(1 answer)
Closed 1 year ago.
Practising Inheritence in python
I am practising inheritance on python. I am unsure how to change the variable name of the parent class.
# Parent Class
class Family_Member():
def __init__(self, name):
self.name = name
def catch_phrase(self):
print("I am a family member")
# Child Class
class Mum(Family_Member):
def __init__(self):
Family_Member.__init__(self)
# Attempting to change variable of parent class from child class
My_Mum = Mum("Kerry")
This gives me
TypeError: __init__() takes 1 positional argument but 2 were given
Questions
Why does this occur? How do I name my member Kerry without this error
Why does this error not occur when I don't include the init function in the child class. e.g this code works
# Attempt 2
class Family_Member():
def __init__(self, name):
self.name = name
def catch_phrase(self):
print("I am a family member")
class Mum(Family_Member): # THIS CLASS IS NOW EMPTY
pass
My_Mum = Mum("Kerry")
print(My_Mum.name)
class Family_Member():
def __init__(self, name):
self.name = name
def catch_phrase(self):
print("I am a family member")
class Mum(Family_Member):
def __init__(self, name):
Family_Member.__init__(self, name)
My_Mum = Mum("Kerry")
should work, does it?

Old data to new structure

let's say i got some pickled data in an class structure like the following:
class dog:
def __init__(self, nameDog, age):
self.nameDog = namedog
self.age = age
self.favoriteToys = {}
class toy:
def __init__(self, nameToy):
self.nameToy = nameToy
self.color = ''
Now i want to load the data an use it in an new structure with an extra Attribute based on the old structure.
class dog:
def __init__(self, nameDog, age):
self.nameDog = namedog
self.age = age
self.breed = ''
self.favoriteToys = {}
class toy:
def __init__(self, nameToy):
self.nameToy = nameToy
self.color = ''
Is there an easy way to do it?
You might want to create a class that is derived from another. That is called inheritance Python inheritance.
class Rottweiler(dog):
def __init__(self, nameDog, age):
super().__init__(nameDog, age)
self.breed = ''
Using the super() function, your child class (Rottweiler) will automatically inherit the methods and properties from its parent (dog).

Base class accessing super class variables

I'm using python 3.6.
My goal is to make a base class that would be able to somehow access through polymorphism - one of the child class variables.
I know it sounds somewhat 'not oop', so if what im describing can't be done with python - I would like to know what is the best practice for this case.
Following wikipedia's example:
class Animal:
def __init__(self, name): # Constructor of the class
self.name = name
def talk(self): # Abstract method, defined by convention only
raise NotImplementedError("Subclass must implement abstract method")
class Cat(Animal):
def talk(self):
return 'Meow!'
class Dog(Animal):
def talk(self):
return 'Woof! Woof!'
animals = [Cat('Missy'),
Cat('Mr. Mistoffelees'),
Dog('Lassie')]
for animal in animals:
print animal.name + ': ' + animal.talk()
Prints the following:
Missy: Meow!
Mr. Mistoffelees: Meow!
Lassie: Woof! Woof!
I would like to achieve the exactly same output - using
variable overloading (is that a thing?) instead of method overloading.
The reason is that in the programm im working on - dog, cat, and every other kind of animal will talk exactly the same way - influenced only by the data member, such as:
class Animal:
def __init__(self, name): # Constructor of the class
self.name = name
self.vocabulary = [] # so called abstract data member
def talk(self): # Non Abstract method, all animals would talk
for word in self.vocabulary: print (word)
class Cat(Animal):
vocabulary = ["Meow", "Muuuew", "Maow"]
class Dog(Animal):
vocabulary = ["Woof", "Waf", "Haw"]
animals = [Cat('Missy'),
Cat('Mr. Mistoffelees'),
Dog('Lassie')]
for animal in animals:
print animal.name + ': ' + animal.talk()
Prints the following:
Missy: Meow Muuuew Maow
Mr. Mistoffelees: Meow Muuuew Maow
Lassie: Woof Waf Haw
Clearly, this won't work since vocabulary will be empty, as it is in the base class.
I tried to find a solution using super, e.g:
class Cat(Animal):
vocabulary = ["Meow", "Muuuew", "Maow"]
def talk(self):
super(Animal,Cat).talk()
But the result would be AttributeError: 'super' object has no attribute 'talk'
Am I using super wrong?
There are a few unresolved issues in your code, but since python is so dynamic, it will find the subclass instance attribute through normal lookup:
class Animal:
def __init__(self, name):
self.name = name
def talk(self):
for word in self.vocabulary: print (word)
class Cat(Animal):
def __init__(self, name):
super().__init__(name)
self.vocabulary = ["Meow", "Muuuew", "Maow"]
class Dog(Animal):
def __init__(self, name):
super().__init__(name)
self.vocabulary = ["Woof", "Waf", "Haw"]
animals = [Cat('Missy'),
Cat('Mr. Mistoffelees'),
Dog('Lassie')]
for animal in animals:
print(animal.name, end=': ')
animal.talk()
If you want something to enforce this requirement more explicitly in the code, you can make Animal an abstract base class and make an abstruct property named vocabulary:
import abc
class Animal(abc.ABC):
def __init__(self, name):
self.name = name
#property
#abc.abstractmethod
def vocabulary(self):
...
def talk(self):
for word in self.vocabulary: print (word)
class Cat(Animal):
#property
def vocabulary(self):
return ["Meow", "Muuuew", "Maow"]
here is a live link
Python is dynamically typed. There is no need to somehow declare an "abstract data member" in Animal for Animal methods to refer to self.vocabulary; in fact, your attempts to declare an "abstract data member" are causing your problems.
Just remove self.vocabulary = [], and talk will automatically find the subclass vocabulary when it tries to access self.vocabulary.

Mutually Reference-able Instances in Python

Say I have a pair of instances that reference one another mutually. Is there a preferable manner to structure this relationship than the following.
class Human():
def __init__(self, name):
self.name = name
self.pet = Dog('Sparky', self)
def pet(self, animal):
self.pet.receive_petting()
class Dog(Pet):
def __init__(self, name, owner):
self.name = name
self.owner = owner
def receive_petting(self):
pass
def bark_at(self, person):
"do something"
The thing I don't like is that the relationship needs to be specified in two places. Any ideas on how to make this dryer?
I would break this into three classes:
class Human():
def __init__(self, name):
self.name = name
class Dog(Pet):
def __init__(self, name):
self.name = name
def bark_at(self, person):
"do something"
class OwnerPetRelation():
def __init__(self, dog, human):
self.owner=human
self.pet=dog
Now, one owner can also have many dogs, we just need to define as many OwnerPetRelations.
Similarly, a dog can also belong to multiple owners now.
I would create a method on Human that allows you to add pets (since a human might have many pets):
class Human():
def __init__(self, name):
self.name = name
self.pets = []
def add_pet(self, pet):
pet.owner = self
self.pets.append(pet)
def pet(self, animal):
for pet in self.pets:
pet.receive_petting()
class Dog(Pet):
def __init__(self, name):
self.name = name
self.owner = None
def receive_petting(self):
pass
def bark_at(self, person):
"do something"
This can be used as follows
human = Human('Jim')
human.add_pet(Dog('Woof'))
This approach can of course also be used for just a single pet and one could also extend it to allow pets to be owned by many humans.
There's nothing really Python-specific here; this is just a limitation of constructor-based dependency injection. It's hard to inject a reference to another object that cannot have been created yet. Instead, you can create an object that has a reference to something that will have a reference to the other object. For instance, you can pass a function to the constructor that will be able to return the value:
class Human():
def __init__(self,name,dog):
self.name = name
self._dog = dog
#property
def dog(self):
return self._dog()
class Dog():
def __init__(self,name,human):
self.name = name
self._human = human
#property
def human(self):
return self._human()
Then you can use it like this:
human = None
dog = Dog('fido',lambda: human)
human = Human('john',lambda: dog)
print(dog.human.name)
print(human.dog.name)
john
fido
It is not hard to update this so that the property function caches the value, of course. E.g.:
class Dog():
def __init__(self,name,human):
self.name = name
self._human = human
#property
def human(self):
try:
return self._human_
except AttributeError:
self._human_ = self._human()
return self._human_

Categories

Resources