我实现了一个元类,它删除了用它创建的类的类属性,并从这些参数的数据构建方法,然后将这些动态创建的方法直接附加到类对象(有问题的类允许轻松定义Web表单对象,用于Web测试框架)。它已经工作得很好,但现在我需要添加一个更复杂的方法类型,为了保持干净,我实现了一个可调用的类。不幸的是,当我尝试在一个实例上调用可调用类时,它被视为一个类属性而不是实例方法,并且在被调用时,只接收它自己的self
。我可以看出为什么会发生这种情况,但我希望有人可能比我提出的更好的解决方案。问题的简化说明:
class Foo(object):
def __init__(self, name, val):
self.name = name
self.val = val
self.__name__ = name + '_foo'
self.name = name
# This doesn't work as I'd wish
def __call__(self, instance):
return self.name + str(self.val + instance.val)
def get_methods(name, foo_val):
foo = Foo(name, foo_val)
def bar(self):
return name + str(self.val + 2)
bar.__name__ = name + '_bar'
return foo, bar
class Baz(object):
def __init__(self, val):
self.val = val
for method in get_methods('biff', 1):
setattr(Baz, method.__name__, method)
baz = Baz(10)
# baz.val == 10
# baz.biff_foo() == 'biff11'
# baz.biff_bar() == 'biff12'
我想到了:
foo
的工厂内使用闭包,但嵌套的闭包是大多数时候对象的丑陋和凌乱的替换,imo Foo
实例包含在将self
向下传递给Foo
实例instance
的方法中,基本上是一个装饰器,这就是我实际添加到{ {1}},但这似乎是多余的,基本上只是一种更复杂的方式来做同样的事情(2)有没有比这些更好的方法来尝试完成我想要的东西,或者我应该咬紧牙关并使用一些封闭工厂类型模式?
答案 0 :(得分:4)
执行此操作的一种方法是将可调用对象作为未绑定方法附加到类。方法构造函数将使用任意可调用对象(即具有__call__()
方法的类的实例) - 而不仅仅是函数。
from types import MethodType
class Foo(object):
def __init__(self, name, val):
self.name = name
self.val = val
self.__name__ = name + '_foo'
self.name = name
def __call__(self, instance):
return self.name + str(self.val + instance.val)
class Baz(object):
def __init__(self, val):
self.val = val
Baz.biff = MethodType(Foo("biff", 42), None, Baz)
b = Baz(13)
print b.biff()
>>> biff55
在Python 3中,没有未绑定的实例(类只附加了常规函数),因此您可以改为使Foo
类成为一个描述符,通过赋予它{{1 }} 方法。 (实际上,这种方法也适用于Python 2.x,但上面的方法会更好一些。)
__get__()
答案 1 :(得分:1)
你遇到的麻烦是你的对象没有被绑定为你所使用的Baz类的方法。这是因为它不是描述符,which regular functions are!
您可以通过向__get__
类添加一个简单的Foo
方法来解决此问题,该方法在将其作为描述符进行访问时将其作为方法:
import types
class Foo(object):
# your other stuff here
def __get__(self, obj, objtype=None):
if obj is None:
return self # unbound
else:
return types.MethodType(self, obj) # bound to obj