I am trying to learn how classes work on Python and new to this, I have the following class defined as 'Animal':
class Animal(object):
def __init__(self, size, color, mood):
# init: consists of statements that bind the parameters passed to init to the instance o f the class, when an instance
# is created.
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return "The", self.color, str(self), " is feeling", self.mood, "."
def colors(self, other):
return "The", str(self), "is", self.color, "and the", str(other), "is", other.color, "."
I then create an instance of the Animal object as follow:
hippo = Animal("large", "purple", 'amused')
Finally I call a method on my object as follow:
print(hippo.feeling())
My expectation is to get an output like below:
"The purple hippo is feeling amused."
But what I get in output if I print the same argument as above is:
('The', 'purple', '<__main__.Animal object at 0x7f43cc978160>', ' is feeling', 'amused', '.')
Can someone explain please why the output is similar to a list? also why str(self) returned the object name rather than the word hippo.
The original code in the tutorial was written in Python 3.5, I thought that may have caused it, but I tried the online IDE on https://www.jdoodle.com/python3-programming-online/ for Python 3.5.1 and the result was the same.
You need to pass the animal name when you initialize it — the class won't know the variable name.
class Animal(object):
def __init__(self, name, size, color, mood):
# init: consists of statements that bind the parameters passed to init to the instance of the class, when an instance
# is created.
# pass the name to the class
self.name = name
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return str("The " + self.color + " " + self.name + " is feeling " + self.mood + ".")
def colors(self, other):
return str("The ", self.name, " is " + self.color + " and the " + other.name, " is ", other.color, ".")
The output:
hippo = Animal("hippo", "large", "purple", 'amused')
print(hippo.feeling())
# The purple hippo is feeling amused.
Your method uses commas to separate arguments. Use an f-string, and print instead of returning, as such:
print(f”The {self.size} {self.color} Animal is feeling {self.mood}.”)
Also, you expect self to somehow return the name of the variable. Instead, pass the animal type to the function in init.
As answered by # Ch3steR, you can use __repr__ or __str__. Both serve for the purpose. example is as below:
>>> class Test:
... def __repr__(self):
... return "Test()"
... def __str__(self):
... return "member of Test"
...
>>> t = Test()
>>> t
Test()
>>> print(t)
member of Test
There are few things to address here
The value return from the def feeling(self) function is a tuple, whenever the return values are seprated by a comma, the function returns a tuple consiting of all the return values. Hence we you try to print it it comes looking like a list. So either return a string or modify how you are printing the returned values from the tuple.
You want to get the instance name of class object when you are printing it. i.e
hippo = Animal("large", "purple", 'amused') for this you expect str(self) to return the instance name, which is a bit non trivial. First define this funtion def __str__(self): to get desired output whenever you use str(self). Second to get the variable name either supply the name as a class variable in constructor and use it, which would be easier way or you can use python-varname package to use the varname() function to acheive this.
class Klass:
def __init__(self):
self.id = varname()
k = Klass()
# k.id == 'k'
Expandable using list comprehension,
class Animal:
def __init__(self, name, size, color, mood):
self.name = name
self.size = size
self.color = color
self.mood = mood
self.alive = True
def feeling(self):
# first method, methods are limited to the class, that is why their name does not need to be unique.
return str(f"The {self.color} {self. name} is feeling {self.mood}.")
def colors(self, other):
return str(f"The {self.name} is {self.color} and the {other.name} is {other.color}.")
n = int(input("No of Animals:"))
Animals = []
for i in range(n):
print(f"Enter Details for Animal No.{i+1}")
s = Animal(*[input(f'Enter {info}: ')for info in ["Name", "Size", "Color", "Mood"]])
Animals.append(s)
for i in range(len(Animals)):
print(f"\nAnimal {i+1}")
print(Animals[i].feeling())
No of Animals:1
Enter Details for Animal No.1
Enter Name: Hippo
Enter Size: large
Enter Color: purple
Enter Mood: happy
Animal 1
The purple Hippo is feeling happy.
[Program finished]
Related
Is it a good idea to handle all the arguments in the constructor? instead of handling them in the particular methods where the arguments are actually needed?
Method 1:
def __init__(self,name,rollno,dob,city,state,zip):
self.name=name
..
..
self.zip = zip
def address(self):
return self.city+self.state+self.zip
def unique_identifier(self):
return self.name+self.rollno
test.py
example = Example("Programming","941","1997-09-07","Nashville","TN","37311")
print(example.address())
print(example.unique_identifier())
Method 2:
Class Example:
def address(self,city,state,zip):
return self.city+self.state+self.zip
def unique_identifier(self,name,rollno):
return self.name+self.rollno
test.py
example = Example()
print(example.address("ab","cd","111")
print(example.unique_identifier("Programmer","123")
Any explanation/reasoning to help understand Which method is more preferable for best practices.
Either is fine, it just depends on if the data belongs to the object (method 1) or if the data comes from outside the object (method 2). It can also be a mix of both. A short example:
class Person:
# store data specific to the instance
def __init__(self, name, birthdate, hometown):
self.name = name
self.birthdate = birthdate
self.hometown = hometown
# here I only need data from the instance
def introduce(self):
print("Hello, I am", self.name,
", I come from", self.hometown,
" and was born on ", self.birthdate,
".")
# food shouldn't be part of the Person,
# so it is passed in as an argument
def order_food(self, food):
print("I am ", self.name,
" and would like some ", food, " please.")
Let's suppose I have a parent class called figure:
class Figure:
def __init__(self):
self.name = " "
self.description = " "
self.data = []
def myprint(self):
# Print all variables in a special way
I want to create several childs of this class (Circle, rectangle...) and I want to use as much inheritance as possible. That's why I want to create a myprint function that outputs all the data which is common to all childs, i.e. this one:
self.name = " "
self.description = " "
self.data = []
What is the correct way to do it?
Should I include those lines in class Figure and then modify them in every child using
Figure.name = 'Circle'
... Or should I create them in every child? How would I use a common myprint function then? This way:
class Figure:
def __init__(self):
def myprint(self):
# Print all variables in a special way
class Cricle(Figure):
def __init__(self, radius):
name='Circle'
pass
class Figure:
name = 'Figure'
description = "I'm a figure"
def __init__(self):
self.data = []
def myprint(self):
print(self.name, self.description, self.data)
class Circle(Figure):
name = 'Circle'
description = "I'm a circle"
This is all you need. If the properties aren't specific to an instance, but are the same for all class instances, just define them on the class (here name and description). Only data is defined within the constructor because [] is mutable and you probably want that to be unique for each instance.
The child class then redefines name and description with different values. myprint of Figure instances will print "Figure", while myprint of Circle instances will print "Circle". That's because self.name refers to the name attribute of the current object, and that value will differ based on whether it's a Figure or Circle.
Everything you define in __init__ are instance variables.
I suppose you are looking for class variables, or rather constants which are exactly the same, but written with all capitals by convention.
Also, take a look on the __str__ method here.
The correct way therefore would be:
class Figure:
NAME = "Figure"
def __str__(self):
""" override me """
return "I am a {name} and have the default __str__".format(name=self.NAME)
class Circle(Figure):
NAME = "Circle"
def __init__(self, x, y, r):
self.x, self.y, self.r = x, y, r
def __str__(self):
return "I am a {name} at ({x}, {y}) with radius {r}".format(
name=NAME, x=self.x, y=self.y, r=self.r)
Now all you need to do to get a correct output is to run
f = Figure()
c = Circle(1, 2, 3)
print(f)
print(c)
Which will output
I am a Figure and have my __str__ not overwritten
I am a Circle at (1, 2) with radius 3
I'm trying to call a method from a previous Class for the Class I'm currently working on. It's a mock GPS system using classes for different things. The class I'm trying to get the method from looks like the following :
class GPS_POI:
def __init__(self, location, name , kind):
self.location= location
self.name = str(name)
self.kind = str(kind)
def __str__ (self):
return (str(self.location) + ": "+ self.name +", " + self.kind )
The current class and method I am working on:
class GPS :
def __init__ (self, current, map = None):
self.current = current
self.map= map
self.route= []
def display_map(self):
for i in self.route:
display= GPS_POI()
return (display.__str__ + "\n")
When I run it, I just end up getting the result of "None" when the output I want (example) would be :
"(3,1): kmart, clothes \n(2,3): burger king, food\n" etc.
Would I need to include my parameter self.map from the class GPS into the display_map function for it work properly? What am I not understanding about calling a method from a previous class?
You aren't calling display.__str__; you are just referencing it. You shouldn't call __str__ explicitly anyway. Its purpose is to provide a hook for when you try to treat the object as a string, such as when passing it to str as an argument:
return str(display) + "\n"
I'm doing an extra credit assignment for school. Here's the directions:
Create “Class” of Dog:
Status (properties)
color = "yellow"
legs = 4
Action (method):
Bark() – will take one string argument and print out follow by “Ruff Ruff”
On your main code, create two Objects: Spot, Barney
When you call this in your main code it should give the following results:
Spot = Dog()
Spot.bark("I'm Spot")
I'm Spot : Ruff Ruff
print(Spot.color)
yellow
Barney = Dog()
Barney.bark("Grrrrr")
Grrrrr : Ruff Ruff*
So I completed the program, but when I put my two arguments into my "Main()" function, it says "Spot is not defined". I honestly can't think of where or why it should be defined. Do I have everything right? Any help would be greatly appreciated.
Here's my code:
class Dog:
def _init_ (self, dog_name, color, legs):
self.dog_name = dog_name
self.color = yellow
self.legs= 4
def set_name(self, dog_name):
self.dog_name = dog_name
def get_name (self):
return self.dog_name
def color (self):
return self.color
def legs(self):
return legs
def Bark(string):
print(str(string) + " : " + "Ruff Ruff")
def Main (dog1, dog2):
dog1 = Dog()
dog2 = Dog()
dog1.bark("I'm Spot")
print(dog1.color)
dog2.bark("Grrrrr")
Main(Spot, Barney)
There are a number of small things to fix here. First, make sure _init_ is written as __init__. Second, provide default arguments to color and legs, rather than hardcoding them in self.color = 'yellow'.
The bark method is capitalized in one place but not others - keep that consistent. Also in the bark method, pass in self to keep it a method of Dog.
Lastly, and most importantly, the main method needs an overhaul. Main(Spot, Barney) passes in Spot and Barney, both of which are undefined variables. Even if they were defined, though, the main method overwrites the parameters it takes in:
def Main (dog1, dog2):
dog1 = Dog()
dog2 = Dog()
Here, don't pass any parameters into the main method. Rather, define Spot and Barney as instances of Dog in Main(). The final code should look something like:
class Dog:
def __init__(self, dog_name, color="yellow", legs=4):
self.dog_name = dog_name
self.color = color
self.legs = legs
def set_name(self, dog_name):
self.dog_name = dog_name
def get_name(self):
return self.dog_name
def color(self):
return self.color
def legs(self):
return legs
def bark(self, string):
print(str(string) + " : " + "Ruff Ruff")
def Main():
Spot = Dog("Spot")
Barney = Dog("Barney")
Spot.bark("I'm Spot")
print(Spot.color)
Barney.bark("Grrrrr")
Main()
I got this code and i'm trying to figure out how this works
class Animal(object):
population = 0
def __init__(self, name):
self.name = name
def __str__(self):
return "I am an instance of {}. ".format(self.__class__, self.name)
def __repr__(self):
return self.__str__()
def make_sound(self):
return "{} is trying to speak, but its method doesn't do much".format(self.name)
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name)
self.breed = breed
def __str__(self):
print(super().__str__())
return "My breed is {}".format(self.breed)
def make_sound(self):
return "{} says woof!".format(self.name)
class Cat(Animal):
pass
animals = {'Felix': ('Cat', None), 'Fido': ('Dog', 'mutt'), 'Charlie': ('Dog', 'spaniel')}
animals_list = []
for k in animals:
if animals[k][1]:
animals_list.append(globals()[animals[k][0]](k, animals[k][1]))
else:
animals_list.append(globals()[animals[k][0]](k))
Animal.population+=1
for animal in animals_list:
print(animal)
print(animal.make_sound())
print("Animal population is {}".format(Animal.population))
How are the classes initiated? I can't get my head around how this is done, seems the classes dog and cat are already initiated when the script reaches the if animals part.
Thanks in advance
The classes are instantiated inside this for loop:
for k in animals:
if animals[k][1]:
animals_list.append(globals()[animals[k][0]](k, animals[k][1])) # Instantiates a class
else:
animals_list.append(globals()[animals[k][0]](k)) # Instantiates a class
So, if k is 'Felix', this code is saying:
if None: # Because animals['Felix'][1] is None
animals_list.append(globals()['Cat']('Felix', None))
else:
animals_list.append(globals()['Cat']('Felix'))
globals() returns a dictionary containing the name -> object mapping of all variables in the global namespace. So, globals()['Cat'] returns the actual Cat class. That means globals()['Cat']('Felix') is equivalent to Cat('Felix'). And that, obviously, is instantiating the Cat class with the name 'Felix'. This same pattern repeats for every entry in the animals dict, so in the end, the animals_list contains the instances returned by calling Cat('Felix'), Dog('Fido', 'mutt'), and Dog('Charlie', 'spaniel').
And for what its worth, I agree with the commentors who have pointed out this code is quite ugly. It makes much more sense to do this:
animals = {'Felix': (Cat, None), 'Fido': (Dog, 'mutt'), 'Charlie': (Dog, 'spaniel')}
animals_list = []
for k in animals:
if animals[k][1]:
animals_list.append(animals[k][0](k, animals[k][1]))
else:
animals_list.append(animals[k][0](k))
No need to use globals().