我设计了一个班级。它非常标准,有一些方法属性
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
列表很长,所以我怎么能以一种简单的方式获得这种行为?可能完全采用其他设计?
答案 0 :(得分:1)
您正在寻找一种动态构建一堆方法的方法。这经常不是一个好主意 - 但有时却是。 (例如,考虑像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
,然后在__get__
上调用f
并返回结果来显式绑定方法。 (如果你不知道这意味着什么,你就不想写这部分......)
答案 1 :(得分: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