使用Python 2.7我需要将字典转换为类型化对象。
例如,如果我有这个词:
mapy = {'id': 1, 'name': 'bob'}
我需要一些方法在运行时根据上一个映射和类型名称(在此示例中为'Person'
)生成此类:
class Person:
def __init__(self):
self.id = id
self.name = name
我应该考虑使用元编程技术吗?如果是的话,我应该考虑哪一种(装饰器,元类,......)?
请注意,我不仅需要将字典转换为对象;我还需要将一些类型信息附加到结果对象。
答案 0 :(得分:6)
您可以尝试namedtuple
:
from collections import namedtuple
mapy = { 'id' : 1, 'name' : 'bob'}
# Note that the order of `mapy.keys()` is unpredictable.
Person = namedtuple('Person', mapy.keys())
p = Person(**mapy)
p.id
p.name
答案 1 :(得分:2)
您的请求有问题:“我不仅需要将dict转换为对象;还需要将某些类型信息附加到生成的对象中。”问题是“某些类型信息”太模糊了。最文字的实现将为每个对象创建一个新类,这几乎肯定不是你想要的。
试试这个:
def make_dict_into_object(name, d):
class Dummy(object):
def __init__(self, attr):
self.__dict__.update(attr)
Dummy.__name__ = name
return Dummy(d)
mapy = { 'id' : 1, 'name' : 'bob'}
bob = make_dict_into_object('Person', mapy)
print bob.name
mapx = { 'id' : 1, 'name' : 'steve'}
steve = make_dict_into_object('Person', mapx)
print steve.id
到目前为止这么好,对吗?但这可能不想要你想要的。运行上面的内容后,添加:
print type(steve) == type(bob)
结果将是 False ,因为make_dict_into_class
会在每次调用时生成一个新类。将“某些类型信息”附加到对象上只是愚蠢,因为它是每个对象的新类型。
有多种方法可以解决此问题,具体取决于生成对象的实际用例。一种方法是缓存新创建的类,并假设后续具有相同名称的调用引用同一个类:
class_cache = {}
def make_dict_into_object(name, d):
the_class = class_cache.setdefault(name, None)
if the_class is None:
class the_class(object):
def __init__(self, attr):
self.__dict__.update(attr)
the_class.__name__ = name
class_cache[name]=the_class
return the_class(d)
使用此版本,bob
和steve
最终会使用相同的类型:
mapy = { 'id' : 1, 'name' : 'bob'}
bob = make_dict_into_class('Person', mapy)
print bob.name
mapx = { 'id' : 1, 'name' : 'steve'}
steve = make_dict_into_class('Person', mapx)
print steve.id
print type(steve) == type(bob)
答案 2 :(得分:1)
通常,您的__init__
会有实际参数来提供属性值:
class Person:
def __init__(self, id, name):
self.id = id
self.name = name
然后你可以直接将字典解压缩到它:
>>> p = Person(**{'id': 1, 'name': 'bob'})
>>> p.id
1
>>> p.name
'bob'
>>> p
<__main__.Person object at 0x02DA5730>
答案 3 :(得分:1)
您可以使用以下函数根据给定的__init__
生成dict
方法:
def make_init(d):
def __init__(self, **kwargs):
for name in d:
setattr(self, name, kwargs[name])
return __init__
然后,使用type
的3参数形式在运行时创建一个类。
type_name = "Person"
Person = type(type_name, (object,), { '__init__': make_init(mapy) })
最后,使用字典实例化类以提供__init__
的参数:
obj = Person(**mapy)