我想用自定義的__init__
函數生成一個類。動態生成python中的默認kwargs函數
例如:
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)
但前一個可以做2件更多的事情:
- 的
__init__
應該只接受a
,b
,c
- 我可以
A(2, 'bar')
和a
,b
調用它,c
被分配以正確的順序。
所以我真的想要生成一個有序的默認kwargs函數。
看來這個函數可以用types.FunctionType和co_varnames和defaults來構建,但是很難找到文檔和樣例。
這樣做的最好方法是什麼?
更新:
我得到這個實現自己經過一番努力
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()這一點。 – RemcoGerlich
除了驗證參數名稱之外,使用eval進行此操作的複雜性在於,您不能只將字符串格式化爲默認值。 '0xwhere處的對象對象>'不是用於默認參數的有效代碼。您必須生成變量來保存默認值。它可能會有點混亂。 – user2357112