【问题标题】:how to construct methods dynamically?如何动态构造方法?
【发布时间】:2018-11-05 08:29:00
【问题描述】:

我设计了一个类。很标准,有一些方法属性

class foo:
   def f1(self):
      print 'f1'
   def f2(self):
      print 'f2'
   ....
   def fn(self):
      print 'fn'

现在我想创建一个包含一组 foo 实例的类。

class bar:
  self.myfoos=[foo(),foo(),foo()]

然后我想对所有 foo 实例的 f1..fn 方法进行分类。 我可以这样做:

   class bar:
   ...
   def f1():
     for foo_ in self.myfoos:
        foo_.f1()

但是,我的f1..fn 列表很长,所以我怎样才能以简洁的方式获得这种行为?也许完全可以使用替代设计?

【问题讨论】:

  • 您所说的“f 列表”是什么意思?功能?
  • 是的,我指的是 foo 的所有功能。我正在编辑以澄清
  • 我不确定我是否理解您的问题。你能读一下我的回答,告诉我这是否是你要找的吗?

标签: python class oop


【解决方案1】:

您可以只实现__getattr__ 并将该调用委托给foos 列表。我确信有一种更优雅的方法可以做到这一点:

class foo:
    def f1(self):
        print('f1')
    def f2(self):
        print('f2')

class bar:
    def __init__(self):
        self.foos = [foo() for _ in range(3)]
    def __getattr__(self, fn):
        def fns(*args, **kwargs):
            for f in self.foos:
                getattr(f, fn)(*args, **kwargs)
        return fns

In []:
b = bar()
b.f1()

Out[]
f1
f1
f1

In []:
b.f2()

Out[]:
f2
f2
f2

【讨论】:

  • 这正是我想要的。但是有了这个解决方案,我还能在 bar 中拥有不在 foo 中的方法吗?
  • 是的,__getattr__() 仅在AttributeError 被抛出时被调用。因此,如果您在 bar 中定义 def b1(self),那么 b.b1() 将按预期工作。
【解决方案2】:

您正在寻找一种动态构造一堆方法的方法。这通常不是一个好主意,但有时确实如此。 (例如,考虑像 PyObjC 和 pythoncom 之类的库,它们为 ObjC 和 COM 类构建动态代理,直到运行时你才知道。你还能怎么做?)

所以,你绝对应该考虑一下你是否真的想要和需要这个——但是,如果你这样做了,有两种基本方法。

动态构建静态类

如果您只是想包装foo 对象的集合,您可以在循环中创建所有方法。方法没什么太神奇的。您只需将它们定义为与任何其他函数相同,然后将它们分配给类。

唯一棘手的一点是你不能只写bar.f1 = …,因为f1 只能作为字符串使用。所以我们必须使用setattr来做到这一点:

class bar:
    # your existing stuff
for name in 'f1 f2 f3 f4 f5 f6 f7 f8'.split():
    foometh = getattr(foo, name)
    def f(self):
        for foo in self.myfoos:
            foometh(foo)
    f.__name__ = name
    setattr(bar, name, f)

如果有某种规则指定您要转发哪些方法,而不是一堆方法名称的列表,您可以这样做:

for name, foometh in inspect.getmembers(foo):
    if name.startswith('_') or not isinstance(foometh, types.FunctionType)) or <rest of your rule>:
        continue
    def f(self):
        # from here it's the same as above

静态构建动态类

如果您试图总结任何符合某些基本条件的东西,而不是某些特定类的特定方法列表,您将不知道要总结什么,或者你想如何包装它,直到有人试图调用这些方法。因此,您必须抓住查找未知方法的尝试,并即时构建包装器。为此,我们覆盖__getattr__

class bar:
    # your existing stuff
    def __getattr__(self, attr):
        if attr.startswith('_') or <other rules here>:
            raise AttributeError
        def f():
            for foo in self.myfoos:
                foometh(foo)
        f.__name__ = attr
        return f

如果您不仔细观察,此版本返回的函数类似于绑定方法,而不是可以自省的实际绑定方法。如果您想要后者,请显式绑定一个方法,将self 作为参数添加到f,然后在f 上调用__get__ 并返回结果。 (如果你不知道这意味着什么,你就不想写这部分……)

【讨论】:

    猜你喜欢
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-14
    相关资源
    最近更新 更多