python - Python getattr 与 joblib 并行

我有两个类,第一个是我的基本实现,第二个类使用第一个类并使用 joblib 的 Parallel 调用它的方法,这样它会是这样的:

class MyClass:
    def __init__(self, param_list: list):
        self.param_list = param_list

    def method1(self, w, z):
        pass

    def method2(self, w, y, z):
        pass

现在,第二个类是这样实现的:

from joblib import Parallel, delayed

class MyParallelClass:
    def __init__(self, param_list: list[dict]):
        self.param_list = param_list

    def method1(self, x: list[dict]):
        results = Parallel(n_jobs=-1)(delayed(MyClass(**params).method1)(**arguments)
                                      for params in self.param_list
                                      for arguments in x)
        return results

    def method2(self, x: list[dict]):
        results = Parallel(n_jobs=-1)(delayed(MyClass(**params).method2)(**arguments)
                                      for params in self.param_list
                                      for arguments in x)
        return results

这行得通,但正如您所见,MyParallelClass 方法 1 和 2 本质上是相同的,唯一不同的是该方法是从 MyClass 调用的

所以我想通过一个处理并行执行的内部方法来简化这个,给定一个告诉我要执行哪个方法的参数,所以它会是这样的:

class MyParallelClass:
    def __init__(self, param_list: list[dict]):
        self.param_list = param_list

    def method1(self, x: list[dict]):
        return self._run(x, method="method1")

    def method2(self, x: list[dict]):
        return self._run(x, method="method2")
    
    def _run(self, x, method):
        pass

我该如何编写这个 _run 方法?我尝试像这样使用标准 getatrr ,但失败了:

def _run(self, x: list[dict], method):
    results = Parallel(n_jobs=-1)(delayed(getattr(MyClass(**params), method))(**arguments)
                                  for params in self.param_list
                                  for arguments in x)
    return results

但我收到此错误:

TypeError: cannot unpack non-iterable function object

回答1

这个例子是否向您解释了如何重用类方法?

class Base:

  def __init__(self, init_arg):
    self.init_arg = init_arg

  def method1(self, x):
    print(x, "from method1,", "iteration_number is", self.init_arg)
    return f"lower value is {x.lower()} [iteration number is {self.init_arg}]"

  def method2(self, x, y):
    print(x, y, "from method2,", "iteration_number is", self.init_arg)
    return f"lower values are {x.lower()}, {y.lower()} [iteration number is {self.init_arg}]"

class Executor:

  def __init__(self, init_arg):
    self.base_instance = Base(init_arg)

  def _method_base(self, method_name, *args, **kwargs):
    return getattr(self.base_instance, method_name)(*args, **kwargs)

  def method1(self, x):
    return self._method_base('method1', x)

  # here x is *args and y=y is **kwargs
  def method2(self, x, y):
    return self._method_base('method2', x, y=y)

for idx, val in enumerate([("X1", "Y1"), ("X2", "Y2"), ("X3", "Y3")]):
  executor = Executor(idx)
  _1 = executor.method1(val[0])
  _2 = executor.method2(val[0], val[1])
  print("calculated values: ", _1, _2)

输出:

X1 from method1, iteration_number is 0
X1 Y1 from method2, iteration_number is 0
calculated values:  lower value is x1 [iteration number is 0] lower values are x1, y1 [iteration number is 0]
X2 from method1, iteration_number is 1
X2 Y2 from method2, iteration_number is 1
calculated values:  lower value is x2 [iteration number is 1] lower values are x2, y2 [iteration number is 1]
X3 from method1, iteration_number is 2
X3 Y3 from method2, iteration_number is 2
calculated values:  lower value is x3 [iteration number is 2] lower values are x3, y3 [iteration number is 2]

相似文章

最新文章