My simplified code is below: it creates an animal, and places it inside a zoo. I want to print the list of animals within the zoo. Going round in circles with this!
class Animal(object):
def __init__(self, name):
self.name = name
class Zoo(object):
def __init__(self):
self.animals = []
def __str__(self):
rep = ", ".join(self.animals)
return rep
def add(self, name):
self.animals.append(Animal(name))
def main():
while True:
zoo = Zoo()
animal = input("add an animal: ")
zoo.add(animal)
print(zoo)
main()
The added __repr__ Method to the Animal returns us the name.
The zoo = Zoo() has to be outside of the loop, this makes sure that we do not create a new zoo with every iteration.
Then we print the list (zoo.animals).
class Animal(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return self.name
class Zoo(object):
def __init__(self):
self.animals = []
def __str__(self):
rep = ", ".join(self.animals)
return rep
def add(self, name):
self.animals.append(Animal(name))
def main():
zoo = Zoo()
while True:
animal = input("add an animal: ")
zoo.add(animal)
print(zoo.animals)
main()
You can simply refer to the name property of Animal in your Zoo.__str__(), e.g.:
def __str__(self):
return ', '.join(animal.name for animal in self.animals)
Now print(zoo) should work correctly.
However this doesn't provide a lot of encapsulation if say you wanted to change what it means to print an animal, e.g. height, size, etc. So perhaps a more encapsulated form would be:
class Animal(object):
...
def __str__(self):
return self.name
class Zoo(object):
...
def __str__(self):
return ", ".join(str(animal) for animal in self.animals)
Now when you print(zoo) the Animal class is responsible for its own string presentation.
Just as a note: you probably should create the Animal instance outside of Zoo, what happens if you decide to create a class hierarchy of Animals (e.g. Mammal) that has different behaviours, your Zoo class would only know about Animals.
class Animal(object):
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
class Zoo(object):
def __init__(self):
self.animals = []
def __str__(self):
return ", ".join(str(animal) for animal in self.animals)
def add(self, animal):
self.animals.append(animal)
def main():
zoo = Zoo()
while True:
animal = Animal(input("add an animal: "))
zoo.add(animal)
print(zoo)
main()
This would still behave properly if you create a Mammal class:
class Mammal(Animal):
...
zoo.add(Mammal(...))
print(zoo)
Related
I want to separate the DB models from the actual classes. But i need two static functions for fetching data from the DB regardless of the subclass type. the implementation for both functions are the same across all DB models.
pyright showing an error that cls inside get() and get_all() functions doesn't have a db property.
from abc import ABC, abstractstaticmethod
class DogsDB:
lists = ["DOG1", "DOG2", "DOG3"]
#classmethod
def get(cls, id):
return cls.lists[id]
class CatsDB:
lists = ["CAT1", "CAT2", "CAT3"]
#classmethod
def get(cls, id):
return cls.lists[id]
class Animal(ABC):
def __init__(self, name):
self.name = name
#abstractstaticmethod
def save(m):
pass
#abstractstaticmethod
def _from_model(obj):
pass
#classmethod
def get(cls, id):
obj = cls.db.get(id)
return cls._from_model(obj)
#classmethod
def get_all(cls):
objs = cls.db.lists
lists = []
for obj in objs:
e = cls._from_model(obj)
lists.append(e)
return lists
def __repr__(self):
return self.name
class DogSound:
def __init__(self, name):
self.name = name
def sound(self):
print(self.name, ": DOG SOUND!!")
class Dog(Animal, DogSound):
db = DogsDB
def __init__(self, name, age):
super(Dog, self).__init__(name)
self.age = age
#staticmethod
def save(m):
print(m)
#staticmethod
def _from_model(obj):
return Dog(obj, 4)
class Cat(Animal):
db = CatsDB
def __init__(self, name, age):
super().__init__(name)
self.age = age
#staticmethod
def save(m):
print(m)
#staticmethod
def _from_model(obj):
return Cat(obj, 4)
print(Cat.get(1))
print(Dog.get(1))
print(Cat.get_all())
print(Dog.get_all())
Dog.get(1).sound()
I cannot duplicate your first error.
Your second issue is a result of method sound implicitly returning None since it has no return statement and you have print(Dog.get(1).sound()), which will print out the return value from that method. You either want to change this to just Dog.get(1).sound() or modify the sound method to return what it is currently being printed and remove the print statement (my choice).
As an aside, I found this class structure a bit difficult to follow. Why do you need a separate DogSound class with a name attribute which should belong to Animal? Also, it seems to me that age could/should be an attribute of Animal since both cats and dogs have an age.
from abc import ABC, abstractstaticmethod
class DogsDB:
lists = ["DOG1", "DOG2", "DOG3"]
#classmethod
def get(cls, id):
return cls.lists[id]
class CatsDB:
lists = ["CAT1", "CAT2", "CAT3"]
#classmethod
def get(cls, id):
return cls.lists[id]
class Animal(ABC):
def __init__(self, name, age):
self.name = name
self.age = age
#abstractstaticmethod
def save(m):
pass
#abstractstaticmethod
def _from_model(obj):
pass
#classmethod
def get(cls, id):
obj = cls.db.get(id)
return cls._from_model(obj)
#classmethod
def get_all(cls):
objs = cls.db.lists
lists = []
for obj in objs:
e = cls._from_model(obj)
lists.append(e)
return lists
def __repr__(self):
return self.name
class Dog(Animal):
db = DogsDB
def __init__(self, name, age):
super().__init__(name, age)
def sound(self):
return f"{self.name}: DOG SOUND!!"
#staticmethod
def save(m):
print(m)
#staticmethod
def _from_model(obj):
return Dog(obj, 4)
class Cat(Animal):
db = CatsDB
def __init__(self, name, age):
super().__init__(name, age)
self.age = age
#staticmethod
def save(m):
print(m)
#staticmethod
def _from_model(obj):
return Cat(obj, 4)
print(Cat.get(1))
print(Dog.get(1))
print(Cat.get_all())
print(Dog.get_all())
print(Dog.get(1).sound())
Prints:
CAT2
DOG2
[CAT1, CAT2, CAT3]
[DOG1, DOG2, DOG3]
DOG2: DOG SOUND!!
If for some reason you want DogSound to be a separate class, then there is no need for the name attribute to be duplicated:
...
class DogSound: # A "Mixin" class
def sound(self):
return f"{self.name}: DOG SOUND!!"
class Dog(Animal, DogSound):
db = DogsDB
def __init__(self, name, age):
super().__init__(name, age)
#staticmethod
def save(m):
print(m)
#staticmethod
def _from_model(obj):
return Dog(obj, 4)
...
In my program I have the following question. How can I define a method in the class 'Mouse' 'Keyboard' and 'Screen' so that they return the room and the computer they belong to + the associated attribute of the class (so for the keyboard class this would be: 'The computer {} is located in the room {} and has the language {} ') Can someone tell me how I can define such a method for these 3 classes without changing the program itself? The method should be defined for each class seperated. The exact task is "Extend the output of maus, screen and tastatur so that the user knows which computer in which room they belong".
I've tried to define the following method:
def as_text(self):
return "{} an {} in {}".format(self.__name, self.__computer, self.__computer.__room)
In my three classes I have build in a reference to computer. My Class Computer has a reference to room, so I've tried to call it with self.__computer.__room but that doesn't work and I'm not sure how to call this attribute.
Here is my code:
class Room:
__name = "unknown"
def __init__(self, name):
self.__name = name
def get_name(self):
return self.__name
class Device:
__name = "Device"
def __init__(self, name):
self.__name = name
def as_text(self):
return "%s" % (self.__name)
class Computer(Device):
__ip = "unknown"
def __init__(self, name, ip, room):
super().__init__(name)
self.__ip = ip
self.__room = room
def as_text(self):
return "%s with ip=%s" % (super().as_text(), self.__ip)
class Laptop(Computer):
def __init__(self, name, room, ip, with_case = True):
super().__init__(name, room, ip)
self.__with_case = with_case
def as_text(self):
if (self.__with_case):
return "%s with case" % super().as_text()
else:
return super().as_text()
class Screen(Device):
__width = "1920"
__height = "1080"
def __init__(self, name, width, height, computer):
super().__init__(name)
self.__width = width
self.__height = height
self.__computer = computer
def as_text(self):
return "{} an {}".format(self.__name, self.__computer)
class Tastatur(Device):
__language = 'English'
def __init__(self, name, language, computer):
super().__init__(name)
self.__language = language
self.__computer = computer
class Maus(Device):
__type = 'Gaming Mouse'
def __init__(self, name, type, computer):
super().__init__(name)
self.__type = type
self.__computer = computer
Your request is not particularly clear, here what I got.
This is my method for the Screen Class:
def as_text(self):
return "{} an {} in {}".format(super().as_text(), self.__computer.as_text(), self.__computer.display_room())
super().as_text()
This calls the method as_text from the parent class Device.
self.__computer.as_text()
This calls the as_text() method from an instance of the Computer class, which is an attribute of your class Screen.
self.__computer.display_room()
This calls the method display_room() from the Computer class, I created it and returns the Room's name.
def display_room(self):
return self.__room.get_name()
Now you should be able to write methods for Tastur and Maus yourself.
So I have been making an RPG game and run into some troubles with inheritance and unpacking.
I have tried to make a simple version of the problem I am having:
class Animal():
def __init__(self,name):
self.name = name
def say_noise(self):
noise = "I am an animal"
by_who = "Animal"
return noise,by_who
class Dog(Animal):
def __init__(self,name):
self.name = name
def say_noise(self):
Animal.say_noise(self)
animal = Animal("man")
doggy = Dog("name")
What I want to do is return the same 2 things in the Animal class and the Dog class.
Now when I do say_noise() with my Animal it works fine, as it returns:
('I am an animal', 'Animal')
However, it does not return anything when I do it with the Dog class, and I tried unpacking them as well (which is what I aim to do in my real code), but when I do this.
a,b =doggy.say_noise()
it just returns this:
TypeError: cannot unpack non-iterable NoneType object
How can I return the same thing with the same class method, by only inheriting it from the parent class?
It's because you are not returning anything from Dog classes say_noise method.
Update your code like this,
class Animal():
def __init__(self, name):
self.name = name
def say_noise(self):
noise = "I am an animal"
by_who = "Animal"
return noise, by_who
class Dog(Animal):
def __init__(self, name):
self.name = name
def say_noise(self):
return Animal.say_noise(self)
animal = Animal("man")
doggy = Dog("name")
a, b = doggy.say_noise()
class Apple:
def print_my_tree_name(self):
print('I want to use name of Tree on which I\'m hanging')
class Tree:
def __init__(self, name):
self.name = name
self.apple = Apple()
a = Tree('test')
a.apple.print_my_tree_name()
Is it possible to access the name variable without passing self to the Apple class e.g. a.apple.print_my_tree_name()?
You can specify the name of the tree as an attribute of the apple in the tree constructor
class Apple:
def print_my_tree_name(self):
print('I am hanging on tree: %s'%self.tree_name)
class Tree:
def __init__(self, name):
self.name = name
self.apple = Apple()
self.apple.tree_name = name
a = Tree('test')
a.apple.print_my_tree_name()
Perhaps something like this, using a #staticmethod
class Tree:
def __init__(self, name):
self.name = name
self.apple = Apple()
class Apple():
#staticmethod
def print_my_tree_name():
print(f'Hanging on {a.name} tree.')
a = Tree('test')
a.apple.print_my_tree_name()
# Hanging on test tree.
I am not sure why you want to access name in Apple class but if I had to do this, I will implement it something as below
class Tree:
def __init__(self, name):
self.name = name
class Apple:
def __init__(self, name):
self.tree = Tree(name)
def print_my_tree_name(self):
print('I want to use %s'%self.tree.name)
a = Tree('test')
a.print_my_tree_name()
See composition in python that is what you need basically.
http://blog.thedigitalcatonline.com/blog/2014/08/20/python-3-oop-part-3-delegation-composition-and-inheritance/
I am working on an assignment for Python Programming 157 at my school.
I need to write a class called Pet that has the following data attributes:
__name (for the name of the pet)
__animal_type (Examples: "Cat", "Dog", and "Hamster" )
__age (for the pet's age)
__height (for the pet's height)
It needs to include
set_name
get_name
I have tried like 4 times and cannot seem to get it right... any clues on getting it started?
# The Pet Program.
class PetProgram:
# The __init__ method accepts an argument for the program
# and adds it to the __pets attribute.
def __init__(self, pet):
self.__pets = pet
# The name will add to the pet attribute.
def name(self, name):
self.__pets = name
def age(self, age):
self.__pets = age
def animal(self, animal):
self.__pets = animal
def height(self, height):
self.__pets = height
# The pets_return will show you the list.
def pets_return(self):
return self.__pets
# The Pet Program.
import petsprogram
def main():
# Enter the name.
petname = input('What is the name of the pet: ')
print 'This will be added to the record.'
savings.name(petname)
# Display the list.
print petsprogram
main()
Above is my latest try...no such luck...any help? Thanks in advance...
A class is not a program, a class should model a thing, like a pet. Therefore, to start off, you should name your class appropriately.
class Pet(object): # Pet derives from the object class, always do this
Now I think you want a constructor that takes the name of the pet, and perhaps the type of pet as well, so we'll define that.
def __init__(self, pet_name, pet_type):
self.pet_name = pet_name
self.pet_type = pet_type
You also need a get and set for the name:
def get_name(self):
return self.pet_name
def set_name(self, pet_name):
self.pet_name = pet_name
To use this class, you instantiate it into an instance of the class:
puppy = Pet('Rover', 'Dog')
puppy.get_name() # prints Rover
I hope that's enough to get you going. You should read up on OOP in Python as mentioned in the comments.
First, why are you using "private" __attributes? That doesn't seem warranted.
Second, you're assigning all your properties to the same instance variable:
self.__pets = pet
self.__pets = name
self.__pets = age
self.__pets = animal
self.__pets = height
You should be using something like
def __init__(self, pet, name, age, animal, height):
self.pet = pet
self.name = name
self.age = age
self.animal = animal
self.height = height
and you should definitely read the tutorial on classes before venturing any further.
I'm not sure where the __pets binding comes into play. Your initial description doesn't say anything about that. I would not have expected an object that represents a pet, as in, a singular pet, to have an attribute that was a list of pets. I would expect something like:
class PetProgram:
def __init__(self, name ='', age=0, type='Unknown', height=0):
self.__name = name
self.__age = age
self.__animal_type = type
self.__height = height
def get_name(self):
return self.__name
def set_name(self, name):
self.__name = name
I'm also not sure where the imports petprogram comes from... is that perchance what your supposed to call your module, and then the instructor has provided that as something you're supposed to run to test it?
(also, what's with all the __under_scores? is this something your teacher is encouraging?)
How does something like this look?
>>> class Pets:
def set_Name(self,name):
self.name=name
def get_Name(self):
return self.name
def set_Atype(self,atype):
self.atype=atype
def get_Atype(self):
return self.atype
def set_Age(self,age):
self.age=age
def get_Age(self):
return self.age
def set_Height(self,height):
self.height=height
def get_Height(self):
return self.height