首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何动态地构造方法?

如何动态地构造方法?
EN

Stack Overflow用户
提问于 2018-05-25 22:39:24
回答 2查看 72关注 0票数 1

我设计了一门课。它非常标准,有一些方法属性。

代码语言:javascript
复制
class foo:
   def f1(self):
      print 'f1'
   def f2(self):
      print 'f2'
   ....
   def fn(self):
      print 'fn'

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

代码语言:javascript
复制
class bar:
  self.myfoos=[foo(),foo(),foo()]

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

代码语言:javascript
复制
   class bar:
   ...
   def f1():
     for foo_ in self.myfoos:
        foo_.f1()

然而,我的f1..fn列表很长,所以我如何才能以一种简洁的方式获得这种行为呢?也许完全采用替代设计?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-25 23:36:16

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

代码语言:javascript
复制
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
票数 2
EN

Stack Overflow用户

发布于 2018-05-25 23:01:46

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

所以,你一定要想清楚你是否真的想要和需要这个--但是,如果你需要,有两种基本的方法。

动态构建静态类

如果您只是试图包装foo对象的集合,则可以在一个循环中创建所有方法。方法没有什么神奇之处;您只需定义它们与任何其他函数相同,并将它们分配给类。

唯一棘手的一点是,您不能只编写bar.f1 = …,因为f1只能作为字符串使用。因此,我们必须使用setattr来完成这个任务:

代码语言:javascript
复制
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)

如果有某种规则指定要转发哪些方法,而不是一组方法名称的列表,则可以执行以下操作:

代码语言:javascript
复制
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__

代码语言:javascript
复制
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__并返回结果,显式绑定方法。(如果你不知道这意味着什么,你不想写这部分…)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50537673

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档