Python 动态添加可调用类作为实例";方法“;
我实现了一个元类,该元类可以删除用它创建的类的类属性,并从这些参数的数据中构建方法,然后将这些动态创建的方法直接附加到类对象(该类允许轻松定义web测试框架中使用的web表单对象)。它一直工作得很好,但现在我需要添加一种更复杂的方法,为了保持整洁,我将其实现为一个可调用类。不幸的是,当我尝试调用实例上的可调用类时,它被视为类属性而不是实例方法,并且在调用时,只接收它自己的Python 动态添加可调用类作为实例";方法“;,python,class,methods,callable,Python,Class,Methods,Callable,我实现了一个元类,该元类可以删除用它创建的类的类属性,并从这些参数的数据中构建方法,然后将这些动态创建的方法直接附加到类对象(该类允许轻松定义web测试框架中使用的web表单对象)。它一直工作得很好,但现在我需要添加一种更复杂的方法,为了保持整洁,我将其实现为一个可调用类。不幸的是,当我尝试调用实例上的可调用类时,它被视为类属性而不是实例方法,并且在调用时,只接收它自己的self。我知道为什么会这样,但我希望有人能找到比我想出的更好的解决方案。问题的简化说明: class Foo(object)
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
使用闭包,但是嵌套闭包在大多数情况下都是丑陋而混乱的对象替换Foo
实例包装在一个方法中,该方法将其自身
传递给Foo
实例作为实例
,基本上是一个装饰器,这是我实际添加到Baz
中的内容,但这似乎是多余的,基本上只是一种与(2)相同的更复杂的方法有没有比这些更好的方法来实现我想要的,或者我应该咬紧牙关,使用某种闭包工厂类型模式呢?一种方法是将可调用对象作为未绑定方法附加到类上。方法构造函数将处理任意可调用项(即具有
\uuuu call\uuuu()
方法的类的实例),而不仅仅是函数
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
在Python3中,没有未绑定实例(类只是附加了常规函数),因此您可以将Foo
类作为一个描述符,通过给它一个\uuuu get\uuuu()
方法来返回绑定实例方法。(实际上,这种方法在Python2.x中也可以使用,但是上面的方法性能会更好一些。)
您遇到的问题是,您的对象没有被绑定为所放入的Baz类的方法。这是因为它不是一个描述符 您可以通过向
Foo
类添加一个简单的\uuuuu get\uuuu
方法来解决此问题,该方法在作为描述符访问时使其成为一个方法:
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
这在Python 3中不起作用,因为未绑定的方法不再存在(
MethodType
只接受两个参数,第二个参数不能是None)。我想在您编写注释时我正在更新它。:-)我以前写过描述符,但我想在这种情况下,描述符没有那么凌乱,真的。。。我以前曾尝试过MethodType
,但老实说,它总是让我感到害怕,因为它似乎很容易被破坏,需要基本上初始化它的名称空间等等。我最终实现了另一个闭包,但我可能会回头看看用这个来替换它。谢谢。MethodType
真的没有那么复杂。您需要一个函数(或其他可调用函数)、一个实例(如果您正在创建实例方法;在Python3中,这是唯一可以创建的类型)和一个类型(在Python2.x中;在Python3中,它从实例获取类型)。就是这样。我认为您不需要在其中使用if/else
,因为当通过类访问Foo
实例时,\uu get\uu()
不会被调用。@kindall:如果我没有if
块,我通过类访问Foo
实例时遇到异常:TypeError:self不能为None
。这就是Python 3中仍然存在的“类绑定”,尽管函数不再使用它来生成未绑定的方法。
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