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
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)
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?
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).
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.
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_