【发布时间】:2014-06-06 08:28:15
【问题描述】:
我想生成一个带有自定义__init__function 的类。
例如:
l = [('a', 1), ('b', 'foo'), ('c', None)]
生成:
class A(object):
def __init__(self, a=1, b='foo', c=None):
self.a = a
self.b = b
self.c = c
我知道这可以通过以下方式完成:
def __init___(self, **kwargs):
self.__dict__.update(kwargs)
但前一个还可以做两件事:
-
__init__应该只接受a、b、c - 我可以用
A(2, 'bar')调用它,a、b、c被分配了正确的顺序。
所以我真的很想用有序的默认 kwargs 生成一个函数。
似乎可以使用 types.FunctionType 和 co_varnames 和默认值构建函数,但是文档和示例很难找到。
最好的方法是什么?
更新:
经过一番尝试,我自己得到了这个实现
import types
def init_generator(spec):
"""Generate `__init__` function based on spec
"""
varnames, defaults = zip(*spec)
varnames = ('self', ) + varnames
def init(self):
kwargs = locals()
kwargs.pop('self')
self.__dict__.update(kwargs)
code = init.__code__
new_code = types.CodeType(len(spec) + 1,
0,
len(spec) + 2,
code.co_stacksize,
code.co_flags,
code.co_code,
code.co_consts,
code.co_names,
varnames,
code.co_filename,
"__init__",
code.co_firstlineno,
code.co_lnotab,
code.co_freevars,
code.co_cellvars)
return types.FunctionType(new_code,
{"__builtins__": __builtins__},
argdefs=defaults)
class A(object):
pass
spec = [('a', 1), ('b', 'foo'), ('c', None)]
A.__init__ = init_generator(spec)
a = A(2, c='wow!')
# {'a': 2, 'b': 'foo', 'c': 'wow!'}
print(a.__dict__)
import inspect
# ArgSpec(args=['self', 'a', 'b', 'c'], varargs=None, keywords=None, defaults=(1, 'foo', None))
print(inspect.getargspec(A.__init__))
现在唯一困扰我的是init()中的locals(),这可能不安全?
它可以改进为更好的东西吗?
【问题讨论】:
-
我很想为此使用 eval()。
-
为此使用 eval 的复杂性,除了验证参数名称之外,还在于您不能仅将默认值字符串格式化到位。
<object object at 0xwherever>不是默认参数的有效代码。您必须生成变量来保存默认值。可能会有点乱。
标签: python types metaprogramming