如何在元类的__init__方法中将方法绑定到类?

6 投票
2 回答
1716 浏览
提问于 2025-04-17 20:19

最后编辑

我的问题是我试图将一个部分方法绑定到一个类上。不确定我是否应该删除这个问题,或者改一下标题。

原始问题

我知道在元类中将方法绑定到类的“正确”方式是把它添加到元类的 __new__ 方法里的 classdict 参数中。一般来说,你可以通过简单地将方法赋值给类来绑定一个实例方法。

但是,在我的使用场景中,我需要在元类的 __init__ 方法中将一个方法绑定到类上。问题是,通常的赋值方法不起作用。这个函数虽然被赋值给了类,可以通过 ClassName.function_nameclass_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 个回答

-1

问题在于,元类的 __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 中是否有变化。

9

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)

撰写回答