__init__ and the setting of class variables - python

Im having some trouble understanding Inheritance in classes and wondering why this bit of python code is not working, can anyone walk me through what is going wrong here?
## Animal is-a object
class Animal(object):
def __init__(self, name, sound):
self.implimented = False
self.name = name
self.sound = sound
def speak(self):
if self.implimented == True:
print "Sound: ", self.sound
def animal_name(self):
if self.implimented == True:
print "Name: ", self.name
## Dog is-a Animal
class Dog(Animal):
def __init__(self):
self.implimented = True
name = "Dog"
sound = "Woof"
mark = Dog(Animal)
mark.animal_name()
mark.speak()
This is the output through the terminal
Traceback (most recent call last):
File "/private/var/folders/nd/4r8kqczj19j1yk8n59f1pmp80000gn/T/Cleanup At Startup/ex41-376235301.968.py", line 26, in <module>
mark = Dog(Animal)
TypeError: __init__() takes exactly 1 argument (2 given)
logout
I was trying to get animal to check if an animal was implemented, and then if so, get the classes inheriting from animal to set the variables that Animals would then be able to manipulate.

katrielalex answered your question pretty well, but I'd also like to point out that your classes are somewhat poorly - if not incorrectly - coded. There seems to be few misunderstandings about the way you use classes.
First, I would recommend reading the Python docs to get the basic idea: http://docs.python.org/2/tutorial/classes.html
To create a class, you simply do
class Animal:
def __init__(self, name, sound): # class constructor
self.name = name
self.sound = sound
And now you can create name objects by calling a1 = Animal("Leo The Lion", "Rawr") or so.
To inherit a class, you do:
# Define superclass (Animal) already in the class definition
class Dog(Animal):
# Subclasses can take additional parameters, such as age
def __init__(self, age):
# Use super class' (Animal's) __init__ method to initialize name and sound
# You don't define them separately in the Dog section
super(Dog, self).__init__("Dog", "Woof")
# Normally define attributes that don't belong to super class
self.age = age
And now you can create a simple Dog object by saying d1 = Dog(18) and you don't need to use d1 = Dog(Animal), you already told the class that it's superclass is Animal at the first line class Dog(Animal):

To create an instance of a class you do
mark = Dog()
not mark = Dog(Animal).
Don't do this implimented stuff. If you want a class that you can't instantiate (i.e. you have to subclass first), do
import abc
class Animal(object):
__metaclass__ = abc.ABCMeta
def speak(self):
...

Since age in the given example is not part of the parent (or base) class, you have to implement the the function (which in a class is called method) in the class which inheritted (also known as derived class).
class Dog(Animal):
# Subclasses can take additional parameters, such as age
def __init__(self, age):
... # Implementation can be found in reaction before this one
def give_age( self ):
print self.age

Related

How can I make the OOP code print my classes objects name?

I've tried to make an OOP based program in python. I gave it an object to work with and tried to make it print the name, but its not working.
class human:
def __init__(self, name):
print("this is a human")
def name(self, name):
print("this is {}".format(bob.name))
bob = human("bob")
Anyone know what the problem could be?
Beyond the answers you already received (which solve your problem), I'd suggest not having a method that prints the name. Rather, you should have a __str___ dunder method that defines the object's behavior when an instance is printed.
class human:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
person = human("bob")
print(person)
'bob'
You can also define the object's behavior when the instance name is entered in the console, for instance just running the line
>>> person
You can do it with __repr__:
def __repr__(self):
return f'when entering the instance name in the console: {self.name}'
This will print:
when entering the instance name in the console: bob
This appears more pythonic to me than having a method that simply prints the name.
You're never storing the name on the instance, where would it get the name from? Your __init__ needs to do something along the lines of self.name = name
the name method and attribute are going to conflict, the latter will shadow (hide) the former, and it should look up whatever attribute its using on self
You never assigned the passed name to the object. Try:
class human:
def __init__(self, name):
print("this is a human")
self.name = name
def print_name(self):
print("this is {}".format(self.name))
bob = human("bob")
bob.print_name()
there are couple of things to update in the code:
bob is an instance which is not defined at human class
notice that init, name functions expect external param but you never use it in the function. (in self. = name)
in order to use it:
define a var in the class named 'name' and update you function to:
class human:
_name = ""
def __init__(self, name):
print("this is a human")
self._name = name
def name(self):
print("this is "+ self._name)
bob = human("bob")
bob.name()
bob = human("bob") only init function and you should call bob.name() in order to call the print-name function

Python: How to properly reassign attributes to work with parent class functions

I am trying to create a parent class and a child class in Python. Ive created getter functions within the parent, that call the parent's attributes using self. When creating the child, I do not want to override the function, simply reassign the value. When I do this, and call the getter from the child, I still receive the parent's attribute value. How can I force the code to use the child's attribute without having to override the getter function?
My class definitions are as follows:
class Dad:
def __init__(self):
self.likes = "Baseball"
self.name = "John"
def get_likes(self):
print(self.likes)
def get_name(self):
print(self.name)
def works(self):
print("Programmer")
class Son(Dad):
def __init__(self):
self.likes = "Soccer"
super().__init__()
def works(self):
print("Student")
When trying to run the code,
d = Dad()
s = Son()
d.get_name()
d.get_likes()
d.works()
s.get_name()
s.get_likes()
s.works()
the output looks like this:
John
Baseball
Programmer
John
Baseball
Student
My desired output would be:
John
Baseball
Programmer
John
Soccer
Student
You just need to set the Son attributes to overwrite those of the parent class:
class Son(Dad):
def __init__(self):
super().__init__()
self.likes = "Soccer"
This is the canonical way to implement child precedence.

python method override with multiple inheritance and instancing

Here is my code - my base_file.py
class modify_file(object):
def modify_file_delete_obj():
print "modify file here"
def modify_file_add_attributes():
print "modify file here"
return ["data"]
class task_list(object):
modify_file_instance = modify_file() #problem part when accessing from project1.py
def check_topology():
data = modify_file_instance.modify_file_add_attributes()
#use this data further in this method
def check_particles():
print "check for particles"
project1.py file
import base_file as base_file
class project1(base_file.modify_file,base_file.task_list):
#overriding method of modify_file class
def modify_file_add_attributes(self):
print "different attributes to modify"
return ["different data"]
The idea is to run base_file.py for most projects and the project specific ones when required.
But when i run the method
"check_topology" from project1.py
the modify_file class is being derived from the base_file.py not project1.py
So the output is still ["data"] not ["different data"]
If you want to correctly use inheritance, define a base class Pet which provides a method to be overridden by a specific kind of pet.
class Pet(object):
def talk(self):
pass
class Cat(Pet):
def talk(self):
return "meow"
class Dog(Pet):
def talk(self):
return "woof"
pets = [Cat(), Dog(), Cat()]
for p in pets:
print(p.talk())
# Outputs
# meow
# woof
# meow
(I leave the issue of what Pet.talk should do, if anything, as a topic for another question.)
You are mixing up object composition with multiple inheritance.
The task_list class uses object composition when it creates an internal instance of the modify_file class. But there is a problem here in that you are creating it as a class attribute, which means it will be shared by all instances of task_list. It should instead be an instance attribute that is created in an __init__ method:
class task_list(object):
def __init__(self):
super(task_list, self).__init__()
self.modify_file_instance = modify_file()
def check_topology(self):
data = self.modify_file_instance.modify_file_add_attributes()
The project1 class uses multiple inheritance, when in fact it should use single inheritance. It is a kind of task_list, so it makes no sense for it to inherit modify_file as well. Instead, it should create it's own internal sub-class of modify_file - i.e. use object composition, just like task_list class does:
# custom modify_file sub-class to override methods
class project1_modify_file(base_file.modify_file):
def modify_file_add_attributes(self):
print "different attributes to modify"
return ["different data"]
class project1(base_file.task_list):
def __init__(self):
super(project1, self).__init__()
self.modify_file_instance = project1_modify_file()
Now you have a consistent interface. So when project1.check_topology() is called, it will in turn call task_list.check_topology() (by inheritance), which then accessses self.modify_file_instance (by composition):
>>> p = project1()
>>> p.check_topology()
different attributes to modify
In your dog class you're re-constructing an instance of cat, this instance (and the cat type) does not know they are inherited elsewhere by pets.
So you can naturally try:
class cat(object):
def meow(self):
self.sound = "meow"
return self.sound
class dog(object):
def woof(self):
return self.meow()
class pets(cat,dog):
def meow(self):
self.sound = "meow meow"
return self.sound
print(pets().woof())
Which still make no sense with those actual names, but you told they are fake names so it make be OK.

How do I get rid of unneeded parameters in a class initiation?

So I'm trying to get the hang of OOP in Python. The problem I have is when initializing my objects for sub-classes, I'm still having to input information which I shouldn't need to.
Specifically, I'm trying to make it so I can create a Person object without specifying can_speak. So I could do something like:
John = person("John Anderson")
Without having to input can_speak as part of the initialization.
class Animal(object):
def __init__(self, name, can_speak):
self.name = name
self.can_speak = False
class Dog(Animal):
pass
class Person(Animal):
def __init__(self, name, can_speak):
self.name = name
self.can_speak = True
Bob = Person("Bob the Builder", 3.141)
print(Bob.name)
print(Bob.can_speak)
# Bob the Builder
# True
Sam = Dog("Sam the Mutt", 0.00059)
print(Sam.name)
print(Sam.can_speak)
# Sam the Mutt
# False
Here I have to put something as the second input into the initialization, or I get an error. It's a waste like this.
You do not have to add a parameter for every attribute an object has. You can simply fill it in at the Animal level, and override it at the Person level, like:
class Animal(object):
def __init__(self, name): # look ma, no can_speak parameter
self.name = name
self.can_speak = False
class Dog(Animal):
pass
class Person(Animal):
def __init__(self, name): # look ma, no can_speak parameter
super().__init__(name) # perform a super call
self.can_speak = True # override the can_speak
You only have to add a parameter if how such an object should be constructed depends on input.
Furthermore note that you do not have to add such an attribute is attached to an object. You can attach attributes to classes, or define methods. For instance:
class Animal(object):
can_speak = False
def __init__(self, name): # look ma, no can_speak parameter
self.name = name
class Dog(Animal):
pass
class Person(Animal):
can_speak = True
Now we store whether an Animal can speak in the class. This will result in less memory usage, whereas we can still get whether an animal can speak:
>>> a = Animal('foo')
>>> a.can_speak
False
>>> p = Person('bar')
>>> p.can_speak
True
We can however still add an attribute can_speak to an individual dog (in Belgium for instance, there was a television show about a fictitious speaking dog named Samson):
>>> samson = Dog('Samson')
>>> samson.can_speak = True
>>> samson.can_speak
True
>>> foo = Dog('other dog')
>>> foo.can_speak
False
Assuming Animal is the Base class having an attribute can_speak Defaulted to the variable passed into the constructor, which is again defaulted to False.
In the child class Dog is calling its base constructor so it can't speak. But Person is calling the base constructor with a True value for can_speak.
So you can create an object of person which can't speak as well as an animal which can speak(such as parrot). By following the below method the can_speak variable remains constant throughout all the classes and not duplicated in child classes and can be changed by passing an argument instead of changing manually within child class.
Try the following
class Animal(object):
def __init__(self, name, can_speak=False):
self.name = name
self.can_speak = can_speak
class Dog(Animal):
pass
class Person(Animal):
def __init__(self, name, can_speak=True):
super(Person, self).__init__(name, can_speak)
Bob = Person("Bob the Builder")
print(Bob.name)
print(Bob.can_speak)
# Bob the Builder
# True
Sam = Dog("Sam the Mutt")
print(Sam.name)
print(Sam.can_speak)
# Sam the Mutt
# False
First you should always use the built-in function super() and call parent's __init__() unless you are really sure you don't want to do that. The parent can initialize more than those two attributes and you would have to copy it into children's __init__() which is highly error-prone.
Now you can accomplish your task in several ways:
Use default value
class Person(Animal):
def __init__(self, name, can_speak = True):
super().__init__(name, can_speak)
In that case you still can create instance of Person and set that he can't speak (he can be speechless).
If you don't want to support speechless people then you can do this:
class Person(Animal):
def __init__(self, name, can_speak = True):
super().__init__(name, True)
But then the parameter can be misleading so you can omit that (from this point the parent and child has different constructor parameters which is usually not a problem):
class Person(Animal):
def __init__(self, name):
super().__init__(name, True)

Python understanding OOP, inheritance

I solve this problem:
Develop an application which operates with next types:
Person (field Name, method ShowData())
Student (field Education)
Worker (field WorkPlace)
Classes Student and Worker are derived from class Person.
Class Academy in it's container collects Students and Workers and shows Name, Education or WorkPlace for all persons in method ShowAll().
We can add new persons to Academy by calling method AddPerson().
Which hierarchy of classes is the best
for solving this problem?
Code should include inheritance and use collections.
This is my solution, but i don't know how to realize method AddPerson:
class Academy(object):
theWholeList = []
#staticmethod
def showAll():
for obj in Academy.theWholeList:
if isinstance(obj,Student):
print obj.name+' - '+obj.edu
elif isinstance(obj,Worker):
print obj.name+' - '+obj.wplace
class Person(Academy):
def __init__(self,name):
self.name = name
super(Person, self).theWholeList.append(self)
def showData(self):
return vars(self)
class Student(Person):
def __init__(self, name, edu):
super(Student, self).__init__(name)
self.edu = edu
class Worker(Person):
def __init__(self, name, wplace):
super(Worker, self).__init__(name)
self.wplace = wplace
Maybe Academy must inherit Person and method AddPerson will be like that:
def add(self,name):
super(Academy,self).__init__(name)
first thing:
class Academy(object):
theWholeList = []
#staticmethod
def showAll():
for obj in Academy.theWholeList:
if isinstance(obj,Student):
print obj.name+' - '+obj.edu
elif isinstance(obj,Worker):
print obj.name+' - '+obj.wplace
you do not need to have Academy's method showAll() be a static method, as on your design the Academy is legitimate to be a singleton, i.e. a class having a single instance.
Also theWholeList is a very bad name for a list. Because you know it is a list, as you're assigning it a list. The name shall describe its semantic, i.e. the kind of things it contains, what it is used for.
You should rewrite it as follows:
class Academy:
def __init__(self):
self.person_list = []
def show_all(self):
for item in self.person_list:
item.show_data()
And you would instanciate it once:
academy = Academy()
Then the following:
class Person(Academy):
def __init__(self,name):
self.name = name
super(Person, self).theWholeList.append(self)
is bad design: in object oriented programming you should think about encapsulating data. Here you're making the assumption that Person knows the internals of Academy. And what if you decide to change Academy's implementation so theWholeList is renamed? Or switched into a dict()? This should be transparent to the "user" of the class Academy. A better design should be:
class Academy:
... # cf earlier
def add_person(self, person):
self.person_list.append(person)
class Person(Academy):
def __init__(self,name):
self.name = name
def show_data(self):
print("My name is: {}".format(name))
So you can use it as follows:
person_a = Person("John Doe")
person_b = Person("Jim Smith")
academy.add_person(person_a)
academy.add_person(person_b)
And finally you're wondering:
Maybe Academy must inherit Person
Most of the time, subclassing is the wrong answer of a wrong question. You need to subclass when you want to extend or specialize behaviour of a class. A classical example would be:
class Animal:
def noise(self):
raise NotImplementedError # virtual method
class Duck(Animal):
def noise(self):
print("quack")
class Cat(Animal):
def noise(self):
print("meaw")
So in your case, you have a class person that implements show_data, and what you want is to extend the behaviour, for worker and student:
class Worker(Person): # a worker _is_ a person!
def __init__(self, name, unit):
# left as an exercise to the OP
def show_data(self):
# left as an exercise to the OP
class Student(Person):
def __init__(self, name, promo):
# left as an exercise to the OP
def show_data(self):
# left as an exercise to the OP
I won't get into much more details here, as I suppose you have a teacher you can ask more about the comments I made. But at least you tried, made some mistakes (AND MISTAKES ARE GOOD!). But I'm not giving you a full answer, my only goal here is to set you up in the right mind set to make your code a better design!
I hope this helps!
You want to be able to add people:
>>> academy = Academy()
>>> academy.add(Person('Pete'))
>>> academy.showAll()
Name: Pete
>>> academy.add(Student('Taras', 'Higher'))
>>> academy.showAll()
Name: Pete
Name: Taras, Education: Higher
>>> academy.add(Worker('riotburn', 'StackOverflow')
>>> academy.showAll()
Name: Pete
Name: Taras, Education: Higher
Name: riotburn, Workplace: StackOverflow
showAll needs to iterate over all people calling ShowData on them. This will be implemented differently for each type.
class Academy(object):
def __init__(self):
self.people = []
def add(self, person):
self.people.append(person)
def showAll(self):
for person in self.people:
person.ShowData()
Where for example, Worker will implement ShowData as:
def ShowData(self):
print 'Name: ' + self.name + ', Education:' + self.edu

Categories