Как я могу сгенерировать несколько объектов, используя один и тот же класс с разными атрибутами? - PullRequest
0 голосов
/ 05 мая 2020

Я работаю над пакетом Python для онлайн-систем и начал реализовывать декораторы, которые работают следующим образом:

@Service
class MyCode ():
  # This will run once on beginning
  def setup (self):
    pass
  # This will run once on every loop
  def main (self):
    pass
  # This will run on an exclusive thread forever (or until program shuts down)
  def loop (self):
    pass

и хотел реализовать декоратор Swarm, например

@Swarm (10)
class MyCode ():
  pass

сгенерирует 10 экземпляров MyCode с именами от MyCode_O до MyCode_9, каждый из которых отличается друг от друга.

Мой Service декоратор отлично работает для отдельных экземпляров, и он вот так:

from copy import deepcopy

class Service ():
  def __init__ (self, obj, context = None, name=None):
    @wraps(obj)
    def init(obj, context = None):
      try:
        if name:
          self.__name = name
        else:
          self.__name = obj.name
      except:
          self.__name = obj.__name__
      self.__context = context
      self.__rawObj = deepcopy(obj)
      self.__obj = deepcopy(obj)
      self.__obj.__init__(self.__obj)
      self.__obj.MSG_VERBOSE  = self.MSG_VERBOSE
      self.__obj.MSG_DEBUG    = self.MSG_DEBUG
      self.__obj.MSG_INFO     = self.MSG_INFO
      self.__obj.MSG_WARNING  = self.MSG_WARNING
      self.__obj.MSG_ERROR    = self.MSG_ERROR
      self.__obj.MSG_FATAL    = self.MSG_FATAL
      try:
        self.seed = self.__obj.seed
      except:
        self.seed = 0
      self._active = True
    return init(obj, context=None)

Этот self.seed предназначен только для отладки.

Я пытался реализовать Swarm вот так:

class Swarm ():
  def __init__ (self, size=1, obj=None, context=None):

    self.__context = context
    self.__services = []
    self.__name = "Otools Swarm <None>"
    self.__size = size
    if obj:
      self.__call__(obj)
    self._active = True

  def __call__ (self, obj, context=None, index=None):

    @wraps(obj)
    def init(obj, index=0):
      obj.__init__(obj)
      new_obj = deepcopy(obj)
      self.__rawObj = deepcopy(new_obj)
      self.__name = new_obj.__name__
      new_obj.name = "{}_{}".format(new_obj.__name__, index)
      svc = Service(new_obj)
      self.__services.append(svc)

    for i in range(self.size):
      init(obj, i)

    for service in self.__services:
      print ("SERVICE_DATA:", service.name, service.seed)
      print ("OBJ_DATA:", service.obj.name, service.obj.seed)

    return self

но потом те print s покажет мне это:

SERVICE_DATA: SwarmTest_0 2199
OBJ_DATA: SwarmTest_4 2643
SERVICE_DATA: SwarmTest_1 4148
OBJ_DATA: SwarmTest_4 2643
SERVICE_DATA: SwarmTest_2 1438
OBJ_DATA: SwarmTest_4 2643
SERVICE_DATA: SwarmTest_3 1341
OBJ_DATA: SwarmTest_4 2643
SERVICE_DATA: SwarmTest_4 2643
OBJ_DATA: SwarmTest_4 2643

Я пробовал добавлять deepcopy во многих местах, пытался не вызывать __init__ на объекте, и я не знаю, что еще делать.

1 Ответ

0 голосов
/ 06 мая 2020

Благодаря @chepner у меня возникла идея и я исправил ее.

Мое решение:

Service.py

class Service ():
  """
  A Service is a class that shall encapsulate your own class in order to 
  attach it into a context. It has four core methods: "setup", 
  "main", "loop" and "finalize". The "setup" method will run once.
  The "main" method will run once every execution loop on the main
  thread. The "loop" method will loop forever, unless the service is
  diabled. The "finalize" method will run when the program shuts down.
  """

  def __init__ (self, obj, context = None, name=None):
    @wraps(obj)
    def init(obj, context = None):
      self.__obj = obj()
      self.__context = context
      self.__rawObj = deepcopy(obj)
      try:
        if name:
          self.__name = name
        else:
          self.__name = self.__obj.name
      except:
          self.__name = self.__obj.__class__.__name__
      self.__obj.name = self.__name
      self.__obj.MSG_VERBOSE  = self.MSG_VERBOSE
      self.__obj.MSG_DEBUG    = self.MSG_DEBUG
      self.__obj.MSG_INFO     = self.MSG_INFO
      self.__obj.MSG_WARNING  = self.MSG_WARNING
      self.__obj.MSG_ERROR    = self.MSG_ERROR
      self.__obj.MSG_FATAL    = self.MSG_FATAL
      self._active = True
    return init(obj, context=context)

Swarm.py

class Swarm ():
  """
  A Swarm helps deploying multiple similar Service objects
  by handling everything the user should do in order to deploy
  them with much fewer lines of code.
  """

  def __init__ (self, size=1, obj=None, context=None):

    self.__context = context
    self.__services = []
    self.__name = "Otools Swarm <None>"
    self.__objName = None
    self.__size = size
    if obj:
      self.__call__(obj)
    self._active = True

  def __call__ (self, obj, context=None, index=None):

    @wraps(obj)
    def init(obj, index=0):
      self.__objName = obj.__name__
      new_obj = deepcopy(obj)
      self.__rawObj = deepcopy(new_obj)
      new_obj.name = "{}_{}".format(self.__objName, index)
      svc = Service(new_obj)
      self.__services.append(svc)

    for i in range(self.size):
      init(obj, i)

    return self

и работает нормально.

Полный код: https://github.com/gabriel-milan/otools

...