首页 > 解决方案 > 动态定义类的 __init__ 参数(使用先前定义的字典)

问题描述

有没有办法使用字典来定义类的参数?

例如,假设我有一个包含一堆键值对的字典。每个键都应该是类的一个参数,每个值应该是该参数的默认值。

在代码方面,我正在寻找这样的东西:

d = {'apples':0,'bananas':1}
class A:
    def __init__(self,k=v for k,v in d.items())
        print('apples',apples)
        print('bananas',bananas)
A(4)

应该输出:

-> apples 4
-> bananas 1

标签: pythonclassdynamic

解决方案


您询问:

有没有办法使用字典来定义类的参数?

确实是这样。动态构建类通常使用所谓的元类来完成,即实例是其他类的类。

下面是一个做你想做的事的例子。除了__init__()使用字典定义类的方法的参数外,它还生成方法的主体,该主体仅打印出其所有参数及其值。我添加了这个是因为你从来没有回答我在评论中问你是否想要完成这个问题。

简而言之,它的作用是生成定义函数所需的源代码,该函数具有所需的参数,然后是打印它们的代码行。完成后,使用内置exec()函数执行代码以获得执行结果(即函数对象的可执行字节码)。"__init__"最后,一个带有可执行字节码键和值的字典条目被添加到类的字典 ( classdict) 中,然后将其传递给内置type()函数以构造成可用class对象。

呸!解释比代码更复杂。;¬)

class MyMetaClass(type):
    def __new__(cls, name, bases, classdict, **kwargs):
        initargs = classdict.pop('initargs', None)
        if not initargs:
            INIT_METHOD = f"def __init__(self):\n\tprint('{name}.__init__() called')\n"
        else:
            args = ", ".join(f"{k}={v}" for (k, v) in initargs.items())
            body = "\n".join(f"\tprint({k!r}, {k})" for k in initargs.keys())
            INIT_METHOD = (f'def __init__(self, ' + f'{args}' + '):\n'
                           f'\tprint("{name}.__init__() called")\n'
                           f'{body}\n')
        result = {'__builtins__' : None, 'print': print}  # Must explicitly list any builtins.
        exec(INIT_METHOD, result)
        init_method = result['__init__']
        classdict.update({'__init__': init_method})
        return type.__new__(cls, name, bases, classdict, **kwargs)


class A(metaclass=MyMetaClass):
    initargs = {'apples': 0, 'bananas': 1}


A(4)

输出:

A.__init__() called
apples 4
bananas 1

推荐阅读