在Python 3中使用元类重新定义__init__是什么意思?

4

我正在学习Python 3中的元编程。我的教授给了我们这个练习:

编写名为Spell的元类,将Student的实例转换为Wizard。

我完成了以下代码:

class Spell(type):
    def __new__(cls, classname, supers, cls_dict):
        cls_dict['__init__'] = Spell.toWizard()
        cls_dict['__qualname__'] = 'wizard'
        return type.__new__(cls, 'wizard', supers, cls_dict)

    @staticmethod
    def toWizard():
        def init(*args):
            wizard(args, 'fire_spell')
        return init    

class student(metaclass=Spell):
    def __init__(self, name):
        self.name = name

class person():
    def __init__(self, name):
        self.name = name

class wizard(person):
    def __init__(self, name, magic):
        self.magic = magic
        super().__init__(name)



if __name__ == '__main__':
    s = student('name1')
    print(s.__dict__)
    s = student('name2')
    print(s.__dict__)

在我的代码中,巫师类的__init__正确调用,而不是学生类的__init__,但是创建的对象具有空的__dict__。我做错了什么?

1个回答

7
您的init()替代函数会创建一个本地的wizard()实例,并且不会返回任何内容:
def init(*args):
    wizard(args, 'fire_spell')

这是一个独立的实例,self 没有被触碰。

不要使用__new__; 那会生成一个新类。您只是重命名了student类,并给它一个无效的__init__方法。

重写__call__方法来连接创建实例。在那里,您可以替换或忽略第一个参数,即 student 类对象,并在其位置使用 wizard 类:

class Spell(type):
    def __call__(cls, *args, **kwargs):
        # ignore the cls argument, return a wizard instead
        if 'magic' not in kwargs and len(args) < 2:
            # provide a default magic value
            kwargs['magic'] = 'fire_spell'
        return wizard(*args, **kwargs)

因为student通常只接受一个参数,所以在上面的代码中如果没有指定,会添加magic参数。

示例:

>>> student('name1')
<__main__.wizard object at 0x10f1e8198>
>>> vars(_)
{'magic': 'fire_spell', 'name': 'name1'}

@Aran-Fey:抱歉让你等了,我刚才有点事情要处理。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接