【问题标题】:Dispatch a function call to a collection of objects将函数调用调度到对象集合
【发布时间】:2020-06-30 01:04:30
【问题描述】:

我不确定问题的标题是否正确。

我正在努力实现以下目标。


class A():
   def __init__(self, name):
       self.name = name
    
   def foo1(self):
       print(1, self.name)

   def foo2(self):
       print(2, self.name)

a1 = A('a1')
a1.foo1() # print '1, a1'

a2 = A('a2')
b = SomeFoo(a1, a2)  # or, SomeFoo([a1, a2])
b.foo1()  # calls a1.foo1(), a2.foo2() 

同样,

b.foo2() 应该调用a1a2foo2。我猜np.vectorize 是类似的东西。

这个潜在的SomeFoo(类或函数)会被调用什么?

更重要的是,写SomeFoo的好方法是什么?

更新

printprintB 替换为foo1foo2

【问题讨论】:

  • 过去对类似问题的回答(例如Idiomatic way to call method on all objects in a list of objects Python 3)通常说只是为了使用for循环。另请参阅How to call same method for a list of objects?
  • 谢谢@DennisSparrow。我想someFoo(a1, a2, a3, a4).bar() 打电话给a1.bar(), ..., a4.bar()。我希望someFoo 不需要声明bar。不确定是否可以不侵入类属性。
  • Dilawar,实际上,我想知道您是否正在寻找比您得到的答案更笼统的东西,所以很高兴您能澄清它。我的猜测是它不能完全按照你指定的方式完成,但是像b.callMethod("foo1") 这样的变体可能是可能的。

标签: python-3.x


【解决方案1】:

为了满足您对通用性的渴望,请考虑这个类:

class SomeFoo:
    def __init__(self, *args):
        self.objects = [*args]

    def callMethod(self, methodName):
        for object in self.objects:
            if hasattr(object, methodName):
                method = getattr(object, methodName)
                if callable(method):
                    method()

(我不明白你为什么问它叫什么名字。你可以随意命名它。我称它为 SomeFoo 以匹配你的问题。)

你会像这样使用这个类:

b = SomeFoo(a1, a2)  
b.callMethod("foo1")
b.callMethod("foo2")

这种设计不要求 SomeFoo 事先知道要调用的任何函数的名称,甚至不要求所有参数对象都属于同一个类。如果其中一个对象没有指定的方法,它将被无声无害地绕过。

如您所料,它需要“侵入类属性”。

当然,例如,如果一个对象有一个需要参数的名称正确的方法,这可能会失败。这可以用一些额外的代码来检查。

编辑:自从发布上面的答案后,我发现可以支持问题中指定的b.foo1()调用接口。如果有人关心,我可以发布代码。

【讨论】:

    【解决方案2】:

    有点不清楚您要达到的目标,但我猜我猜。

    A() 的每次调用都会创建一个实例。您正在尝试做的事情要求每个实例彼此了解——即,它们具有类共有的属性。

    例子:

    class A():
        members={}
        def __init__(self, name, func=lambda e: print(self.name)):
            self.name = name
            self.members[name]=func
    
        def __del__(self):
            del self.members[self.name] 
    
        def do_all(self):
            for k, func in self.members.items():
                print(k)
                func() 
            
    a=A('a1', lambda: print('I am the great and powerful OZ'))  
    b=A('b1', lambda: print('paCHOO!')) 
    
    b.do_all()
    

    在实践中:

    a=A('a1', lambda: print('I am the great and powerful OZ'))  
    b=A('b1', lambda: print('paCHOO!')) 
    
    b.do_all()
    

    打印:

    a1
    I am the great and powerful OZ
    b1
    paCHOO!
    

    【讨论】:

      【解决方案3】:

      你使用的语法:

      b = someFoo(a1, a2)
      b.print()
      

      使它看起来像你想使用一个类,但根据你所描述的功能,我认为实现这一点的最简单方法是使用一个函数。它使您不必编写一个类,并且您可以在一行上启动打印,而不是需要两行。

      我添加了一个类型提示(List[A])让函数更清晰,但这不是必需的,在python 3之前不支持。

      from typing import List
      
      def someFoo(classAs: List[A]) -> None:
          for a in classAs:
              a.printB()
      
      a1 = A('a1')
      a2 = A('a2')
      someFoo([a1, a2])
      

      【讨论】:

        【解决方案4】:
        class b:
            def __init__(self, *args):
                self.thelist = *args
            def print(self):
                [print(i) for i in self.thelist]
        

        没有?

        【讨论】:

        • 不,应该是i.print(),而不是print(i)。否则OK。
        • Don't use comprehensions for side effects。请改用普通的 for 循环。
        • 执行:'\n'.join([str(i) for i in self.thelist]) 而不是 [print(i) for i in self.thelist]
        • “不”是什么意思?您能否为您的答案添加一些解释,以便其他人可以从中学习?
        • 您好!虽然这段代码可以解决问题,including an explanation 解决问题的方式和原因确实有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案添加解释并说明适用的限制和假设。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多