2015-05-21 2 views
3
class vehicles: 
    class car: 
     def drive(): 
      pass 

car1 = car() 
car2 = car() 
car3 = car() 

Есть ли способ, которым я могу вызвать функцию привода на всех автомобилях за один вызов, не называя их явно.Вызов метода во всех экземплярах объекта

+1

вы должны [следить за всеми экземплярами у вас есть] (http://stackoverflow.com/questions/12101958/keep-track-of-instances -in-python) –

+1

Все сразу, вы имеете в виду параллельно? Или один за другим? –

+1

Отмеченный код имеет синтаксическую ошибку. 'car1 = vehicles.car()' вызовет конструктор. – Paul

ответ

5

Если вы действительно этого хотите, вы должны создать его в своей модели - так, например, у вас есть реестр всех созданных автомобилей.

Это не трудно, что нужно сделать - я думаю, что самый очевидный способ настроить метод __new__ в своем классе, чтобы сохранить этот реестр, и сделать звонки:

class Base: 
    def __new__(cls, *args, **kw): 
     self = super.__new__(*args, **kw) 
     if not hasattr(cls, _instances): 
      cls._instances = [] 
     cls._instances.append(self) 
     return self 

    @classmethod 
    def call_all(cls, method_name, *args, **kw): 
     results = [] 
     for instance in cls._instances: 
      results.append(getattr(instance, method_name)(*args, **kw)) 
     return results 

    def __del__(self): 
     self.__class__._instances.remoce(self) 

class vehicles: 
    class car(Base): 

     def drive(): 
      pass 

car1 = car() 
car2 = car() 
car3 = car() 

car.call_all("drive") 

Другой способ, так как это вещи на уровне класса, которые должны поддерживаться при создании классов, которые могут быть рассмотрены в метаклассах. Хорошее: оно было бы «чистым», и у вас не было бы специальной обработки, которая возникает, когда вы создаете экземпляр первого объекта этого класса, как указано выше. Плохие: классы с разными метаклассами трудно комбинировать - и , если у вас есть иерархия классов, в которой некоторым классам требуется такое поведение, а некоторые из них не делают этого на уровне класса, все взаимозаменяемо.

Собственно, обратите внимание, что создание суперкласса Base является необязательным шагом. Если вы используете его только в одном месте во всем своем проекте, логика вполне может быть внутри самого класса car (как в ответе на Нарцисе, ниже).

Если вы не хотите этого делать , вы можете использовать модуль сбора мусора (gc), чтобы узнать все экземпляры вашего объекта и вызвать метод на них. Я не думаю, что это было бы ледяной штукой, так как сама gc представляет собой детальную реализацию реализации cPython для .

import gc 

... 
for obj in gc.get_referrers(car): 
    if not isinstance(obj, car): continue 
    obj.drive() 

или некрасиво Oneliner:

[getattr(obj, "drive")() for obj in gc.get_referrers(car) if isinstance(obj, car)] 
+1

Зачем настраивать' __new__' и вместо '__init__'? –

+0

Это можно сделать с помощью '__init__', я думаю, но поскольку это будет возиться только с атрибутами класса, а класс derirved, возможно, захочет использовать' __init__' для других целей, я думаю, что это улучшает разделение. Это скорее чувство, чем «вы должны это делать». – jsbueno

+0

Зачем создавать базовый класс, когда класс 'vehicle' выглядит так, как будто он предназначен для размещения типов транспортных средств? –

1

Чтобы ответить на ваш вопрос, да, есть способ. Вы можете использовать class variable для отслеживания экземпляров.

class vehicles: 

    working_vehicles = [] # this is a class variable 

    class car: 
     def __init__(self): 
      vehicles.working_vehicles.append(self) # adds itself to working_vehicles 

     def drive(self): 
      pass 

Затем вы можете создавать экземпляры и получать к ним доступ от vehicles.working_vehicles.

Демо:

Сначала создайте машины:

>>> car1 = vehicles.car() 
>>> car2 = vehicles.car() 
>>> car3 = vehicles.car() 

Затем к ним доступ из vehicles.working_vehicles.

>>> print(vehicles.working_vehicles) 
[<__main__.vehicles.car object at 0x022DF6F0>, <__main__.vehicles.car object at 0x01E97ED0>, <__main__.vehicles.car object at 0x01EAA6B0>] 

Что не очень полезно визуально, но вы можете вызвать метод drive на все автомобили, как это:

>>> for car in vehicles.working_vehicles: 
...  car.drive() 

Или в одной строке:

>>> map(lambda car: car.drive(), vehicles.working_vehicles) 

Которая не сразу приведет в движение автомобили.Вам нужно будет позвонить list на итераторе map.

+0

Обратите внимание, что 'map' возвращает итератор в Python 3, который сразу не будет приводить в движение автомобили, в отличие от' list' в Python 2, который будет немедленно двигаться. – Navith

3
class Vehicule(): 

     pos, child = 0, [] 

     def __init__(self): 
      self.__class__.child.append(self) 
      self.pos = self.__class__.pos 
      self.__class__.pos +=1 

     def cond(self): 
      print self.pos 

     @classmethod 
     def drive(cls): 
      for v in cls.child: 
       v.cond() 

испытания:

t = Vehicule() 
c = Vehicule() 
g = Vehicule() 
Vehicule.drive() 

>>0 
>>1 
>>2 
+1

приятный, простой ответ - вы можете использовать «@classmethod» вместо «staticmethod» и использовать cls.child вместо transportule.child, что также сделает его работу с подвалами, среди других преимуществ. – jsbueno

Смежные вопросы