<p>您正在寻找一种动态构造一组方法的方法。这通常不是一个好主意,但有时确实是。(例如,考虑像PyObjC和pythoncom这样的库,它们为ObjC和COM类构建动态代理,而这些类直到运行时才知道)。你还能怎么做呢?)你知道吗</p>
<p>所以,你应该仔细考虑你是否真的想要和需要这个,但是,如果你真的想要,有两种基本的方法。你知道吗</p>
<h3>动态构建静态类</h3>
<p>如果您只想包装一个<code>foo</code>对象的集合,那么可以在一个循环中创建所有方法。方法并不太神奇;您只需将它们定义为与任何其他函数相同的函数,并将它们分配给类。你知道吗</p>
<p>唯一棘手的一点是不能只写<code>bar.f1 = …</code>,因为<code>f1</code>只能作为字符串使用。所以我们必须用<a href="https://docs.python.org/3/library/functions.html#setattr" rel="nofollow noreferrer">^{<cd4>}</a>来做:</p>
<pre><code>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)
</code></pre>
<p>如果有某种规则指定要转发的方法,而不是一系列方法名的列表,则可以执行以下操作:</p>
<pre><code>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
</code></pre>
<h3>静态构建动态类</h3>
<p>如果您试图包装任何满足一些基本条件的<em>内容,而不是某个特定类的特定方法列表,那么在有人尝试调用这些方法之前,您将不知道要包装什么,或者如何包装。因此,您必须捕获查找未知方法的尝试,并动态构建包装器。为此,我们重写<a href="https://docs.python.org/3/reference/datamodel.html#object.__getattr__" rel="nofollow noreferrer">^{<cd5>}</a>:</p>
<pre><code>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
</code></pre>
<p>如果不仔细观察,这个版本会返回类似于绑定方法的函数,而不是可以内省的实际绑定方法。如果需要后者,请显式绑定一个方法,方法是将<code>self</code>作为参数添加到<code>f</code>,然后在<code>f</code>上调用<code>__get__</code>,并返回结果。(如果你不知道这是什么意思,你就不想写这部分……)</p>