简体   繁体   English

更改多个对象中的属性

[英]Change attribute in multiple objects

I'm learning OOP in Python and I get stucked with one thing. 我正在学习Python中的OOP而且我被一件事情搞定了。

I have an example class: 我有一个示例类:

class Animal:

    def __init__(self, name="", hunger=0):
        self.name = name
        self.hunger = hunger

    def eat(self):
        self.hunger += 1

And some objects: 还有一些对象:

dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")

I would like to use method eat() to change value of hunger in every single one of them at one blow. 我想用方法eat()一次性改变每一个人的饥饿价值。 I have already tried to do something like this: 我已经尝试过这样的事情:

Animal.eat()

But it doesn't work (there's TypeError, because of missing argument 'self'). 但它不起作用(存在TypeError,因为缺少参数'self')。

Also: 也:

Animal.hunger += 1

Doesn't work (returns AttributeError). 不起作用(返回AttributeError)。

If anyone has any ideas, I would be very grateful! 如果有人有任何想法,我将非常感激!

You can maintain a class variable that collects the instances and adjust all of their hungers in eat : 您可以维护一个类变量来收集实例并调整eat所有hungers:

class Animal:
    instances = []

    def __init__(self, name="", hunger=0):
        self.name = name
        self.hunger = hunger
        Animal.instances.append(self)

    def eat(self):
        for i in Animal.instances:
            i.hunger += 1

Semantically, you might want to make it a classmethod , though 从语义上讲,您可能希望将其作为一种classmethod

    @classmethod
    def eat(cls):
        for i in cls.instances:
            i.hunger += 1

You can still call it on instances if you so wish. 如果您愿意,您仍然可以在实例上调用它。

You actually have to call it on the object itself like this: 你实际上必须像这样在对象本身上调用它:

cat.eat()
dog.eat()
giraffe.eat()

otherwise it doesn't know which object to actually change. 否则它不知道实际改变哪个对象。 You could store all your Objects in an array and loop over that array to call the function on all of them one after another: 您可以将所有对象存储在一个数组中并循环遍历该数组,以便一个接一个地调用所有这些函数:

dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
animals=[dog, cat, giraffe]
for animalType in animals:
    animalType.eat()

now you can do them all at once or one at a time if you want. 现在,如果你愿意,你可以一次完成所有这些操作,也可以一次完成。 You will however need to addnew animals to the array after you create them to keep the list up to date: 但是,您需要在创建它们之后将新动物添加到阵列中以使列表保持最新:

fish=new Animal("fish")
animals.append(fish)
class Animal(object):

    hunger = 0

    def __init__(self, name=""):
        self.name = name


    def eat(self):
        Animal.hunger = Animal.hunger + 1

dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")


dog.eat()

print("Dog's hunger variable is", dog.hunger)
1
dog.eat()

print("Dog's hunger variable is :",dog.hunger)
2

print("Cat's hunger variable is :",cat.hunger)
2

print("Giraffe's hunger variable is :", giraffe.hunger)
2

When eat() is called on a single instance, the hunger variable is updated for all instances! 当在单个实例上调用eat() ,会更新所有实例的hunger变量!

@schwobaseggi has the most straightforward answer for what you want to do, but what you want to do seems like it's asking for trouble. @schwobaseggi对你想做的事情有最直接的答案,但是你想要做的事情似乎是在寻找麻烦。 You have one class that does two very different things. 你有一个课做两件非常不同的事。 Animal is an animal that has a name and eats, and it also keeps track of every animal instance and makes all of them eat. Animal是有一个名字和吃动物, 而且它也使每一种动物实例的轨道,使所有的人吃。 Animal is trying to do what individual animals do and also control a group of animals. Animal正试图做个体动物所做的事情并控制一群动物。

It might be better to split this into two different kinds of objects: An animal, and some sort of AnimalGroup like Zoo or Farm or Herd . 将它分成两种不同的对象可能更好:一种动物,以及某种AnimalGroupZooFarmHerd The AnimalGroup class should be responsible for keeping track of a bunch of instances and make them all do stuff. AnimalGroup类应该负责跟踪一堆实例并让它们全部完成。

class AnimalGroup(object):
    def __init__(self, animal_list):
        self.animals = animal_list[:]  

    def add_animal(self, animal):
        self.animals.append(animal)

    def all_eat(self):
        for animal in self.animals:
            animal.eat()

then 然后

dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
group = AnimalGroup([dog, cat, giraffe])
group.all_eat()
group.add_animal(Animal("pig"))
group.all_eat()

This separates out the responsibilities of each class and makes things much easier to change later on. 这将每个类的职责分开,并使以后更容易更改。 You can now have different group behaviors without ever needing to change the animal class. 您现在可以拥有不同的群体行为,而无需更改动物类别。 You can have new animal classes that inherit from Animal and you don't need to worry about side effects. 您可以拥有从Animal继承的新动物类,您无需担心副作用。 for example: class Mammal(Animal) . 例如: class Mammal(Animal) When I call Mammal.eat , will it update all animals? 当我打电话给Mammal.eat ,它会更新所有动物吗? It might. 它可能。 class variables can be a bit tricky like that. 类变量可能有点棘手。 Should it update all animals? 它应该更新所有动物吗? No idea. 不知道。 With an AnimalGroup object, you don't need to worry. 使用AnimalGroup对象,您无需担心。

If you're wanting to do something on the class you have to declare it as a class variable: 如果您想要在类上执行某些操作,则必须将其声明为类变量:

class Animal:
  hunger = 0

  def __init__(self, name=""):
    self.name = name

  @classmethod
  def eat(klass):
    klass.hunger += 1

This way anytime you call Animal.eat() you'll be referencing the class method that modifies your class variable. 这样,只要你调用Animal.eat()你就会引用修改类变量的类方法。 You can still access the variable from within an Animal class with self.hunger but I would advise against that as it can get confusing coming back and trying to determine what's a class variable and what's a member variable. 您仍然可以使用self.hunger从Animal类中访问该变量,但我建议不要这样,因为它可能会让人感到困惑,并尝试确定什么是类变量以及什么是成员变量。

To the best of my knowledge (and I really like OOP in python), the only way to do this is to create a new class with that specific attribute aka 据我所知(我非常喜欢python中的OOP),唯一的方法是创建一个具有该特定属性的新类

class Animals:
    def __init__(self, animals):
        self.animals = animals
    def all_eat(self):
        for animal in animals:
            animal.eat()

Then what you would have to do is: 然后你需要做的是:

dog = Animal("dog")
cat = Animal("cat")
giraffe = Animal("giraffe")
animals = Animals((dog, cat, giraffe))
animals.all_eat()

The reason for this is that python classes themselves do not have callable attributes so you have to call each instance of the class separately. 原因是python类本身没有可调用的属性,因此您必须分别调用该类的每个实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM