如何在元类的__init__方法中将方法绑定到类?
最后编辑
我的问题是我试图将一个部分方法绑定到一个类上。不确定我是否应该删除这个问题,或者改一下标题。
原始问题
我知道在元类中将方法绑定到类的“正确”方式是把它添加到元类的 __new__
方法里的 classdict
参数中。一般来说,你可以通过简单地将方法赋值给类来绑定一个实例方法。
但是,在我的使用场景中,我需要在元类的 __init__
方法中将一个方法绑定到类上。问题是,通常的赋值方法不起作用。这个函数虽然被赋值给了类,可以通过 ClassName.function_name
或 class_instance.function_name
来访问,但它并没有真正绑定到类上,第一参数也没有设置为 self
。
我猜这是因为在元类的 __init__
方法中,类还没有完全初始化,但有没有什么办法可以解决这个问题呢?
编辑:代码示例
给定:
def fun(self):
pass
class MetaClass(type):
def __init__(cls, name, bases, dct):
pass
class Class(object):
__metaclass__ = MetaClass
我想在 MetaClass.__init__
中将 fun
绑定到 Class
,这样调用
instance = Class()
instance.fun()
时,instance
会作为第一个参数传递给 fun
。
第二次编辑
显然,问题出在我试图绑定一个部分方法上。不知道为什么这样会造成问题。
我会稍后确认一下,如果有必要会更新或删除这个问题。
2 个回答
问题在于,元类的 __new__
方法已经调用了 type.__new__
,这个过程会把类字典里的函数变成未绑定的方法,这是构建类对象的一部分。
你可以使用 types
模块来构建方法。你的代码大概会是这样的:
import types
def fun(self):
pass
class MetaClass(type):
def __init__(cls, name, bases, dct):
cls.fun = types.MethodType(fun, None, cls)
class Class(object):
__metaclass__ = MetaClass
注意:这适用于 Python 2,我不知道在 Python 3 中是否有变化。
在 metaclass.__new__()
和 metaclass.__init__()
之间几乎没有区别;它们都是在处理类对象。
__new__
用来生成新的对象,而 __init__
则可以对这个对象进行修改。整个过程大致是这样的:
new_class_obj = YourMeta.__new__(YourMeta, name, bases, bodydict)
YourMeta.__init__(new_class_obj, name, bases, bodydict)
当你想在新的类对象上添加函数时(通过 bodydict
或直接在类对象上赋值),其实没有任何区别。
如果你在设置类对象上的函数时遇到问题,你需要确保你设置的是实际的函数对象。
比如说,如果你使用的是 绑定方法,你需要将这个方法解包,只提取出函数本身:
new_class_obj.name = method_obj.__func__
如果你在类上添加的是 普通函数对象,那么在实例访问时它们会自动绑定,你不需要做额外的工作。
总之,你需要添加 某种东西,它能充当一个 描述符,具体来说,就是一个能通过 descriptor.__get__
方法返回方法对象的描述符。这正是普通函数对象的作用。
而 functools.partial()
对象 不是 这样的描述符。最简单的办法是把这个部分函数包裹在一个函数里(这里用 lambda
就可以):
new_class_obj.name = lambda *args, **kw: partial_obj(*args, **kw)