如何将Python dict转换为特定类型的对象?

如何将Python dict转换为特定类型的对象?,python,dictionary,metaprogramming,Python,Dictionary,Metaprogramming,使用Python2.7,我需要将字典转换为类型化对象 例如,如果我有这句话: mapy = {'id': 1, 'name': 'bob'} 鉴于前面的映射和类型名(在本例中为'Person'),我需要某种方法在运行时生成此类: 我是否应该考虑使用元编程技术,如果是这样的话,哪一个是精确的(装饰器,元类,…)?< /P> 请注意,我不仅仅需要将dict转换为对象;我还需要将一些类型信息附加到结果对象 您可以尝试将命名为tuple: from collections import namedtu

使用Python2.7,我需要将字典转换为类型化对象

例如,如果我有这句话:

mapy = {'id': 1, 'name': 'bob'}
鉴于前面的映射和类型名(在本例中为
'Person'
),我需要某种方法在运行时生成此类:

我是否应该考虑使用元编程技术,如果是这样的话,哪一个是精确的(装饰器,元类,…)?< /P>


请注意,我不仅仅需要将dict转换为对象;我还需要将一些类型信息附加到结果对象

您可以尝试将
命名为tuple

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

您可以尝试
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

通常,您的
\uuuu init\uuuu
将具有实际参数来提供属性值:

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>
p=Person(**{'id':1,'name':'bob'}) >>>p.id 1. >>>p.name “鲍勃” >>>p
通常,您的
\uuuu init\uuuu
会有实际参数来提供属性值:

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>
p=Person(**{'id':1,'name':'bob'}) >>>p.id 1. >>>p.name “鲍勃” >>>p
您可以使用以下函数根据给定的
dict
生成
\uuuuuuu初始化\uuuuuuu
方法:

def make_init(d):
    def __init__(self, **kwargs):
        for name in d:
            setattr(self, name, kwargs[name])
    return __init__
然后,使用
type
的三参数形式在运行时创建一个类

type_name = "Person"
Person = type(type_name, (object,), { '__init__': make_init(mapy) })
最后,使用字典实例化该类以向
\uuuu init\uuuu
提供参数:

obj = Person(**mapy)

您可以使用以下函数根据给定的
dict
生成
\uuuuu init\uuuu
方法:

def make_init(d):
    def __init__(self, **kwargs):
        for name in d:
            setattr(self, name, kwargs[name])
    return __init__
然后,使用
type
的三参数形式在运行时创建一个类

type_name = "Person"
Person = type(type_name, (object,), { '__init__': make_init(mapy) })
最后,使用字典实例化该类以向
\uuuu init\uuuu
提供参数:

obj = Person(**mapy)

您的请求有一个问题:“我不仅需要将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)

您的请求有一个问题:“我不仅需要将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)

我不太确定你想在这里做什么,但可能是你想要的。我不太确定你想在这里做什么,但可能是您正在寻找的。类定义需要以编程方式生成,即当程序运行时,定义不存在launched@Chedy2149那么nneonneo的
namedtuple
建议可能是你最好的选择,但我很想听听你为什么认为这是必要的——做你的“课程”没有实例方法?@Chedy2149,Python中的类是一级对象。动态创建一个新类并为其指定所需的名称和属性非常容易;见下面我的答案。类定义需要通过编程生成,即当程序运行时,定义不存在launched@Chedy2149那么nneonneo的
namedtuple
建议可能是你最好的选择,但我很想听听你为什么认为这是必要的——做你的“课程”没有实例方法?@Chedy2149,Python中的类是一级对象。动态创建一个新类并为其指定所需的名称和属性非常容易;请看下面我的答案。这是一个很好的方法。我看到的唯一问题是它创建了一个只读对象(因为它是
tuple
的一个子类)。@Dan:这一点很好。如果OP需要读/写对象,他们可以查看
namedtuple
的实现,了解如何动态生成适当的类定义。这是一种很好的方法。我看到的唯一问题是它创建了一个只读对象(因为它是
tuple
的一个子类)。@Dan:这一点很好。如果OP需要读/写对象,他们可以查看
namedtuple
的实现,以了解如何动态生成适当的类定义。您可以将
for
循环替换为
self.\uu dict\uuuuu.update(d)
,并且有一种更明确的动态创建类的方法(参见下面的示例)。您可以将循环的
替换为
self.\uu dict\uuuu.update(d)