i am start to learn how to write python code
There is an option to write code ones onthis situation?
i want to crate class and 2 class how extend from her and i want to check if i can loop on only ones my example:
class animal:
def printDetail(self):
print(self.name)
class bird(animal):
def printDetail(self):
super(bird, self).printName()
print(self.wingsSize)
class fish(animal):
def printDetail(self):
super(fish, self).printName()
print(self.weight)
fishList = []
birdList = []
animalList = []
def main():
for a in (animalList,fishList,birdList):
a.printDetail()
main()
when i try to do it i got an error that AttributeError: 'list' object has no attribute 'printDetail' like this is an unknow function. i understand that it try to take the attribute of the list class but there is any option that i can do it more esear then:
for a in animalList:
a.printDetail()
for a in fishList:
a.printDetail()
for a in birdList:
a.printDetail()
that is work fine but to long?
The first code snippet creates a 3-tuple of lists. You're invoking .printDetail() on every list in that tuple.
To create a list that contains the elements from each list (as opposed to a list that contains the lists themselves), you can use for a in (animalList + fishList + birdList):
As others have already answered, there are a variety of quick ways to do this. I prefer the unpacking method that Wups uses in his answer.
However, I also wanted to check if we needed to add initializations to each of these classes in order for the print to work. Further, I was thinking when you called printName in some methods, you meant printDetail instead (maybe I am wrong?). Thus I also revised the class code also, I hope it may benefit you and others who may want to run the code and see a result:
class animal:
def __init__(self, name):
self.name=name
def printDetail(self):
print(self.name)
class bird(animal):
def __init__(self, name, wingsSize):
self.name=name
self.wingsSize = wingsSize
def printDetail(self):
super(bird, self).printDetail()
print(self.wingsSize)
class fish(animal):
def __init__(self, name, weight):
self.name=name
self.weight=weight
def printDetail(self):
super(fish, self).printDetail()
print(self.weight)
fishList = [fish("salmon",12)]
birdList = [bird("eagle",4)]
animalList = [animal("bear")]
def main():
for a in (*animalList, *birdList, *fishList):
a.printDetail()
main()
Output:
bear
eagle
4
salmon
12
Related
Good morning,
I'm trying something like this:
class Fish:
def __init__(self, name):
self.name = name
def swim(self):
print(self.name,"is swimming!")
My ourpose is to extend the class to Aquarium, which cointains a dictionary of fishes:
class Aquarium(Fish):
def __init__(self, **kwargs):
self.fishes ={}
for _, name in kwargs.items():
self.fishes[name] = Fish.__init__(self,name)
def how_many(self):
print("In acquarium there are",len(self.fishes),"fishes")
def all_swimming(self):
#???
Is it possible to implement something like Aquarium.swim() to use the method of all classes inserted? I tried it, but as result it prints out only of the last fish inserted. Any suggestion?
How can I collect many Fish() inside Aquarium()? Are there better methods?
It looks like you are confusing the idea of "is a kind of" and "contains". Writing class Aquarium(Fish) suggests that Aquarium is a kind of Fish, which it is not. An Aquarium contains fish. So, the Aquarium should not be derived from Fish.
I think this is more like your intentions:
class Fish:
def __init__(self, name):
self.name = name
def swim(self):
print(self.name, "is swimming!")
class Aquarium: # An aquarium is not a kind of fish, rather it contains fish
def __init__(self, **kwargs):
self.fishes = [] # list of all fishes in the aquarium
fishes = kwargs["fishes"]
for fish_name in fishes:
new_fish = Fish(fish_name)
self.fishes.append(new_fish) # add to your list
def how_many(self):
print("In aquarium there are " + str(len(self.fishes)) + " fishes")
def all_swimming(self):
print("The list of all fishes in the aquarium:")
for fish in self.fishes:
print(" " + fish.name)
a = Aquarium(fishes=["Nemo", "Dory"])
print(a.how_many())
a.all_swimming()
Yes, it is possible. But I think this is a better way.
class Fish:
def __init__(self, name:str):
self.name = name
def swim(self):
print(self.name,"is swimming!")
class Aquarium():
def __init__(self, fishes:Fish):
self.fishes = []
for fish in fishes:
self.fishes.append(fish)
def how_many(self):
print("In acquarium there are",len(self.fishes),"fishes")
def all_swimming(self):
for fish in self.fishes:
fish.swim()
Here is a list of suggestions that you may correct:
An aquarium is not a fish. Do not inherit from it! If you need an aspect of the Fish class then split that class and make an composite.
A dictionary is used to store a key and a value. But fish already knows that key. So why don't you use a list? Do you need the dictionary? If not use a list, it is easier to use (this is just my personal opinion).
You used **kwargs. While this is usable nobody can clearly understand what exactly you want these parameters to be. Usually it is better to use a clearly defined set of parameters.
Use typing. At least for the parameters. This is really helpful to understand your code better. Also you IDE might become more helpful if you do.
I'm trying to create three classes one mainly storing attribute of a person, the other two will access to the instance of a person and do a bunch of things to adjust the its attribute values.
I want to keep them in separate way so its easy to manage the content in each class and expand. I think this is not a inheritance problem so my code is obviously wrong for the goal but I have no clue what shall be done.
class CreatePerson():
def __init__(self):
self.to_do_list=[]
class Shop(CreatePerson):
def __init__(self,CreatePerson):
super().__init__()
def add_element(self,a):
self.to_do_list+=[a]
class Recreation(CreatePerson):
def __init__(self,CreatePerson):
super().__init__()
def add_element(self,a):
self.to_do_list+=[a]
if __name__ == '__main__':
joe=CreatePerson()
p1=Shop(joe)
p2=Recreation(joe)
p1.add_element('whole milk')
p2.add_element('reading book')
print(joe.to_do_list)
I was hoping it could return following, but obviously it didn't link
['whole milk','reading book']
If I understand correctly, you want your Shop and Recreation objects to share their underlying CreatePerson object. But your code doesn't do that. As #mike scotty commented, you pass in Joe, but don't use Joe for anything. So these new objects just create their own to_do_lists, which are not shared. Here is something like what i imagine you want:
class CreatePerson():
def __init__(self):
self.to_do_list = []
def add_element(self, a):
self.to_do_list += [a]
class Shop():
def __init__(self, CreatePerson):
self.my_person = CreatePerson
def add_element(self, a):
self.my_person.add_element(a)
class Recreation():
def __init__(self, CreatePerson):
self.my_person = CreatePerson
def add_element(self, a):
self.my_person.add_element(a)
>>> joe=CreatePerson()
>>> p1=Shop(joe)
>>> p2=Recreation(joe)
>>> p1.add_element('whole milk')
>>> p2.add_element('reading book')
>>> print(joe.to_do_list)
['whole milk', 'reading book']
So now Shop and Recreation aren't instances of a CreatePerson, but they do take a CreatePerson in their constructor, and store a reference to that person. And when you call add_element on those objects, they call the new add_element method that their CreatePerson has.
I'd just like to note that I don't think this is exactly the right abstraction - your Shop has one-and-only-one person, as does your Recreation. But I took it at face value for the purposes of answering this question.
Hope that helps, Happy Coding!
I'm working in Python 2.7.8. What follows is a slight variant of the problem I'm working on.
I have a large number of custom classes that I've written where the inheritance is like a tree. The behavior is well encapsulated by the following example:
import random
class Animal(object):
def __init__(self, name):
self.name = name
self.can_own_pets = False #most Animals cannot own pets
self.get_features()
def give_pet(self, pet):
if not self.can_own_pets:
print(self.name+' cannot own a pet!')
else:
self.pets.append(pet)
def is_hungry(self):
return random.choice([True, False])
def get_features(self):
"""
In some classes, get features will be a function
that uses self.name to extract features.
In my problem, the features are extracted
with regular expressions that are determined by
by the class.
"""
pass
class Human(Animal):
def __init__(self, name):
super(Human, self).__init__(name)
self.can_own_pets = True
self.pets = []
class Dog(Animal):
def __init__(self, name):
super(Dog, self).__init__(name)
def bark(self):
print 'WOOF'
def get_features(self):
if 'chihuahua' in self.name:
self.is_annoying = True
elif 'corgi' in self.name:
self.adorable = True
My program needs to take in a large number of animals and delegate them to the correct classes -- I need the correct attributes and methods. What I would like to do is modify the Animal constructor so that if the name argument is something like "Finn the Dog" or "Jake the Human", it (the constructor) returns an instance of the class "Dog" or "Human", complete with the appropriate methods and attributes. Now, I know that I could easily write a function that takes a string and class as arguments, constructs a dictionary where the keys are the names of the subclasses of the given class, looks up the element of the dictionary that is contained in the string, and returns an object of that class. My question is whether or not there is a way to code this into the Animal class itself, which seems more elegant to me (as well as easier to maintain).
Here's an implementation --
def _get_all_subclasses(cls):
for scls in cls.__subclasses__():
yield scls
for scls in _get_all_subclasses(scls):
yield scls
class Animal(object):
#staticmethod
def from_string(s):
for cls in _get_all_subclasses(Animal):
# Somehow pick the class based on the string... This is a really simple example...
if cls.__name__ in s:
return cls()
raise ValueError('Bummer. Animal has not been discovered.')
class Dog(Animal):
pass
class Cat(Animal):
pass
class Lion(Cat):
pass
print Animal.from_string('is a Dog')
print Animal.from_string('is a Cat')
print Animal.from_string('Lions!!!')
print Animal.from_string('Lockness Monster')
There are limitations here
All of the constructors need to be pretty much the same which means that Cat.__init__ needs to basically do the same thing that Human.__init__ does.
After you create the instance, your code needs to have logic to handle Cat, Human, Dog, etc. In some cases that's Ok (e.g. the code really only cares that it is working with an Animal), but frequently it isn't (after all, Cats can walk on fences, but Humans can't).
Generally, the principle that I like to live by is to try to make the inputs to my functions permissive (is it a list or a tuple? Who cares! Duck Typing FTW!) but to try to have really well defined outputs. I think that this makes interfaces easier to use in the long haul and the code that I wrote above would probably not pass a code review if I was the reviewer :-).
To build upon mgilson's answer
You can override the __new__ method so that you can instantiate the classes like normal without a static method.
class Animal(object):
#classmethod
def _get_all_subclasses(cls):
for scls in cls.__subclasses__():
yield scls
for scls in scls._get_all_subclasses():
yield scls
def __new__(cls, name):
cls_ = cls
for subcls in Animal._get_all_subclasses():
if subcls.__name__ in name:
cls_ = subcls
break
instance = object.__new__(cls_)
if not issubclass(cls_, cls):
instance.__init__(name)
return instance
I have the following problem that I will attempt to illustrate with the following example.
class Brick():
def __init__(self):
self.weight = 1
class House():
def __init__(self, number_bricks):
self.bricks = [Brick() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x,y: x+y, [brick.weight for brick in self.bricks])
But now suppose I create a new kind of Brick, StrongBrick, so that I make a house, a subclass StrongHouse, where StrongBrick plays exactly the same role in StrongHouse as Brick plays in House. How can I do this in a nice way (not just retyping all the class definitions)?
So the basic idea is, how can I change a class which is composed of some objects to the same class but composed of say a subclass of the original member objects?
Thanks very much for any help you can give me.
You could have a factory (a brickyard?) and pass that to House.__init__().
class Brick(object): pass
class StrongBrick(Brick): pass
class House(object):
def __init__(self, brick_factory, num_bricks):
self.bricks = [brick_factory() for i in range(num_bricks)]
house = House(Brick, 10000)
strong_house = House(StrongBrick, 10000)
As you can see, subclassing House isn't even necessary to be able to construct houses from different types of bricks.
There are various ways to do this. You could make the relevant Brick class an attribute of the House class:
class House(object):
brick_class = Brick
def __init__(self, number_bricks):
self.bricks = [self.brick_class() for i in range(number_bricks)]
class StrongHouse(House):
brick_class = StrongBrick
Or, you could pass in the Brick class you want to use when constructing the House:
class House(object):
def __init__(self, brick_class, number_bricks):
self.bricks = [brick_class() for i in range(number_bricks)]
One nice pattern could be this:
class Brick(object):
weight = 1
class StrongBrick(Brick):
weight = 42
class House(object):
brick_type = Brick
def __init__(self, number_bricks):
self.bricks = [self.brick_type() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x, y: x + y, [brick.weight for brick in self.bricks])
class StrongHouse(House):
brick_type = StrongBrick
Another is to make a function making a factory, and using an argument for the brick_type with default value:
class House(object):
def __init__(self, number_bricks, brick_type=Brick):
self.bricks = [brick_type() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x, y: x + y, [brick.weight for brick in self.bricks])
def make_house_factory(brick_type):
def factory(number_bricks):
return House(number_bricks, brick_type)
return factory
StrongHouse = make_house_factory(StrongBrick)
Of course all such objects would be instances of the House only, even though I named StrongHouse here so that it resembles a class name.
But now suppose I create a new kind of Brick, StrongBrick, so that I make a house, a subclass StrongHouse, where StrongBrick plays exactly the same role in StrongHouse as Brick plays in House. How can I do this in a nice way (not just retyping all the class definitions)?
As all of the other answers have explained, you really don't want to create this parallel hierarchy at all. But to answer your direct question: You can create classes dynamically, so you can create a parallel hierarchy without copying and pasting all the class definitions. Classes are, after all, first-class objects.
Again, let me stress that you almost certainly don't want to do this, and I'm just showing that it is possible.
def make_house_class(brick_type):
class NewHouse(House):
def __init__(self, number_bricks):
self.bricks = [brick_type() for i in range(number_bricks)]
return NewHouse
Now, you could statically create all the house types:
StrongHouse = make_house_class(StrongBrick)
CheapHouse = make_house_class(CheapHouse)
# ...
… or maybe build them dynamically from a collection of all of your brick type:
brick_types = (StrongBrick, CheapBrick)
house_types = {brick_type: make_house_class(brick_type) for brick_type in brick_types}
… or even add some hacky introspection to just create a new FooHouse type for every FooBrick type in the current module:
for name, value in globals().items():
if name.endswith('Brick') and name != 'Brick' and isinstance(value, type):
globals()[name.replace('Brick', 'House')] = make_house_class(value)
… or even create them on the fly as needed in the factory-maker:
def make_house_factory(brick_type):
house_type = make_house_class(brick_type)
def factory(number_bricks):
return house_type(number_bricks, brick_type)
return factory
… or even the generated factory:
def make_house_factory(brick_type):
def factory(number_bricks):
return make_house_class(brick_type)(number_bricks, brick_type)
return factory
Add a parameter to the House.__init__ so that you can specify the Brick type:
import functools
class Brick():
def __init__(self):
self.weight = 1
class StrongBrick():
def __init__(self):
self.weight = 10
class House():
def __init__(self, number_bricks,brick_type=Brick):
self.bricks = [brick_type() for i in range(number_bricks)]
def get_weight(self):
return reduce(lambda x,y: x+y, [brick.weight for brick in self.bricks])
#not a new class, but an alias with a different default brick_type
StrongHouse = functools.partial(House,brick_type=StrongBrick)
In plain english: I am creating class instances dynamically in a for loop, the class then defines a few attributes for the instance. I need to later be able to look up those values in another for loop.
Sample code:
class A:
def __init__(self, name, attr):
self.name=name
self.attr=attr
names=("a1", "a2", "a3")
x=10
for name in names:
name=A(name, x)
x += 1
...
...
...
for name in names:
print name.attr
How can I create an identifier for these instances so they can be accessed later on by "name"?
I've figured a way to get this by associating "name" with the memory location:
class A:
instances=[]
names=[]
def __init__(self, name, attr):
self.name=name
self.attr=attr
A.instances.append(self)
A.names.append(name)
names=("a1", "a2", "a3")
x=10
for name in names:
name=A(name, x)
x += 1
...
...
...
for name in names:
index=A.names.index(name)
print "name: " + name
print "att: " + str(A.instances[index].att)
This has had me scouring the web for 2 days now, and I have not been able to find an answer. Maybe I don't know how to ask the question properly, or maybe it can't be done (as many other posts seemed to be suggesting).
Now this 2nd example works, and for now I will use it. I'm just thinking there has to be an easier way than creating your own makeshift dictionary of index numbers and I'm hoping I didn't waste 2 days looking for an answer that doesn't exist. Anyone have anything?
Thanks in advance,
Andy
Update: A coworker just showed me what he thinks is the simplest way and that is to make an actual dictionary of class instances using the instance "name" as the key.
Sometimes keeping it simple is best. Having a dict that stores your instances with their names as the keys would be both straightforward and fairly simple to implement.
class A:
instances={}
def __init__(self, name, attr):
self.name=name
self.attr=attr
A.instances[name] = self
and then to get the proper instance, just...
instance = A.instances[name]
No need to put the instance dict inside the class. Just create a dict, inst in the local scope:
class A:
def __init__(self, name, attr):
self.name=name
self.attr=attr
inst={}
names=("a1", "a2", "a3")
x=10
for name in names:
inst[name]=A(name, x)
x += 1
Then, whenever you want to access a certain instance by name, just use inst[name]:
for name in names:
print inst[name].attr
Yes, the dictionary approach should work well, and can be dovetailed into the class itself.
class A:
_instances = {}
#classmethod
def get(cls, name):
return A._instances[name]
def __init__(self, name, attr):
self.name=name
self.attr=attr
A._instances[name] = self
a = A('foo', 10)
aa = A.get('foo')
If you want to play around with __new__, you can even make this transparent:
a = A('foo', 10)
aa = A('foo') # 'a' and 'aa' refer to the same instance.
This is a bit complicated, so I'll leave it to you to research (and of course ask another question on SO if you get stuck).