标签归档:dictionary

如何对字典中的所有值求和?

问题:如何对字典中的所有值求和?

假设我有一本字典,其中的键映射为整数,例如:

d = {'key1': 1,'key2': 14,'key3': 47}

是否有返回值的总和在语法上简约的方式d-即62在这种情况下?

Let’s say I have a dictionary in which the keys map to integers like:

d = {'key1': 1,'key2': 14,'key3': 47}

Is there a syntactically minimalistic way to return the sum of the values in d—i.e. 62 in this case?


回答 0

如您所料:

sum(d.values())

As you’d expect:

sum(d.values())

回答 1

在Python 2中,您可以避免通过使用itervalues()dictionary方法创建所有值的临时副本,该方法返回字典键的迭代器:

sum(d.itervalues())

在Python 3中,您只能使用d.values()该方法,因为该方法已更改为可以这样做(并且itervalues()由于不再需要而被删除)。

为了使编写总是在字典键值上进行迭代的版本无关代码更容易,实用程序功能可能会有所帮助:

import sys

def itervalues(d):
    return iter(getattr(d, ('itervalues', 'values')[sys.version_info[0]>2])())

sum(itervalues(d))

这本质上就是本杰明·彼得森的six模块所做的。

In Python 2 you can avoid making a temporary copy of all the values by using the itervalues() dictionary method, which returns an iterator of the dictionary’s keys:

sum(d.itervalues())

In Python 3 you can just use d.values() because that method was changed to do that (and itervalues() was removed since it was no longer needed).

To make it easier to write version independent code which always iterates over the values of the dictionary’s keys, a utility function can be helpful:

import sys

def itervalues(d):
    return iter(getattr(d, ('itervalues', 'values')[sys.version_info[0]>2])())

sum(itervalues(d))

This is essentially what Benjamin Peterson’s six module does.


回答 2

当然可以。这是一种汇总字典值的方法。

>>> d = {'key1':1,'key2':14,'key3':47}
>>> sum(d.values())
62

Sure there is. Here is a way to sum the values of a dictionary.

>>> d = {'key1':1,'key2':14,'key3':47}
>>> sum(d.values())
62

回答 3

d = {'key1': 1,'key2': 14,'key3': 47}
sum1 = sum(d[item] for item in d)
print(sum1)

你可以使用for循环

d = {'key1': 1,'key2': 14,'key3': 47}
sum1 = sum(d[item] for item in d)
print(sum1)

you can do it using the for loop


回答 4

我觉得这sum(d.values())是获得总和的最有效方法。

您也可以尝试用reduce函数来计算总和以及lambda表达式:

reduce(lambda x,y:x+y,d.values())

I feel sum(d.values()) is the most efficient way to get the sum.

You can also try the reduce function to calculate the sum along with a lambda expression:

reduce(lambda x,y:x+y,d.values())

回答 5

sum(d.values())-“ d”->您的字典变量

sum(d.values()) – “d” -> Your dictionary Variable


回答 6

phihag的答案(和类似的答案)在python3中不起作用。

对于python 3:

d = {'key1': 1,'key2': 14,'key3': 47}
sum(list(d.values()))

更新!有人抱怨说这行不通!我只是在终端上附上截图。可能是版本不匹配等。

在此处输入图片说明

phihag’s answer (and similar ones) won’t work in python3.

For python 3:

d = {'key1': 1,'key2': 14,'key3': 47}
sum(list(d.values()))

Update! There are complains that it doesn’t work! I just attach a screenshot from my terminal. Could be some mismatch in versions etc.

enter image description here


回答 7

您可以为此考虑“ for循环”:

  d = {'data': 100, 'data2': 200, 'data3': 500}
  total = 0
  for i in d.values():
        total += i

总计= 800

You could consider ‘for loop’ for this:

  d = {'data': 100, 'data2': 200, 'data3': 500}
  total = 0
  for i in d.values():
        total += i

total = 800


回答 8

您可以获取字典中所有值的生成器,然后将其转换为列表,然后使用sum()函数获取所有值的总和。

例:

c={"a":123,"b":4,"d":4,"c":-1001,"x":2002,"y":1001}

sum(list(c.values()))

You can get a generator of all the values in the dictionary, then cast it to a list and use the sum() function to get the sum of all the values.

Example:

c={"a":123,"b":4,"d":4,"c":-1001,"x":2002,"y":1001}

sum(list(c.values()))

如何将字典转储到json文件?

问题:如何将字典转储到json文件?

我有这样的命令:

sample = {'ObjectInterpolator': 1629,  'PointInterpolator': 1675, 'RectangleInterpolator': 2042}

我不知道如何将字典转储到json文件,如下所示:

{      
    "name": "interpolator",
    "children": [
      {"name": "ObjectInterpolator", "size": 1629},
      {"name": "PointInterpolator", "size": 1675},
      {"name": "RectangleInterpolator", "size": 2042}
     ]
}

有python方式可以做到这一点吗?

您可能会猜到我想生成一个d3树形图。

I have a dict like this:

sample = {'ObjectInterpolator': 1629,  'PointInterpolator': 1675, 'RectangleInterpolator': 2042}

I can’t figure out how to dump the dict to a json file as showed below:

{      
    "name": "interpolator",
    "children": [
      {"name": "ObjectInterpolator", "size": 1629},
      {"name": "PointInterpolator", "size": 1675},
      {"name": "RectangleInterpolator", "size": 2042}
     ]
}

Is there a pythonic way to do this?

You may guess that I want to generate a d3 treemap.


回答 0

import json
with open('result.json', 'w') as fp:
    json.dump(sample, fp)

这是一种更简单的方法。

在第二行代码中,文件result.json被创建并作为变量打开fp

在第三行中,您的字典sample被写入result.json

import json
with open('result.json', 'w') as fp:
    json.dump(sample, fp)

This is an easier way to do it.

In the second line of code the file result.json gets created and opened as the variable fp.

In the third line your dict sample gets written into the result.json!


回答 1

结合@mgilson和@gnibbler的答案,我发现我需要的是:


d = {"name":"interpolator",
     "children":[{'name':key,"size":value} for key,value in sample.items()]}
j = json.dumps(d, indent=4)
f = open('sample.json', 'w')
print >> f, j
f.close()

这样,我得到了一个漂亮的json文件。print >> f, j从这里可以找到技巧:http : //www.anthonydebarros.com/2012/03/11/generate-json-from-sql-using-python/

Combine the answer of @mgilson and @gnibbler, I found what I need was this:


d = {"name":"interpolator",
     "children":[{'name':key,"size":value} for key,value in sample.items()]}
j = json.dumps(d, indent=4)
f = open('sample.json', 'w')
print >> f, j
f.close()

It this way, I got a pretty-print json file. The tricks print >> f, j is found from here: http://www.anthonydebarros.com/2012/03/11/generate-json-from-sql-using-python/


回答 2

d = {"name":"interpolator",
     "children":[{'name':key,"size":value} for key,value in sample.items()]}
json_string = json.dumps(d)

当然,不可能完全保留顺序…但这只是字典的性质…

d = {"name":"interpolator",
     "children":[{'name':key,"size":value} for key,value in sample.items()]}
json_string = json.dumps(d)

Of course, it’s unlikely that the order will be exactly preserved … But that’s just the nature of dictionaries …


回答 3

这应该给你一个开始

>>> import json
>>> print json.dumps([{'name': k, 'size': v} for k,v in sample.items()], indent=4)
[
    {
        "name": "PointInterpolator",
        "size": 1675
    },
    {
        "name": "ObjectInterpolator",
        "size": 1629
    },
    {
        "name": "RectangleInterpolator",
        "size": 2042
    }
]

This should give you a start

>>> import json
>>> print json.dumps([{'name': k, 'size': v} for k,v in sample.items()], indent=4)
[
    {
        "name": "PointInterpolator",
        "size": 1675
    },
    {
        "name": "ObjectInterpolator",
        "size": 1629
    },
    {
        "name": "RectangleInterpolator",
        "size": 2042
    }
]

回答 4

具有漂亮的打印格式:

import json

with open(path_to_file, 'w') as file:
    json_string = json.dumps(sample, default=lambda o: o.__dict__, sort_keys=True, indent=2)
    file.write(json_string)

with pretty-print format:

import json

with open(path_to_file, 'w') as file:
    json_string = json.dumps(sample, default=lambda o: o.__dict__, sort_keys=True, indent=2)
    file.write(json_string)

在python中计算字典中关键字的数量

问题:在python中计算字典中关键字的数量

我在词典中有一个单词列表,其值=关键字的重复,但是我只想要一个不同单词的列表,因此我想计算关键字的数量。有没有一种方法可以计算关键字的数量,或者还有另一种方法我应该寻找不同的单词?

I have a list of words in a dictionary with the value = the repetition of the keyword but I only want a list of distinct words so I wanted to count the number of keywords. Is there a way to count the number of keywords or is there another way I should look for distinct words?


回答 0

len(yourdict.keys())

要不就

len(yourdict)

如果您想计算文件中的唯一单词,则可以使用set并执行以下操作

len(set(open(yourdictfile).read().split()))
len(yourdict.keys())

or just

len(yourdict)

If you like to count unique words in the file, you could just use set and do like

len(set(open(yourdictfile).read().split()))

回答 1

可以使用该len()功能找到不同单词的数量(即词典中的条目数)。

> a = {'foo':42, 'bar':69}
> len(a)
2

要获取所有不同的单词(即键),请使用.keys()方法。

> list(a.keys())
['foo', 'bar']

The number of distinct words (i.e. count of entries in the dictionary) can be found using the len() function.

> a = {'foo':42, 'bar':69}
> len(a)
2

To get all the distinct words (i.e. the keys), use the .keys() method.

> list(a.keys())
['foo', 'bar']

回答 2

len()直接在您的字典上进行调用是有效的,并且比构建迭代器,d.keys()和对其进行调用要快len(),但是与您的程序正在执行的其他操作相比,两者的速度都可以忽略不计。

d = {x: x**2 for x in range(1000)}

len(d)
# 1000

len(d.keys())
# 1000

%timeit len(d)
# 41.9 ns ± 0.244 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%timeit len(d.keys())
# 83.3 ns ± 0.41 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Calling len() directly on your dictionary works, and is faster than building an iterator, d.keys(), and calling len() on it, but the speed of either will negligible in comparison to whatever else your program is doing.

d = {x: x**2 for x in range(1000)}

len(d)
# 1000

len(d.keys())
# 1000

%timeit len(d)
# 41.9 ns ± 0.244 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%timeit len(d.keys())
# 83.3 ns ± 0.41 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

回答 3

如果问题是关于计算关键字数量,则建议使用类似

def countoccurrences(store, value):
    try:
        store[value] = store[value] + 1
    except KeyError as e:
        store[value] = 1
    return

在main函数中有一些循环数据并将值传递给countoccurrences函数的东西

if __name__ == "__main__":
    store = {}
    list = ('a', 'a', 'b', 'c', 'c')
    for data in list:
        countoccurrences(store, data)
    for k, v in store.iteritems():
        print "Key " + k + " has occurred "  + str(v) + " times"

代码输出

Key a has occurred 2 times
Key c has occurred 2 times
Key b has occurred 1 times

If the question is about counting the number of keywords then would recommend something like

def countoccurrences(store, value):
    try:
        store[value] = store[value] + 1
    except KeyError as e:
        store[value] = 1
    return

in the main function have something that loops through the data and pass the values to countoccurrences function

if __name__ == "__main__":
    store = {}
    list = ('a', 'a', 'b', 'c', 'c')
    for data in list:
        countoccurrences(store, data)
    for k, v in store.iteritems():
        print "Key " + k + " has occurred "  + str(v) + " times"

The code outputs

Key a has occurred 2 times
Key c has occurred 2 times
Key b has occurred 1 times

回答 4

在发布的答案UnderWaterKremlin上进行了一些修改,以使其成为python3证明。下面是一个令人惊讶的结果作为答案。

系统规格:

  • python = 3.7.4,
  • 康达= 4.8.0
  • 3.6Ghz,8核心,16gb。
import timeit

d = {x: x**2 for x in range(1000)}
#print (d)
print (len(d))
# 1000

print (len(d.keys()))
# 1000

print (timeit.timeit('len({x: x**2 for x in range(1000)})', number=100000))        # 1

print (timeit.timeit('len({x: x**2 for x in range(1000)}.keys())', number=100000)) # 2

结果:

1)= 37.0100378

2)= 37.002148899999995

因此,len(d.keys())目前看来比使用来得快len()

Some modifications were made on posted answer UnderWaterKremlin to make it python3 proof. A surprising result below as answer.

System specs:

  • python =3.7.4,
  • conda = 4.8.0
  • 3.6Ghz, 8 core, 16gb.
import timeit

d = {x: x**2 for x in range(1000)}
#print (d)
print (len(d))
# 1000

print (len(d.keys()))
# 1000

print (timeit.timeit('len({x: x**2 for x in range(1000)})', number=100000))        # 1

print (timeit.timeit('len({x: x**2 for x in range(1000)}.keys())', number=100000)) # 2

Result:

1) = 37.0100378

2) = 37.002148899999995

So it seems that len(d.keys()) is currently faster than just using len().


Django模板如何使用变量查找字典值

问题:Django模板如何使用变量查找字典值

mydict = {"key1":"value1", "key2":"value2"}

查找在Django模板字典值的常规方法是{{ mydict.key1 }}{{ mydict.key2 }}。如果键是循环变量怎么办?即:

{% for item in list %} # where item has an attribute NAME
  {{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}

mydict.item.NAME失败。如何解决?

mydict = {"key1":"value1", "key2":"value2"}

The regular way to lookup a dictionary value in a Django template is {{ mydict.key1 }}, {{ mydict.key2 }}. What if the key is a loop variable? ie:

{% for item in list %} # where item has an attribute NAME
  {{ mydict.item.NAME }} # I want to look up mydict[item.NAME]
{% endfor %}

mydict.item.NAME fails. How to fix this?


回答 0

编写自定义模板过滤器:

from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

(我.get这样使用,如果不存在该键,则不返回任何键。如果执行dictionary[key]此操作,则将引发一个KeyErrorthen。)

用法:

{{ mydict|get_item:item.NAME }}

Write a custom template filter:

from django.template.defaulttags import register
...
@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

(I use .get so that if the key is absent, it returns none. If you do dictionary[key] it will raise a KeyError then.)

usage:

{{ mydict|get_item:item.NAME }}

回答 1

从循环中的字典中获取键和值:

{% for key, value in mydict.items %}
    {{ value }}
{% endfor %}

我发现这更容易阅读,并且不需要特殊的编码。无论如何,我通常都需要循环内的键和值。

Fetch both the key and the value from the dictionary in the loop:

{% for key, value in mydict.items %}
    {{ value }}
{% endfor %}

I find this easier to read and it avoids the need for special coding. I usually need the key and the value inside the loop anyway.


回答 2

默认情况下不能。点是属性查找/键查找/切片的分隔符/触发器。

点在模板渲染中具有特殊含义。变量名称中的点表示查找。具体来说,当模板系统遇到变量名称中的点时,它将按以下顺序尝试以下查找:

  • 字典查找。示例:foo [“ bar”]
  • 属性查询。示例:foo.bar
  • 列表索引查找。示例:foo [bar]

但是您可以创建一个过滤器,以便您传递参数:

https://docs.djangoproject.com/zh-CN/dev/howto/custom-template-tags/#writing-custom-template-filters

@register.filter(name='lookup')
def lookup(value, arg):
    return value[arg]

{{ mydict|lookup:item.name }}

You can’t by default. The dot is the separator / trigger for attribute lookup / key lookup / slice.

Dots have a special meaning in template rendering. A dot in a variable name signifies a lookup. Specifically, when the template system encounters a dot in a variable name, it tries the following lookups, in this order:

  • Dictionary lookup. Example: foo[“bar”]
  • Attribute lookup. Example: foo.bar
  • List-index lookup. Example: foo[bar]

But you can make a filter which lets you pass in an argument:

https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters

@register.filter(name='lookup')
def lookup(value, arg):
    return value[arg]

{{ mydict|lookup:item.name }}

回答 3

对我来说template_filters.py,用下面的内容在我的应用程序中创建一个名为python的文件就可以了

# coding=utf-8
from django.template.base import Library

register = Library()


@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

用法就像culebrón所说的:

{{ mydict|get_item:item.NAME }}

For me creating a python file named template_filters.py in my App with below content did the job

# coding=utf-8
from django.template.base import Library

register = Library()


@register.filter
def get_item(dictionary, key):
    return dictionary.get(key)

usage is like what culebrón said :

{{ mydict|get_item:item.NAME }}

回答 4

我也有类似的情况。但是我使用了不同的解决方案。

在我的模型中,我创建一个执行字典查找的属性。然后在模板中使用该属性。

在我的模型中:-

@property
def state_(self):
    """ Return the text of the state rather than an integer """
    return self.STATE[self.state]

在我的模板中:-

The state is: {{ item.state_ }}

I had a similar situation. However I used a different solution.

In my model I create a property that does the dictionary lookup. In the template I then use the property.

In my model: –

@property
def state_(self):
    """ Return the text of the state rather than an integer """
    return self.STATE[self.state]

In my template: –

The state is: {{ item.state_ }}

回答 5

因为我不能评论,让我做这一个答案的形式:
建立在culebrón的答案虞姬“富田”富田的答案,传递给函数的字典是一个字符串的形式,因此,也许使用AST。 literal_eval,首先将字符串转换为字典,如本例所示

通过此编辑,代码应如下所示:

@register.filter(name='lookup')
def lookup(value, arg):
    dictionary = ast.literal_eval(value)
    return value.get(arg)

{{ mydict|lookup:item.name }}

Since I can’t comment, let me do this in the form of an answer:
to build on culebrón’s answer or Yuji ‘Tomita’ Tomita’s answer, the dictionary passed into the function is in the form of a string, so perhaps use ast.literal_eval to convert the string to a dictionary first, like in this example.

With this edit, the code should look like this:

# code for custom template tag
@register.filter(name='lookup')
def lookup(value, arg):
    value_dict = ast.literal_eval(value)
    return value_dict.get(arg)

<!--template tag (in the template)-->
{{ mydict|lookup:item.name }}

回答 6

环境:Django 2.2

  1. 示例代码:


    from django.template.defaulttags import register

    @register.filter(name='lookup')
    def lookup(value, arg):
        return value.get(arg)

我将此代码放在名为Portfoliomgr的项目文件夹中的一个名为template_filters.py的文件中

  1. 无论您将过滤器代码放在何处,都要确保该文件夹中有__init__.py

  2. 将该文件添加到projectfolder / settings.py文件中模板部分的库部分。对我来说,它是Portfoliomgr / settings.py



    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
                'libraries':{
                    'template_filters': 'portfoliomgr.template_filters',
                }
            },
        },
    ]
  1. 在您的html代码中加载库

    
    {% load template_filters %}

Environment: Django 2.2

  1. Example code:


    from django.template.defaulttags import register

    @register.filter(name='lookup')
    def lookup(value, arg):
        return value.get(arg)

I put this code in a file named template_filters.py in my project folder named portfoliomgr

  1. No matter where you put your filter code, make sure you have __init__.py in that folder

  2. Add that file to libraries section in templates section in your projectfolder/settings.py file. For me, it is portfoliomgr/settings.py



    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
                'libraries':{
                    'template_filters': 'portfoliomgr.template_filters',
                }
            },
        },
    ]

  1. In your html code load the library

    
    {% load template_filters %}
    

回答 7

环保:django 2.1.7

视图:

dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})

模板:

{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>

env: django 2.1.7

view:

dict_objs[query_obj.id] = {'obj': query_obj, 'tag': str_tag}
return render(request, 'obj.html', {'dict_objs': dict_objs})

template:

{% for obj_id,dict_obj in dict_objs.items %}
<td>{{ dict_obj.obj.obj_name }}</td>
<td style="display:none">{{ obj_id }}</td>
<td>{{ forloop.counter }}</td>
<td>{{ dict_obj.obj.update_timestamp|date:"Y-m-d H:i:s"}}</td>

将Python argparse.Namespace()视为字典的正确方法是什么?

问题:将Python argparse.Namespace()视为字典的正确方法是什么?

如果我想将的结果(argparse.ArgumentParser()Namespace对象)与需要字典或类映射对象的方法一起使用(请参阅collections.Mapping),那么正确的方法是什么?

C:\>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> args.baz = 'yippee'
>>> args['baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Namespace' object has no attribute '__getitem__'
>>> dir(args)
['__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '_
_format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__
', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs', 'ba
r', 'baz', 'foo']

“进入”对象并使用其__dict__属性是否合适?

我认为答案是否定的:__dict__闻起来像实现的约定,而不是接口的含义__getattribute____setattr__或者说__contains__是。

If I want to use the results of argparse.ArgumentParser(), which is a Namespace object, with a method that expects a dictionary or mapping-like object (see collections.Mapping), what is the right way to do it?

C:\>python
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> args.baz = 'yippee'
>>> args['baz']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'Namespace' object has no attribute '__getitem__'
>>> dir(args)
['__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '_
_format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__
', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs', 'ba
r', 'baz', 'foo']

Is it proper to “reach into” an object and use its __dict__ property?

I would think the answer is no: __dict__ smells like a convention for implementation, but not for an interface, the way __getattribute__ or __setattr__ or __contains__ seem to be.


回答 0

您可以使用vars()访问命名空间的字典:

>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}

您可以根据需要直接修改字典:

>>> d['baz'] = 'store me'
>>> args.baz
'store me'

是的,可以访问__dict__属性。这是定义明确,经过测试且有保证的行为。

You can access the namespace’s dictionary with vars():

>>> import argparse
>>> args = argparse.Namespace()
>>> args.foo = 1
>>> args.bar = [1,2,3]
>>> d = vars(args)
>>> d
{'foo': 1, 'bar': [1, 2, 3]}

You can modify the dictionary directly if you wish:

>>> d['baz'] = 'store me'
>>> args.baz
'store me'

Yes, it is okay to access the __dict__ attribute. It is a well-defined, tested, and guaranteed behavior.


回答 1

从马口直行

如果您更喜欢具有类似dict的属性视图,则可以使用标准的Python习惯用法vars()

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

— Python标准库,16.4.4.6。命名空间对象

Straight from the horse’s mouth:

If you prefer to have dict-like view of the attributes, you can use the standard Python idiom, vars():

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo')
>>> args = parser.parse_args(['--foo', 'BAR'])
>>> vars(args)
{'foo': 'BAR'}

— The Python Standard Library, 16.4.4.6. The Namespace object


回答 2

“进入”对象并使用其dict属性是否合适?

通常,我会说“不”。但是Namespace,令我震惊的是过度设计,可能是因为类无法从内置类型继承。

另一方面,Namespace确实提供了一种针对argparse的面向任务的方法,我想不出需要抓住的情况__dict__,但是我的想象力的极限与您的一样。

Is it proper to “reach into” an object and use its dict property?

In general, I would say “no”. However Namespace has struck me as over-engineered, possibly from when classes couldn’t inherit from built-in types.

On the other hand, Namespace does present a task-oriented approach to argparse, and I can’t think of a situation that would call for grabbing the __dict__, but the limits of my imagination are not the same as yours.


如何使用点“。” 访问字典成员?

问题:如何使用点“。” 访问字典成员?

如何通过点“。”访问Python词典成员?

例如,mydict['val']我不想写,而是想写mydict.val

我也想以这种方式访问​​嵌套的字典。例如

mydict.mydict2.val 

将指

mydict = { 'mydict2': { 'val': ... } }

How do I make Python dictionary members accessible via a dot “.”?

For example, instead of writing mydict['val'], I’d like to write mydict.val.

Also I’d like to access nested dicts this way. For example

mydict.mydict2.val 

would refer to

mydict = { 'mydict2': { 'val': ... } }

回答 0

您可以使用我刚刚制作的此类进行操作。通过此类,您可以Map像其他字典(包括json序列化)一样使用该对象,也可以使用点符号。希望对您有所帮助:

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

用法示例:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']

You can do it using this class I just made. With this class you can use the Map object like another dictionary(including json serialization) or with the dot notation. I hope to help you:

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

Usage examples:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']

回答 1

我一直将其保存在util文件中。您也可以在自己的类中将其用作混合。

class dotdict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

mydict = {'val':'it works'}
nested_dict = {'val':'nested works too'}
mydict = dotdict(mydict)
mydict.val
# 'it works'

mydict.nested = dotdict(nested_dict)
mydict.nested.val
# 'nested works too'

I’ve always kept this around in a util file. You can use it as a mixin on your own classes too.

class dotdict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

mydict = {'val':'it works'}
nested_dict = {'val':'nested works too'}
mydict = dotdict(mydict)
mydict.val
# 'it works'

mydict.nested = dotdict(nested_dict)
mydict.nested.val
# 'nested works too'

回答 2

dotmap通过安装pip

pip install dotmap

它可以完成您想要做的所有事情并成为其子类dict,因此它的作用类似于普通字典:

from dotmap import DotMap

m = DotMap()
m.hello = 'world'
m.hello
m.hello += '!'
# m.hello and m['hello'] now both return 'world!'
m.val = 5
m.val2 = 'Sam'

最重要的是,您可以将其与dict对象之间进行转换:

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor

这意味着,如果您要访问的内容已经dict存在,可以将其转换DotMap为易于访问的内容:

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city

最后,它会自动创建新的子DotMap实例,因此您可以执行以下操作:

m = DotMap()
m.people.steve.age = 31

与束比较

全面披露:我是DotMap的创建者。我创建它是因为Bunch缺少这些功能

  • 记住添加了订单项并按照该顺序进行迭代
  • 自动子 DotMap创建,这样可以节省时间,并在您具有多个层次结构时使代码更简洁
  • 从构造dict并将所有子dict实例递归转换为DotMap

Install dotmap via pip

pip install dotmap

It does everything you want it to do and subclasses dict, so it operates like a normal dictionary:

from dotmap import DotMap

m = DotMap()
m.hello = 'world'
m.hello
m.hello += '!'
# m.hello and m['hello'] now both return 'world!'
m.val = 5
m.val2 = 'Sam'

On top of that, you can convert it to and from dict objects:

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor

This means that if something you want to access is already in dict form, you can turn it into a DotMap for easy access:

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city

Finally, it automatically creates new child DotMap instances so you can do things like this:

m = DotMap()
m.people.steve.age = 31

Comparison to Bunch

Full disclosure: I am the creator of the DotMap. I created it because Bunch was missing these features

  • remembering the order items are added and iterating in that order
  • automatic child DotMap creation, which saves time and makes for cleaner code when you have a lot of hierarchy
  • constructing from a dict and recursively converting all child dict instances to DotMap

回答 3

从指令派生并实施__getattr__和实施__setattr__

或者您可以使用非常相似的Bunch

我认为不可能对内置的dict类进行修补。

Derive from dict and and implement __getattr__ and __setattr__.

Or you can use Bunch which is very similar.

I don’t think it’s possible to monkeypatch built-in dict class.


回答 4

Fabric具有非常好的,最小的实现。扩展它以允许嵌套访问,我们可以使用defaultdict,结果看起来像这样:

from collections import defaultdict

class AttributeDict(defaultdict):
    def __init__(self):
        super(AttributeDict, self).__init__(AttributeDict)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(key)

    def __setattr__(self, key, value):
        self[key] = value

如下使用它:

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234

这就详细说明了库格尔的回答:“从命令和实现中得出__getattr____setattr__”。现在您知道了!

Fabric has a really nice, minimal implementation. Extending that to allow for nested access, we can use a defaultdict, and the result looks something like this:

from collections import defaultdict

class AttributeDict(defaultdict):
    def __init__(self):
        super(AttributeDict, self).__init__(AttributeDict)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(key)

    def __setattr__(self, key, value):
        self[key] = value

Make use of it as follows:

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234

That elaborates a bit on Kugel’s answer of “Derive from dict and and implement __getattr__ and __setattr__“. Now you know how!


回答 5

我尝试了这个:

class dotdict(dict):
    def __getattr__(self, name):
        return self[name]

你可以试试 __getattribute__

让每个字典都使用点分隔符就足够了,如果您想从多层字典中初始化它,也可以尝试实现__init__

I tried this:

class dotdict(dict):
    def __getattr__(self, name):
        return self[name]

you can try __getattribute__ too.

make every dict a type of dotdict would be good enough, if you want to init this from a multi-layer dict, try implement __init__ too.


回答 6

别。属性访问和索引编制在Python中是分开的,您不希望它们执行相同的操作。namedtuple如果您有一些应该具有可访问属性的东西,并使用[]表示法从字典中获取一项,则创建一个类(可能是由制成的类)。

Don’t. Attribute access and indexing are separate things in Python, and you shouldn’t want them to perform the same. Make a class (possibly one made by namedtuple) if you have something that should have accessible attributes and use [] notation to get an item from a dict.


回答 7

如果要腌制修改后的字典,则需要在上述答案中添加一些状态方法:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    def __getattr__(self, attr):
        return self.get(attr)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __getstate__(self):
        return self

    def __setstate__(self, state):
        self.update(state)
        self.__dict__ = self

If you want to pickle your modified dictionary, you need to add few state methods to above answers:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    def __getattr__(self, attr):
        return self.get(attr)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __getstate__(self):
        return self

    def __setstate__(self, state):
        self.update(state)
        self.__dict__ = self

回答 8

以库格尔(Kugel)的答案为基础,并考虑迈克·格雷厄姆(Mike Graham)的警告语,如果我们做包装纸怎么办?

class DictWrap(object):
  """ Wrap an existing dict, or create a new one, and access with either dot 
    notation or key lookup.

    The attribute _data is reserved and stores the underlying dictionary.
    When using the += operator with create=True, the empty nested dict is 
    replaced with the operand, effectively creating a default dictionary
    of mixed types.

    args:
      d({}): Existing dict to wrap, an empty dict is created by default
      create(True): Create an empty, nested dict instead of raising a KeyError

    example:
      >>>dw = DictWrap({'pp':3})
      >>>dw.a.b += 2
      >>>dw.a.b += 2
      >>>dw.a['c'] += 'Hello'
      >>>dw.a['c'] += ' World'
      >>>dw.a.d
      >>>print dw._data
      {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3}

  """

  def __init__(self, d=None, create=True):
    if d is None:
      d = {}
    supr = super(DictWrap, self)  
    supr.__setattr__('_data', d)
    supr.__setattr__('__create', create)

  def __getattr__(self, name):
    try:
      value = self._data[name]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[name] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setattr__(self, name, value):
    self._data[name] = value  

  def __getitem__(self, key):
    try:
      value = self._data[key]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[key] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setitem__(self, key, value):
    self._data[key] = value

  def __iadd__(self, other):
    if self._data:
      raise TypeError("A Nested dict will only be replaced if it's empty")
    else:
      return other

Building on Kugel’s answer and taking Mike Graham’s words of caution into consideration, what if we make a wrapper?

class DictWrap(object):
  """ Wrap an existing dict, or create a new one, and access with either dot 
    notation or key lookup.

    The attribute _data is reserved and stores the underlying dictionary.
    When using the += operator with create=True, the empty nested dict is 
    replaced with the operand, effectively creating a default dictionary
    of mixed types.

    args:
      d({}): Existing dict to wrap, an empty dict is created by default
      create(True): Create an empty, nested dict instead of raising a KeyError

    example:
      >>>dw = DictWrap({'pp':3})
      >>>dw.a.b += 2
      >>>dw.a.b += 2
      >>>dw.a['c'] += 'Hello'
      >>>dw.a['c'] += ' World'
      >>>dw.a.d
      >>>print dw._data
      {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3}

  """

  def __init__(self, d=None, create=True):
    if d is None:
      d = {}
    supr = super(DictWrap, self)  
    supr.__setattr__('_data', d)
    supr.__setattr__('__create', create)

  def __getattr__(self, name):
    try:
      value = self._data[name]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[name] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setattr__(self, name, value):
    self._data[name] = value  

  def __getitem__(self, key):
    try:
      value = self._data[key]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[key] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setitem__(self, key, value):
    self._data[key] = value

  def __iadd__(self, other):
    if self._data:
      raise TypeError("A Nested dict will only be replaced if it's empty")
    else:
      return other

回答 9

用途SimpleNamespace

>>> from types import SimpleNamespace   
>>> d = dict(x=[1, 2], y=['a', 'b'])
>>> ns = SimpleNamespace(**d)
>>> ns.x
[1, 2]
>>> ns
namespace(x=[1, 2], y=['a', 'b'])

Use SimpleNamespace:

>>> from types import SimpleNamespace   
>>> d = dict(x=[1, 2], y=['a', 'b'])
>>> ns = SimpleNamespace(**d)
>>> ns.x
[1, 2]
>>> ns
namespace(x=[1, 2], y=['a', 'b'])

回答 10

我喜欢Munch,它在点访问之外还提供了许多方便的选项。

进口午餐

temp_1 = {‘person’:{‘fname’:’senthil’,’lname’:’ramalingam’}}

dict_munch = munch.munchify(temp_1)

dict_munch.person.fname

I like the Munch and it gives lot of handy options on top of dot access.

import munch

temp_1 = {‘person’: { ‘fname’: ‘senthil’, ‘lname’: ‘ramalingam’}}

dict_munch = munch.munchify(temp_1)

dict_munch.person.fname


回答 11

最近,我遇到了“ Box ”库,它做同样的事情。

安装命令: pip install python-box

例:

from box import Box

mydict = {"key1":{"v1":0.375,
                    "v2":0.625},
          "key2":0.125,
          }
mydict = Box(mydict)

print(mydict.key1.v1)

我发现它比其他现有的库(例如dotmap)更有效,如点阵图,当嵌套的字典较大时,它们会生成python递归错误。

链接到库和详细信息:https : //pypi.org/project/python-box/

I recently came across the ‘Box‘ library which does the same thing.

Installation command : pip install python-box

Example:

from box import Box

mydict = {"key1":{"v1":0.375,
                    "v2":0.625},
          "key2":0.125,
          }
mydict = Box(mydict)

print(mydict.key1.v1)

I found it to be more effective than other existing libraries like dotmap, which generate python recursion error when you have large nested dicts.

link to library and details: https://pypi.org/project/python-box/


回答 12

使用__getattr__非常简单,可在Python 3.4.3中使用

class myDict(dict):
    def __getattr__(self,val):
        return self[val]


blockBody=myDict()
blockBody['item1']=10000
blockBody['item2']="StackOverflow"
print(blockBody.item1)
print(blockBody.item2)

输出:

10000
StackOverflow

Use __getattr__, very simple, works in Python 3.4.3

class myDict(dict):
    def __getattr__(self,val):
        return self[val]


blockBody=myDict()
blockBody['item1']=10000
blockBody['item2']="StackOverflow"
print(blockBody.item1)
print(blockBody.item2)

Output:

10000
StackOverflow

回答 13

语言本身不支持此功能,但有时这仍然是有用的要求。除了Bunch食谱之外,您还可以编写一些小方法,该方法可以使用点分字符串来访问字典:

def get_var(input_dict, accessor_string):
    """Gets data from a dictionary using a dotted accessor-string"""
    current_data = input_dict
    for chunk in accessor_string.split('.'):
        current_data = current_data.get(chunk, {})
    return current_data

这将支持以下内容:

>> test_dict = {'thing': {'spam': 12, 'foo': {'cheeze': 'bar'}}}
>> output = get_var(test_dict, 'thing.spam.foo.cheeze')
>> print output
'bar'
>>

The language itself doesn’t support this, but sometimes this is still a useful requirement. Besides the Bunch recipe, you can also write a little method which can access a dictionary using a dotted string:

def get_var(input_dict, accessor_string):
    """Gets data from a dictionary using a dotted accessor-string"""
    current_data = input_dict
    for chunk in accessor_string.split('.'):
        current_data = current_data.get(chunk, {})
    return current_data

which would support something like this:

>> test_dict = {'thing': {'spam': 12, 'foo': {'cheeze': 'bar'}}}
>> output = get_var(test_dict, 'thing.spam.foo.cheeze')
>> print output
'bar'
>>

回答 14

为了建立epool的答案,此版本允许您通过点运算符访问内部的所有dict:

foo = {
    "bar" : {
        "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ]
    }
}

例如,foo.bar.baz[1].babareturn "loo"

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    if isinstance(v, dict):
                        v = Map(v)
                    if isinstance(v, list):
                        self.__convert(v)
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                if isinstance(v, dict):
                    v = Map(v)
                elif isinstance(v, list):
                    self.__convert(v)
                self[k] = v

    def __convert(self, v):
        for elem in xrange(0, len(v)):
            if isinstance(v[elem], dict):
                v[elem] = Map(v[elem])
            elif isinstance(v[elem], list):
                self.__convert(v[elem])

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

To build upon epool’s answer, this version allows you to access any dict inside via the dot operator:

foo = {
    "bar" : {
        "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ]
    }
}

For instance, foo.bar.baz[1].baba returns "loo".

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    if isinstance(v, dict):
                        v = Map(v)
                    if isinstance(v, list):
                        self.__convert(v)
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                if isinstance(v, dict):
                    v = Map(v)
                elif isinstance(v, list):
                    self.__convert(v)
                self[k] = v

    def __convert(self, v):
        for elem in xrange(0, len(v)):
            if isinstance(v[elem], dict):
                v[elem] = Map(v[elem])
            elif isinstance(v[elem], list):
                self.__convert(v[elem])

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

回答 15

def dict_to_object(dick):
    # http://stackoverflow.com/a/1305663/968442

    class Struct:
        def __init__(self, **entries):
            self.__dict__.update(entries)

    return Struct(**dick)

如果决定永久将其转换dict为对象,则应该这样做。您可以在访问之前创建一个一次性对象。

d = dict_to_object(d)
def dict_to_object(dick):
    # http://stackoverflow.com/a/1305663/968442

    class Struct:
        def __init__(self, **entries):
            self.__dict__.update(entries)

    return Struct(**dick)

If one decides to permanently convert that dict to object this should do. You can create a throwaway object just before accessing.

d = dict_to_object(d)

回答 16

我最终都尝试了AttrDict Bunch库,发现它们是我使用速度减慢的方法。经过一个朋友和我的研究,我们发现编写这些库的主要方法导致该库通过嵌套对象积极地递归并在整个字典对象中进行复制。考虑到这一点,我们进行了两个关键更改。1)我们使属性延迟加载; 2)我们创建轻量级代理对象的副本,而不是创建字典对象的副本。这是最终的实现。使用此代码的性能提升令人难以置信。使用AttrDict或Bunch时,仅这两个库分别消耗了我的请求时间的1/2和1/3(什么!?)。这段代码将时间减少到几乎没有(在0.5ms范围内)。当然,这取决于您的需求,但是如果您在代码中大量使用此功能,

class DictProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    def __getattr__(self, key):
        try:
            return wrap(getattr(self.obj, key))
        except AttributeError:
            try:
                return self[key]
            except KeyError:
                raise AttributeError(key)

    # you probably also want to proxy important list properties along like
    # items(), iteritems() and __len__

class ListProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    # you probably also want to proxy important list properties along like
    # __iter__ and __len__

def wrap(value):
    if isinstance(value, dict):
        return DictProxy(value)
    if isinstance(value, (tuple, list)):
        return ListProxy(value)
    return value

通过https://stackoverflow.com/users/704327/michael-merickel查看此处的原始实现。

还要注意的另一件事是,此实现非常简单,并没有实现您可能需要的所有方法。您需要根据需要在DictProxy或ListProxy对象上编写这些内容。

I ended up trying BOTH the AttrDict and the Bunch libraries and found them to be way to slow for my uses. After a friend and I looked into it, we found that the main method for writing these libraries results in the library aggressively recursing through a nested object and making copies of the dictionary object throughout. With this in mind, we made two key changes. 1) We made attributes lazy-loaded 2) instead of creating copies of a dictionary object, we create copies of a light-weight proxy object. This is the final implementation. The performance increase of using this code is incredible. When using AttrDict or Bunch, these two libraries alone consumed 1/2 and 1/3 respectively of my request time(what!?). This code reduced that time to almost nothing(somewhere in the range of 0.5ms). This of course depends on your needs, but if you are using this functionality quite a bit in your code, definitely go with something simple like this.

class DictProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    def __getattr__(self, key):
        try:
            return wrap(getattr(self.obj, key))
        except AttributeError:
            try:
                return self[key]
            except KeyError:
                raise AttributeError(key)

    # you probably also want to proxy important list properties along like
    # items(), iteritems() and __len__

class ListProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    # you probably also want to proxy important list properties along like
    # __iter__ and __len__

def wrap(value):
    if isinstance(value, dict):
        return DictProxy(value)
    if isinstance(value, (tuple, list)):
        return ListProxy(value)
    return value

See the original implementation here by https://stackoverflow.com/users/704327/michael-merickel.

The other thing to note, is that this implementation is pretty simple and doesn’t implement all of the methods you might need. You’ll need to write those as required on the DictProxy or ListProxy objects.


回答 17

我想将自己的解决方案付诸实践:

https://github.com/skorokithakis/jsane

它使您可以将JSON解析为可以访问的内容with.attribute.lookups.like.this.r(),主要是因为在开始使用JSON 之前我还没有看到这个答案。

I’d like to throw my own solution into the ring:

https://github.com/skorokithakis/jsane

It allows you to parse JSON into something you can access with.attribute.lookups.like.this.r(), mostly because I hadn’t seen this answer before starting to work on it.


回答 18

不是直接回答OP的问题,而是受到某些人的启发,也许对某些人有用。.我已经使用内部__dict__方法创建了基于对象的解决方案(绝不优化代码)

payload = {
    "name": "John",
    "location": {
        "lat": 53.12312312,
        "long": 43.21345112
    },
    "numbers": [
        {
            "role": "home",
            "number": "070-12345678"
        },
        {
            "role": "office",
            "number": "070-12345679"
        }
    ]
}


class Map(object):
    """
    Dot style access to object members, access raw values
    with an underscore e.g.

    class Foo(Map):
        def foo(self):
            return self.get('foo') + 'bar'

    obj = Foo(**{'foo': 'foo'})

    obj.foo => 'foobar'
    obj._foo => 'foo'

    """

    def __init__(self, *args, **kwargs):
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self.__dict__[k] = v
                    self.__dict__['_' + k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self.__dict__[k] = v
                self.__dict__['_' + k] = v

    def __getattribute__(self, attr):
        if hasattr(self, 'get_' + attr):
            return object.__getattribute__(self, 'get_' + attr)()
        else:
            return object.__getattribute__(self, attr)

    def get(self, key):
        try:
            return self.__dict__.get('get_' + key)()
        except (AttributeError, TypeError):
            return self.__dict__.get(key)

    def __repr__(self):
        return u"<{name} object>".format(
            name=self.__class__.__name__
        )


class Number(Map):
    def get_role(self):
        return self.get('role')

    def get_number(self):
        return self.get('number')


class Location(Map):
    def get_latitude(self):
        return self.get('lat') + 1

    def get_longitude(self):
        return self.get('long') + 1


class Item(Map):
    def get_name(self):
        return self.get('name') + " Doe"

    def get_location(self):
        return Location(**self.get('location'))

    def get_numbers(self):
        return [Number(**n) for n in self.get('numbers')]


# Tests

obj = Item({'foo': 'bar'}, **payload)

assert type(obj) == Item
assert obj._name == "John"
assert obj.name == "John Doe"
assert type(obj.location) == Location
assert obj.location._lat == 53.12312312
assert obj.location._long == 43.21345112
assert obj.location.latitude == 54.12312312
assert obj.location.longitude == 44.21345112

for n in obj.numbers:
    assert type(n) == Number
    if n.role == 'home':
        assert n.number == "070-12345678"
    if n.role == 'office':
        assert n.number == "070-12345679"

Not a direct answer to the OP’s question, but inspired by and perhaps useful for some.. I’ve created an object-based solution using the internal __dict__ (In no way optimized code)

payload = {
    "name": "John",
    "location": {
        "lat": 53.12312312,
        "long": 43.21345112
    },
    "numbers": [
        {
            "role": "home",
            "number": "070-12345678"
        },
        {
            "role": "office",
            "number": "070-12345679"
        }
    ]
}


class Map(object):
    """
    Dot style access to object members, access raw values
    with an underscore e.g.

    class Foo(Map):
        def foo(self):
            return self.get('foo') + 'bar'

    obj = Foo(**{'foo': 'foo'})

    obj.foo => 'foobar'
    obj._foo => 'foo'

    """

    def __init__(self, *args, **kwargs):
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self.__dict__[k] = v
                    self.__dict__['_' + k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self.__dict__[k] = v
                self.__dict__['_' + k] = v

    def __getattribute__(self, attr):
        if hasattr(self, 'get_' + attr):
            return object.__getattribute__(self, 'get_' + attr)()
        else:
            return object.__getattribute__(self, attr)

    def get(self, key):
        try:
            return self.__dict__.get('get_' + key)()
        except (AttributeError, TypeError):
            return self.__dict__.get(key)

    def __repr__(self):
        return u"<{name} object>".format(
            name=self.__class__.__name__
        )


class Number(Map):
    def get_role(self):
        return self.get('role')

    def get_number(self):
        return self.get('number')


class Location(Map):
    def get_latitude(self):
        return self.get('lat') + 1

    def get_longitude(self):
        return self.get('long') + 1


class Item(Map):
    def get_name(self):
        return self.get('name') + " Doe"

    def get_location(self):
        return Location(**self.get('location'))

    def get_numbers(self):
        return [Number(**n) for n in self.get('numbers')]


# Tests

obj = Item({'foo': 'bar'}, **payload)

assert type(obj) == Item
assert obj._name == "John"
assert obj.name == "John Doe"
assert type(obj.location) == Location
assert obj.location._lat == 53.12312312
assert obj.location._long == 43.21345112
assert obj.location.latitude == 54.12312312
assert obj.location.longitude == 44.21345112

for n in obj.numbers:
    assert type(n) == Number
    if n.role == 'home':
        assert n.number == "070-12345678"
    if n.role == 'office':
        assert n.number == "070-12345679"

回答 19

获得点访问(而不是数组访问)的一种简单方法是在Python中使用普通对象。像这样:

class YourObject:
    def __init__(self, *args, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

…并像这样使用它:

>>> obj = YourObject(key="value")
>>> print(obj.key)
"value"

…将其转换为字典:

>>> print(obj.__dict__)
{"key": "value"}

One simple way to get dot access (but not array access), is to use a plain object in Python. Like this:

class YourObject:
    def __init__(self, *args, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

…and use it like this:

>>> obj = YourObject(key="value")
>>> print(obj.key)
"value"

… to convert it to a dict:

>>> print(obj.__dict__)
{"key": "value"}

回答 20

此解决方案是对epool提供的解决方案的改进,以解决OP以一致方式访问嵌套dict的要求。epool的解决方案不允许访问嵌套字典。

class YAMLobj(dict):
    def __init__(self, args):
        super(YAMLobj, self).__init__(args)
        if isinstance(args, dict):
            for k, v in args.iteritems():
                if not isinstance(v, dict):
                    self[k] = v
                else:
                    self.__setattr__(k, YAMLobj(v))


    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(YAMLobj, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(YAMLobj, self).__delitem__(key)
        del self.__dict__[key]

有了这一堂课,您现在可以执行以下操作:A.B.C.D

This solution is a refinement upon the one offered by epool to address the requirement of the OP to access nested dicts in a consistent manner. The solution by epool did not allow for accessing nested dicts.

class YAMLobj(dict):
    def __init__(self, args):
        super(YAMLobj, self).__init__(args)
        if isinstance(args, dict):
            for k, v in args.iteritems():
                if not isinstance(v, dict):
                    self[k] = v
                else:
                    self.__setattr__(k, YAMLobj(v))


    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(YAMLobj, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(YAMLobj, self).__delitem__(key)
        del self.__dict__[key]

With this class, one can now do something like: A.B.C.D.


回答 21

这也适用于嵌套字典,并确保稍后附加的字典具有相同的行为:

class DotDict(dict):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Recursively turn nested dicts into DotDicts
        for key, value in self.items():
            if type(value) is dict:
                self[key] = DotDict(value)

    def __setitem__(self, key, item):
        if type(item) is dict:
            item = DotDict(item)
        super().__setitem__(key, item)

    __setattr__ = __setitem__
    __getattr__ = dict.__getitem__

This also works with nested dicts and makes sure that dicts which are appended later behave the same:

class DotDict(dict):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Recursively turn nested dicts into DotDicts
        for key, value in self.items():
            if type(value) is dict:
                self[key] = DotDict(value)

    def __setitem__(self, key, item):
        if type(item) is dict:
            item = DotDict(item)
        super().__setitem__(key, item)

    __setattr__ = __setitem__
    __getattr__ = dict.__getitem__

回答 22

@ derek73的答案非常简洁,但是不能被腌制或(深度)复制,并且返回None因缺少键。下面的代码解决了这个问题。

编辑:我没有看到上面的答案完全相同的点(已投票)。我将答案留在这里以供参考。

class dotdict(dict):
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

The answer of @derek73 is very neat, but it cannot be pickled nor (deep)copied, and it returns None for missing keys. The code below fixes this.

Edit: I did not see the answer above that addresses the exact same point (upvoted). I’m leaving the answer here for reference.

class dotdict(dict):
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

回答 23

一种精致的解决方案

class DotDict(dict):

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, key):

        def typer(candidate):
            if isinstance(candidate, dict):
                return DotDict(candidate)

            if isinstance(candidate, str):  # iterable but no need to iter
                return candidate

            try:  # other iterable are processed as list
                return [typer(item) for item in candidate]
            except TypeError:
                return candidate

            return candidate

        return typer(dict.get(self, key))

A solution kind of delicate

class DotDict(dict):

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, key):

        def typer(candidate):
            if isinstance(candidate, dict):
                return DotDict(candidate)

            if isinstance(candidate, str):  # iterable but no need to iter
                return candidate

            try:  # other iterable are processed as list
                return [typer(item) for item in candidate]
            except TypeError:
                return candidate

            return candidate

        return typer(dict.get(self, key))

将python字典转换为字符串并返回

问题:将python字典转换为字符串并返回

我正在编写一个将数据存储在字典对象中的程序,但是该数据需要在程序执行过程中的某个时候保存,并在再次运行该程序时重新加载到字典对象中。如何将字典对象转换为可以写入文件并可以加载回字典对象的字符串?希望这将支持包含词典的词典。

I am writing a program that stores data in a dictionary object, but this data needs to be saved at some point during the program execution and loaded back into the dictionary object when the program is run again. How would I convert a dictionary object into a string that can be written to a file and loaded back into a dictionary object? This will hopefully support dictionaries containing dictionaries.


回答 0

json模块是一个很好的解决方案。与pickle相比,它的优势在于它仅生成纯文本输出,并且是跨平台和跨版本的。

import json
json.dumps(dict)

The json module is a good solution here. It has the advantages over pickle that it only produces plain text output, and is cross-platform and cross-version.

import json
json.dumps(dict)

回答 1

如果您的字典不太大,也许str + eval可以完成工作:

dict1 = {'one':1, 'two':2, 'three': {'three.1': 3.1, 'three.2': 3.2 }}
str1 = str(dict1)

dict2 = eval(str1)

print dict1==dict2

如果源不受信任,则可以使用ast.literal_eval而不是eval来提高安全性。

If your dictionary isn’t too big maybe str + eval can do the work:

dict1 = {'one':1, 'two':2, 'three': {'three.1': 3.1, 'three.2': 3.2 }}
str1 = str(dict1)

dict2 = eval(str1)

print dict1==dict2

You can use ast.literal_eval instead of eval for additional security if the source is untrusted.


回答 2

我用json

import json

# convert to string
input = json.dumps({'id': id })

# load to dict
my_dict = json.loads(input) 

I use json:

import json

# convert to string
input = json.dumps({'id': id })

# load to dict
my_dict = json.loads(input) 

回答 3

使用该pickle模块将其保存到磁盘并稍后加载。

Use the pickle module to save it to disk and load later on.


回答 4

为什么不使用Python 3的内置ast库的函数literal_eval。最好使用literal_eval而不是eval

import ast
str_of_dict = "{'key1': 'key1value', 'key2': 'key2value'}"
ast.literal_eval(str_of_dict)

将输出作为实际字典

{'key1': 'key1value', 'key2': 'key2value'}

而且,如果您要求将Dictionary转换为String,那么如何使用str() Python的方法。

假设字典是:

my_dict = {'key1': 'key1value', 'key2': 'key2value'}

这将像这样完成:

str(my_dict)

将打印:

"{'key1': 'key1value', 'key2': 'key2value'}"

这是您想要的简单操作。

Why not to use Python 3’s inbuilt ast library’s function literal_eval. It is better to use literal_eval instead of eval

import ast
str_of_dict = "{'key1': 'key1value', 'key2': 'key2value'}"
ast.literal_eval(str_of_dict)

will give output as actual Dictionary

{'key1': 'key1value', 'key2': 'key2value'}

And If you are asking to convert a Dictionary to a String then, How about using str() method of Python.

Suppose the dictionary is :

my_dict = {'key1': 'key1value', 'key2': 'key2value'}

And this will be done like this :

str(my_dict)

Will Print :

"{'key1': 'key1value', 'key2': 'key2value'}"

This is the easy as you like.


回答 5

如果在中国

import codecs
fout = codecs.open("xxx.json", "w", "utf-8")
dict_to_json = json.dumps({'text':"中文"},ensure_ascii=False,indent=2)
fout.write(dict_to_json + '\n')

If in Chinses

import codecs
fout = codecs.open("xxx.json", "w", "utf-8")
dict_to_json = json.dumps({'text':"中文"},ensure_ascii=False,indent=2)
fout.write(dict_to_json + '\n')

回答 6

将字典转换成JSON(字符串)

import json 

mydict = { "name" : "Don", 
          "surname" : "Mandol", 
          "age" : 43} 

result = json.dumps(mydict)

print(result[0:20])

将为您提供:

{“ name”:“ Don”,“ sur

将字符串转换成字典

back_to_mydict = json.loads(result) 

Convert dictionary into JSON (string)

import json 

mydict = { "name" : "Don", 
          "surname" : "Mandol", 
          "age" : 43} 

result = json.dumps(mydict)

print(result[0:20])

will get you:

{“name”: “Don”, “sur

Convert string into dictionary

back_to_mydict = json.loads(result) 

回答 7

我认为您应该考虑使用shelve提供持久性文件支持的字典式对象的模块。它很容易代替“真实”字典使用,因为它几乎透明地为您的程序提供了可以像字典一样使用的东西,而无需将其显式转换为字符串然后写入文件(或反之,反之亦然。

主要区别是需要open()先使用close()它,然后再使用(完成时可能要使用sync()它,具体取决于writeback要使用所使用选项)。创建的任何“架子”文件对象都可以包含常规字典作为值,从而使它们可以逻辑嵌套。

这是一个简单的例子:

import shelve

shelf = shelve.open('mydata')  # open for reading and writing, creating if nec
shelf.update({'one':1, 'two':2, 'three': {'three.1': 3.1, 'three.2': 3.2 }})
shelf.close()

shelf = shelve.open('mydata')
print shelf
shelf.close()

输出:

{'three': {'three.1': 3.1, 'three.2': 3.2}, 'two': 2, 'one': 1}

I think you should consider using the shelve module which provides persistent file-backed dictionary-like objects. It’s easy to use in place of a “real” dictionary because it almost transparently provides your program with something that can be used just like a dictionary, without the need to explicitly convert it to a string and then write to a file (or vice-versa).

The main difference is needing to initially open() it before first use and then close() it when you’re done (and possibly sync()ing it, depending on the writeback option being used). Any “shelf” file objects create can contain regular dictionaries as values, allowing them to be logically nested.

Here’s a trivial example:

import shelve

shelf = shelve.open('mydata')  # open for reading and writing, creating if nec
shelf.update({'one':1, 'two':2, 'three': {'three.1': 3.1, 'three.2': 3.2 }})
shelf.close()

shelf = shelve.open('mydata')
print shelf
shelf.close()

Output:

{'three': {'three.1': 3.1, 'three.2': 3.2}, 'two': 2, 'one': 1}

回答 8

如果您关心速度,请使用与json相同的API的ujson(UltraJSON):

import ujson
ujson.dumps([{"key": "value"}, 81, True])
# '[{"key":"value"},81,true]'
ujson.loads("""[{"key": "value"}, 81, true]""")
# [{u'key': u'value'}, 81, True]

If you care about the speed use ujson (UltraJSON), which has the same API as json:

import ujson
ujson.dumps([{"key": "value"}, 81, True])
# '[{"key":"value"},81,true]'
ujson.loads("""[{"key": "value"}, 81, true]""")
# [{u'key': u'value'}, 81, True]

回答 9

如果需要可读性(不是IMHO的JSON或XML),或者如果不需要阅读的话,我就使用yaml。

from pickle import dumps, loads
x = dict(a=1, b=2)
y = dict(c = x, z=3)
res = dumps(y)
open('/var/tmp/dump.txt', 'w').write(res)

回过头再读

from pickle import dumps, loads
rev = loads(open('/var/tmp/dump.txt').read())
print rev

I use yaml for that if needs to be readable (neither JSON nor XML are that IMHO), or if reading is not necessary I use pickle.

Write

from pickle import dumps, loads
x = dict(a=1, b=2)
y = dict(c = x, z=3)
res = dumps(y)
open('/var/tmp/dump.txt', 'w').write(res)

Read back

from pickle import dumps, loads
rev = loads(open('/var/tmp/dump.txt').read())
print rev

将Django模型对象转换为所有字段均完整的dict

问题:将Django模型对象转换为所有字段均完整的dict

如何将Django模型对象转换为具有所有字段的字典?理想情况下,所有内容都包含带有的外键和字段editable=False

让我详细说明。假设我有一个类似以下的Django模型:

from django.db import models

class OtherModel(models.Model): pass

class SomeModel(models.Model):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

在终端中,我已执行以下操作:

other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()

我想将其转换为以下字典:

{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
 'foreign_key': 1,
 'id': 1,
 'many_to_many': [1],
 'normal_value': 1,
 'readonly_value': 2}

答案不令人满意的问题:

Django:将整个模型对象集转换为单个字典

如何将Django模型对象转换为字典并仍然具有其外键?

How does one convert a Django Model object to a dict with all of its fields? All ideally includes foreign keys and fields with editable=False.

Let me elaborate. Let’s say I have a Django model like the following:

from django.db import models

class OtherModel(models.Model): pass

class SomeModel(models.Model):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

In the terminal, I have done the following:

other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()

I want to convert this to the following dictionary:

{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
 'foreign_key': 1,
 'id': 1,
 'many_to_many': [1],
 'normal_value': 1,
 'readonly_value': 2}

Questions with unsatisfactory answers:

Django: Converting an entire set of a Model’s objects into a single dictionary

How can I turn Django Model objects into a dictionary and still have their foreign keys?


回答 0

有多种方法可将实例转换为字典,并具有不同程度的特殊情况处理和接近所需结果的程度。


1。 instance.__dict__

instance.__dict__

哪个返回

{'_foreign_key_cache': <OtherModel: OtherModel object>,
 '_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
 'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

到目前为止,这是最简单的方法,但是缺少many_to_manyforeign_key被错误命名,并且其中有两个多余的多余内容。


2。 model_to_dict

from django.forms.models import model_to_dict
model_to_dict(instance)

哪个返回

{'foreign_key': 2,
 'id': 1,
 'many_to_many': [<OtherModel: OtherModel object>],
 'normal_value': 1}

这是唯一的many_to_many,但缺少不可编辑的字段。


3。 model_to_dict(..., fields=...)

from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])

哪个返回

{'foreign_key': 2, 'id': 1, 'normal_value': 1}

这绝对比标准model_to_dict调用差。


4。 query_set.values()

SomeModel.objects.filter(id=instance.id).values()[0]

哪个返回

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

这与输出相同,instance.__dict__但没有额外的字段。 foreign_key_id仍然是错误的,many_to_many仍然不见了。


5.自定义功能

django的代码model_to_dict具有大部分答案。它显式删除了不可编辑的字段,因此删除该检查并获取多对多字段的外键ID会导致以下代码按预期运行:

from itertools import chain

def to_dict(instance):
    opts = instance._meta
    data = {}
    for f in chain(opts.concrete_fields, opts.private_fields):
        data[f.name] = f.value_from_object(instance)
    for f in opts.many_to_many:
        data[f.name] = [i.id for i in f.value_from_object(instance)]
    return data

虽然这是最复杂的选项,但调用to_dict(instance)会给我们确切的预期结果:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

6.使用序列化器

Django Rest Framework的ModelSerialzer允许您从模型自动构建序列化器。

from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SomeModel
        fields = "__all__"

SomeModelSerializer(instance).data

退货

{'auto_now_add': '2018-12-20T21:34:29.494827Z',
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

这几乎与自定义函数一样好,但是auto_now_add是字符串而不是datetime对象。


奖金回合:更好的模型印刷

如果您想要一个具有更好的python命令行显示的Django模型,请让您的模型将以下子类:

from django.db import models
from itertools import chain

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(instance):
        opts = instance._meta
        data = {}
        for f in chain(opts.concrete_fields, opts.private_fields):
            data[f.name] = f.value_from_object(instance)
        for f in opts.many_to_many:
            data[f.name] = [i.id for i in f.value_from_object(instance)]
        return data

    class Meta:
        abstract = True

因此,例如,如果我们这样定义模型:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

SomeModel.objects.first()现在调用将产生如下输出:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

There are many ways to convert an instance to a dictionary, with varying degrees of corner case handling and closeness to the desired result.


1. instance.__dict__

instance.__dict__

which returns

{'_foreign_key_cache': <OtherModel: OtherModel object>,
 '_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
 'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

This is by far the simplest, but is missing many_to_many, foreign_key is misnamed, and it has two unwanted extra things in it.


2. model_to_dict

from django.forms.models import model_to_dict
model_to_dict(instance)

which returns

{'foreign_key': 2,
 'id': 1,
 'many_to_many': [<OtherModel: OtherModel object>],
 'normal_value': 1}

This is the only one with many_to_many, but is missing the uneditable fields.


3. model_to_dict(..., fields=...)

from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])

which returns

{'foreign_key': 2, 'id': 1, 'normal_value': 1}

This is strictly worse than the standard model_to_dict invocation.


4. query_set.values()

SomeModel.objects.filter(id=instance.id).values()[0]

which returns

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

This is the same output as instance.__dict__ but without the extra fields. foreign_key_id is still wrong and many_to_many is still missing.


5. Custom Function

The code for django’s model_to_dict had most of the answer. It explicitly removed non-editable fields, so removing that check and getting the ids of foreign keys for many to many fields results in the following code which behaves as desired:

from itertools import chain

def to_dict(instance):
    opts = instance._meta
    data = {}
    for f in chain(opts.concrete_fields, opts.private_fields):
        data[f.name] = f.value_from_object(instance)
    for f in opts.many_to_many:
        data[f.name] = [i.id for i in f.value_from_object(instance)]
    return data

While this is the most complicated option, calling to_dict(instance) gives us exactly the desired result:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

6. Use Serializers

Django Rest Framework‘s ModelSerialzer allows you to build a serializer automatically from a model.

from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SomeModel
        fields = "__all__"

SomeModelSerializer(instance).data

returns

{'auto_now_add': '2018-12-20T21:34:29.494827Z',
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

This is almost as good as the custom function, but auto_now_add is a string instead of a datetime object.


Bonus Round: better model printing

If you want a django model that has a better python command-line display, have your models child-class the following:

from django.db import models
from itertools import chain

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(instance):
        opts = instance._meta
        data = {}
        for f in chain(opts.concrete_fields, opts.private_fields):
            data[f.name] = f.value_from_object(instance)
        for f in opts.many_to_many:
            data[f.name] = [i.id for i in f.value_from_object(instance)]
        return data

    class Meta:
        abstract = True

So, for example, if we define our models as such:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

Calling SomeModel.objects.first() now gives output like this:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

回答 1

我找到了一个整洁的解决方案以得到结果:

假设您有一个模型对象o

只需调用:

type(o).objects.filter(pk=o.pk).values().first()

I found a neat solution to get to result:

Suppose you have an model object o:

Just call:

type(o).objects.filter(pk=o.pk).values().first()

回答 2

@Zags解决方案很棒!

不过,我将为datefields添加一个条件,以使其对JSON友好。

奖金回合

如果您希望Django模型具有更好的python命令行显示,请让您的模型子类具有以下功能:

from django.db import models
from django.db.models.fields.related import ManyToManyField

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self):
        opts = self._meta
        data = {}
        for f in opts.concrete_fields + opts.many_to_many:
            if isinstance(f, ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True))
            elif isinstance(f, DateTimeField):
                if f.value_from_object(self) is not None:
                    data[f.name] = f.value_from_object(self).timestamp()
            else:
                data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)
        return data

    class Meta:
        abstract = True

因此,例如,如果我们这样定义模型:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    value = models.IntegerField()
    value2 = models.IntegerField(editable=False)
    created = models.DateTimeField(auto_now_add=True)
    reference1 = models.ForeignKey(OtherModel, related_name="ref1")
    reference2 = models.ManyToManyField(OtherModel, related_name="ref2")

SomeModel.objects.first()现在调用将产生如下输出:

{'created': 1426552454.926738,
'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]}

@Zags solution was gorgeous!

I would add, though, a condition for datefields in order to make it JSON friendly.

Bonus Round

If you want a django model that has a better python command-line display, have your models child class the following:

from django.db import models
from django.db.models.fields.related import ManyToManyField

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self):
        opts = self._meta
        data = {}
        for f in opts.concrete_fields + opts.many_to_many:
            if isinstance(f, ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True))
            elif isinstance(f, DateTimeField):
                if f.value_from_object(self) is not None:
                    data[f.name] = f.value_from_object(self).timestamp()
            else:
                data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)
        return data

    class Meta:
        abstract = True

So, for example, if we define our models as such:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    value = models.IntegerField()
    value2 = models.IntegerField(editable=False)
    created = models.DateTimeField(auto_now_add=True)
    reference1 = models.ForeignKey(OtherModel, related_name="ref1")
    reference2 = models.ManyToManyField(OtherModel, related_name="ref2")

Calling SomeModel.objects.first() now gives output like this:

{'created': 1426552454.926738,
'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]}

回答 3

最简单的方法

  1. 如果您的查询是Model.Objects.get():

    get()将返回单个实例,因此您可以直接__dict__从实例中使用

    model_dict = Model.Objects.get().__dict__

  2. 对于filter()/ all():

    all()/ filter()将返回实例列表,因此您可以values()用来获取对象列表。

    model_values = Model.Objects.all()。values()

Simplest way,

  1. If your query is Model.Objects.get():

    get() will return single instance so you can direct use __dict__ from your instance

    model_dict = Model.Objects.get().__dict__

  2. for filter()/all():

    all()/filter() will return list of instances so you can use values() to get list of objects.

    model_values = Model.Objects.all().values()


回答 4

只是vars(obj),它将说明对象的整个值

>>> obj_attrs = vars(obj)
>>> obj_attrs
 {'_file_data_cache': <FileData: Data>,
  '_state': <django.db.models.base.ModelState at 0x7f5c6733bad0>,
  'aggregator_id': 24,
  'amount': 5.0,
  'biller_id': 23,
  'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
  'file_data_id': 797719,
 }

您也可以添加

>>> keys = obj_attrs.keys()
>>> temp = [obj_attrs.pop(key) if key.startswith('_') else None for key in keys]
>>> del temp
>>> obj_attrs
   {
    'aggregator_id': 24,
    'amount': 5.0,
    'biller_id': 23,
    'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
    'file_data_id': 797719,
   }

just vars(obj) , it will state the whole values of the object

>>> obj_attrs = vars(obj)
>>> obj_attrs
 {'_file_data_cache': <FileData: Data>,
  '_state': <django.db.models.base.ModelState at 0x7f5c6733bad0>,
  'aggregator_id': 24,
  'amount': 5.0,
  'biller_id': 23,
  'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
  'file_data_id': 797719,
 }

You can add this also

>>> keys = obj_attrs.keys()
>>> temp = [obj_attrs.pop(key) if key.startswith('_') else None for key in keys]
>>> del temp
>>> obj_attrs
   {
    'aggregator_id': 24,
    'amount': 5.0,
    'biller_id': 23,
    'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
    'file_data_id': 797719,
   }

回答 5

更新资料

@zags发布的较新的汇总答案比我自己的答案更完整,更优雅。请改为参考该答案。

原版的

如果您愿意像@karthiker建议的那样定义自己的to_dict方法,那么就可以将此问题归结为集合问题。

>>># Returns a set of all keys excluding editable = False keys
>>>dict = model_to_dict(instance)
>>>dict

{u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1}


>>># Returns a set of editable = False keys, misnamed foreign keys, and normal keys
>>>otherDict = SomeModel.objects.filter(id=instance.id).values()[0]
>>>otherDict

{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1_id': 1L,
 'value': 1L,
 'value2': 2L}

我们需要从otherDict中删除贴标签的外键。

为此,我们可以使用一个循环来创建一个新字典,该字典除了包含下划线的项外,还包含所有项。或者,为了节省时间,我们可以将它们添加到原始字典中,因为字典只是在幕后设置的。

>>>for item in otherDict.items():
...    if "_" not in item[0]:
...            dict.update({item[0]:item[1]})
...
>>>

因此,我们只能用下面的字典

>>>dict
{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1': 1L,
 'reference2': [1L],
 'value': 1,
 'value2': 2L}

然后您将其退回。

不利的一面是,您不能在editable = false字段名称中使用下划线。从好的方面来说,这将适用于用户创建的字段不包含下划线的任何字段集。

这不是执行此操作的最佳方法,但是在找到更直接的方法之前,它可以作为临时解决方案。

对于以下示例,将基于model_to_dict形成dict,并通过filter的values方法形成otherDict。我本来可以用模型自己完成的,但是我无法让我的机器接受otherModel。

>>> import datetime
>>> dict = {u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1}
>>> otherDict = {'created': datetime.datetime(2014, 2, 21, 4, 38, 51), u'id': 1, 'reference1_id': 1, 'value': 1, 'value2': 2}
>>> for item in otherDict.items():
...     if "_" not in item[0]:
...             dict.update({item[0]:item[1]})
...
>>> dict
{'reference1': 1, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51), 'value2': 2, 'value': 1, 'id': 1, 'reference2': [1]}
>>>

我希望,这应该使您对问题的答案有个大概的了解。

Update

The newer aggregated answer posted by @zags is more complete and elegant than my own. Please refer to that answer instead.

Original

If you are willing to define your own to_dict method like @karthiker suggested, then that just boils this problem down to a sets problem.

>>># Returns a set of all keys excluding editable = False keys
>>>dict = model_to_dict(instance)
>>>dict

{u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1}


>>># Returns a set of editable = False keys, misnamed foreign keys, and normal keys
>>>otherDict = SomeModel.objects.filter(id=instance.id).values()[0]
>>>otherDict

{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1_id': 1L,
 'value': 1L,
 'value2': 2L}

We need to remove the mislabeled foreign keys from otherDict.

To do this, we can use a loop that makes a new dictionary that has every item except those with underscores in them. Or, to save time, we can just add those to the original dict since dictionaries are just sets under the hood.

>>>for item in otherDict.items():
...    if "_" not in item[0]:
...            dict.update({item[0]:item[1]})
...
>>>

Thus we are left with the following dict:

>>>dict
{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1': 1L,
 'reference2': [1L],
 'value': 1,
 'value2': 2L}

And you just return that.

On the downside, you can’t use underscores in your editable=false field names. On the upside, this will work for any set of fields where the user-made fields do not contain underscores.

This is not the best way of doing this, but it could work as a temporary solution until a more direct method is found.

For the example below, dict would be formed based on model_to_dict and otherDict would be formed by filter’s values method. I would have done this with the models themselves, but I can’t get my machine to accept otherModel.

>>> import datetime
>>> dict = {u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1}
>>> otherDict = {'created': datetime.datetime(2014, 2, 21, 4, 38, 51), u'id': 1, 'reference1_id': 1, 'value': 1, 'value2': 2}
>>> for item in otherDict.items():
...     if "_" not in item[0]:
...             dict.update({item[0]:item[1]})
...
>>> dict
{'reference1': 1, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51), 'value2': 2, 'value': 1, 'id': 1, 'reference2': [1]}
>>>

That should put you in a rough ballpark of the answer to your question, I hope.


回答 6

这里有很多有趣的解决方案。我的解决方案是使用dict理解将as_dict方法添加到模型中。

def as_dict(self):
    return dict((f.name, getattr(self, f.name)) for f in self._meta.fields)

另外,如果您要将模型导出到另一个库,则此解决方案与对查询的列表理解一起可以提供一个不错的解决方案。例如,将模型转储到pandas数据框中:

pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()])

Lots of interesting solutions here. My solution was to add an as_dict method to my model with a dict comprehension.

def as_dict(self):
    return dict((f.name, getattr(self, f.name)) for f in self._meta.fields)

As a bonus, this solution paired with an list comprehension over a query makes for a nice solution if you want export your models to another library. For example, dumping your models into a pandas dataframe:

pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()])

回答 7

(并非要发表评论)

好的,它并不是真的那样依赖类型。我可能对这里的原始问题有误解,因此请原谅。如果创建serliazers.py,则在其中创建具有元类的类。

Class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = modelName
        fields =('csv','of','fields')

然后,当您在视图类中获取数据时,您可以:

model_data - Model.objects.filter(...)
serializer = MyModelSerializer(model_data, many=True)
return Response({'data': serilaizer.data}, status=status.HTTP_200_OK)

这在很多地方都差不多,它通过JSONRenderer返回了不错的JSON。

正如我所说的,这是DjangoRestFramework的礼貌,因此值得研究。

(did not mean to make the comment)

Ok, it doesn’t really depend on types in that way. I may have mis-understood the original question here so forgive me if that is the case. If you create serliazers.py then in there you create classes that have meta classes.

Class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = modelName
        fields =('csv','of','fields')

Then when you get the data in the view class you can:

model_data - Model.objects.filter(...)
serializer = MyModelSerializer(model_data, many=True)
return Response({'data': serilaizer.data}, status=status.HTTP_200_OK)

That is pretty much what I have in a vareity of places and it returns nice JSON via the JSONRenderer.

As I said this is courtesy of the DjangoRestFramework so it’s worth looking into that.


回答 8

更简单的方法是只使用pprint,这在基本Python中

import pprint
item = MyDjangoModel.objects.get(name = 'foo')
pprint.pprint(item.__dict__, indent = 4)

这给出的输出类似于,json.dumps(..., indent = 4)但可以正确处理可能嵌入在模型实例中的怪异数据类型,例如ModelStateUUID

在Python 3.7上测试

The easier way is to just use pprint, which is in base Python

import pprint
item = MyDjangoModel.objects.get(name = 'foo')
pprint.pprint(item.__dict__, indent = 4)

This gives output that looks similar to json.dumps(..., indent = 4) but it correctly handles the weird data types that might be embedded in your model instance, such as ModelState and UUID, etc.

Tested on Python 3.7


回答 9

也许这对您有帮助。也许这并不能掩盖很多对很多的关系,但是当您要以json格式发送模型时,它非常方便。

def serial_model(modelobj):
  opts = modelobj._meta.fields
  modeldict = model_to_dict(modelobj)
  for m in opts:
    if m.is_relation:
        foreignkey = getattr(modelobj, m.name)
        if foreignkey:
            try:
                modeldict[m.name] = serial_model(foreignkey)
            except:
                pass
  return modeldict

Maybe this help you. May this not covert many to many relantionship, but es pretty handy when you want to send your model in json format.

def serial_model(modelobj):
  opts = modelobj._meta.fields
  modeldict = model_to_dict(modelobj)
  for m in opts:
    if m.is_relation:
        foreignkey = getattr(modelobj, m.name)
        if foreignkey:
            try:
                modeldict[m.name] = serial_model(foreignkey)
            except:
                pass
  return modeldict

回答 10

您见过的最佳解决方案。

将django.db.models.Model实例以及所有相关的ForeignKey,ManyToManyField和@Property函数字段转换为dict。

"""
Convert django.db.models.Model instance and all related ForeignKey, ManyToManyField and @property function fields into dict.
Usage:
    class MyDjangoModel(... PrintableModel):
        to_dict_fields = (...)
        to_dict_exclude = (...)
        ...
    a_dict = [inst.to_dict(fields=..., exclude=...) for inst in MyDjangoModel.objects.all()]
"""
import typing

import django.core.exceptions
import django.db.models
import django.forms.models


def get_decorators_dir(cls, exclude: typing.Optional[set]=None) -> set:
    """
    Ref: /programming/4930414/how-can-i-introspect-properties-and-model-fields-in-django
    :param exclude: set or None
    :param cls:
    :return: a set of decorators
    """
    default_exclude = {"pk", "objects"}
    if not exclude:
        exclude = default_exclude
    else:
        exclude = exclude.union(default_exclude)

    return set([name for name in dir(cls) if name not in exclude and isinstance(getattr(cls, name), property)])


class PrintableModel(django.db.models.Model):

    class Meta:
        abstract = True

    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self, fields: typing.Optional[typing.Iterable]=None, exclude: typing.Optional[typing.Iterable]=None):
        opts = self._meta
        data = {}

        # support fields filters and excludes
        if not fields:
            fields = set()
        else:
            fields = set(fields)
        default_fields = getattr(self, "to_dict_fields", set())
        fields = fields.union(default_fields)

        if not exclude:
            exclude = set()
        else:
            exclude = set(exclude)
        default_exclude = getattr(self, "to_dict_exclude", set())
        exclude = exclude.union(default_exclude)

        # support syntax "field__childField__..."
        self_fields = set()
        child_fields = dict()
        if fields:
            for i in fields:
                splits = i.split("__")
                if len(splits) == 1:
                    self_fields.add(splits[0])
                else:
                    self_fields.add(splits[0])

                    field_name = splits[0]
                    child_fields.setdefault(field_name, set())
                    child_fields[field_name].add("__".join(splits[1:]))

        self_exclude = set()
        child_exclude = dict()
        if exclude:
            for i in exclude:
                splits = i.split("__")
                if len(splits) == 1:
                    self_exclude.add(splits[0])
                else:
                    field_name = splits[0]
                    if field_name not in child_exclude:
                        child_exclude[field_name] = set()
                    child_exclude[field_name].add("__".join(splits[1:]))

        for f in opts.concrete_fields + opts.many_to_many:
            if self_fields and f.name not in self_fields:
                continue
            if self_exclude and f.name in self_exclude:
                continue

            if isinstance(f, django.db.models.ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    result = []
                    m2m_inst = f.value_from_object(self)
                    for obj in m2m_inst:
                        if isinstance(PrintableModel, obj) and hasattr(obj, "to_dict"):
                            d = obj.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )
                        else:
                            d = django.forms.models.model_to_dict(
                                obj,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        result.append(d)
                    data[f.name] = result
            elif isinstance(f, django.db.models.ForeignKey):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = None
                    try:
                        foreign_inst = getattr(self, f.name)
                    except django.core.exceptions.ObjectDoesNotExist:
                        pass
                    else:
                        if isinstance(foreign_inst, PrintableModel) and hasattr(foreign_inst, "to_dict"):
                            data[f.name] = foreign_inst.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        elif foreign_inst is not None:
                            data[f.name] = django.forms.models.model_to_dict(
                                foreign_inst,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )

            elif isinstance(f, (django.db.models.DateTimeField, django.db.models.DateField)):
                v = f.value_from_object(self)
                if v is not None:
                    data[f.name] = v.isoformat()
                else:
                    data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)

        # support @property decorator functions
        decorator_names = get_decorators_dir(self.__class__)
        for name in decorator_names:
            if self_fields and name not in self_fields:
                continue
            if self_exclude and name in self_exclude:
                continue

            value = getattr(self, name)
            if isinstance(value, PrintableModel) and hasattr(value, "to_dict"):
                data[name] = value.to_dict(
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name)
                )
            elif hasattr(value, "_meta"):
                # make sure it is a instance of django.db.models.fields.Field
                data[name] = django.forms.models.model_to_dict(
                    value,
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name),
                )
            elif isinstance(value, (set, )):
                data[name] = list(value)
            else:
                data[name] = value

        return data

https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52

Best solution you have ever see.

Convert django.db.models.Model instance and all related ForeignKey, ManyToManyField and @Property function fields into dict.

"""
Convert django.db.models.Model instance and all related ForeignKey, ManyToManyField and @property function fields into dict.
Usage:
    class MyDjangoModel(... PrintableModel):
        to_dict_fields = (...)
        to_dict_exclude = (...)
        ...
    a_dict = [inst.to_dict(fields=..., exclude=...) for inst in MyDjangoModel.objects.all()]
"""
import typing

import django.core.exceptions
import django.db.models
import django.forms.models


def get_decorators_dir(cls, exclude: typing.Optional[set]=None) -> set:
    """
    Ref: https://stackoverflow.com/questions/4930414/how-can-i-introspect-properties-and-model-fields-in-django
    :param exclude: set or None
    :param cls:
    :return: a set of decorators
    """
    default_exclude = {"pk", "objects"}
    if not exclude:
        exclude = default_exclude
    else:
        exclude = exclude.union(default_exclude)

    return set([name for name in dir(cls) if name not in exclude and isinstance(getattr(cls, name), property)])


class PrintableModel(django.db.models.Model):

    class Meta:
        abstract = True

    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self, fields: typing.Optional[typing.Iterable]=None, exclude: typing.Optional[typing.Iterable]=None):
        opts = self._meta
        data = {}

        # support fields filters and excludes
        if not fields:
            fields = set()
        else:
            fields = set(fields)
        default_fields = getattr(self, "to_dict_fields", set())
        fields = fields.union(default_fields)

        if not exclude:
            exclude = set()
        else:
            exclude = set(exclude)
        default_exclude = getattr(self, "to_dict_exclude", set())
        exclude = exclude.union(default_exclude)

        # support syntax "field__childField__..."
        self_fields = set()
        child_fields = dict()
        if fields:
            for i in fields:
                splits = i.split("__")
                if len(splits) == 1:
                    self_fields.add(splits[0])
                else:
                    self_fields.add(splits[0])

                    field_name = splits[0]
                    child_fields.setdefault(field_name, set())
                    child_fields[field_name].add("__".join(splits[1:]))

        self_exclude = set()
        child_exclude = dict()
        if exclude:
            for i in exclude:
                splits = i.split("__")
                if len(splits) == 1:
                    self_exclude.add(splits[0])
                else:
                    field_name = splits[0]
                    if field_name not in child_exclude:
                        child_exclude[field_name] = set()
                    child_exclude[field_name].add("__".join(splits[1:]))

        for f in opts.concrete_fields + opts.many_to_many:
            if self_fields and f.name not in self_fields:
                continue
            if self_exclude and f.name in self_exclude:
                continue

            if isinstance(f, django.db.models.ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    result = []
                    m2m_inst = f.value_from_object(self)
                    for obj in m2m_inst:
                        if isinstance(PrintableModel, obj) and hasattr(obj, "to_dict"):
                            d = obj.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )
                        else:
                            d = django.forms.models.model_to_dict(
                                obj,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        result.append(d)
                    data[f.name] = result
            elif isinstance(f, django.db.models.ForeignKey):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = None
                    try:
                        foreign_inst = getattr(self, f.name)
                    except django.core.exceptions.ObjectDoesNotExist:
                        pass
                    else:
                        if isinstance(foreign_inst, PrintableModel) and hasattr(foreign_inst, "to_dict"):
                            data[f.name] = foreign_inst.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        elif foreign_inst is not None:
                            data[f.name] = django.forms.models.model_to_dict(
                                foreign_inst,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )

            elif isinstance(f, (django.db.models.DateTimeField, django.db.models.DateField)):
                v = f.value_from_object(self)
                if v is not None:
                    data[f.name] = v.isoformat()
                else:
                    data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)

        # support @property decorator functions
        decorator_names = get_decorators_dir(self.__class__)
        for name in decorator_names:
            if self_fields and name not in self_fields:
                continue
            if self_exclude and name in self_exclude:
                continue

            value = getattr(self, name)
            if isinstance(value, PrintableModel) and hasattr(value, "to_dict"):
                data[name] = value.to_dict(
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name)
                )
            elif hasattr(value, "_meta"):
                # make sure it is a instance of django.db.models.fields.Field
                data[name] = django.forms.models.model_to_dict(
                    value,
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name),
                )
            elif isinstance(value, (set, )):
                data[name] = list(value)
            else:
                data[name] = value

        return data

https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52


回答 11

@zags的回答很全面,应该足够了,但是#5方法(这是IMO最好的方法)抛出错误,因此我改进了辅助函数。

由于OP请求转换many_to_many领域成主键,而不是对象的列表清单,我增强了功能,所以返回值现在为JSON序列化-通过将datetime物体进入strmany_to_many对象ID的列表。

import datetime

def ModelToDict(instance):
    '''
    Returns a dictionary object containing complete field-value pairs of the given instance

    Convertion rules:

        datetime.date --> str
        many_to_many --> list of id's

    '''

    concrete_fields = instance._meta.concrete_fields
    m2m_fields = instance._meta.many_to_many
    data = {}

    for field in concrete_fields:
        key = field.name
        value = field.value_from_object(instance)
        if type(value) == datetime.datetime:
            value = str(field.value_from_object(instance))
        data[key] = value

    for field in m2m_fields:
        key = field.name
        value = field.value_from_object(instance)
        data[key] = [rel.id for rel in value]

    return data

The answer from @zags is comprehensive and should suffice but the #5 method (which is the best one IMO) throws an error so I improved the helper function.

As the OP requested for converting many_to_many fields into a list of primary keys rather than a list of objects, I enhanced the function so the return value is now JSON serializable – by converting datetime objects into str and many_to_many objects to a list of id’s.

import datetime

def ModelToDict(instance):
    '''
    Returns a dictionary object containing complete field-value pairs of the given instance

    Convertion rules:

        datetime.date --> str
        many_to_many --> list of id's

    '''

    concrete_fields = instance._meta.concrete_fields
    m2m_fields = instance._meta.many_to_many
    data = {}

    for field in concrete_fields:
        key = field.name
        value = field.value_from_object(instance)
        if type(value) == datetime.datetime:
            value = str(field.value_from_object(instance))
        data[key] = value

    for field in m2m_fields:
        key = field.name
        value = field.value_from_object(instance)
        data[key] = [rel.id for rel in value]

    return data

如何避免“ RuntimeError:字典在迭代过程中更改大小”错误?

问题:如何避免“ RuntimeError:字典在迭代过程中更改大小”错误?

我检查了所有其他问题,并发现了相同的错误,但没有找到有帮助的解决方案= /

我有一个列表字典:

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

其中某些值为空。在创建这些列表的最后,我想在返回字典之前删除这些空列表。当前,我正在尝试执行以下操作:

for i in d:
    if not d[i]:
        d.pop(i)

但是,这给了我运行时错误。我知道您无法在字典中进行迭代时添加/删除字典中的元素…那么解决这个问题的方法是什么?

I have checked all of the other questions with the same error yet found no helpful solution =/

I have a dictionary of lists:

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

in which some of the values are empty. At the end of creating these lists, I want to remove these empty lists before returning my dictionary. Current I am attempting to do this as follows:

for i in d:
    if not d[i]:
        d.pop(i)

however, this is giving me the runtime error. I am aware that you cannot add/remove elements in a dictionary while iterating through it…what would be a way around this then?


回答 0

在Python 2.x中,调用keys会生成密钥的副本,您可以在修改时进行迭代dict

for i in d.keys():

请注意,这在Python 3.x中不起作用,因为它keys返回一个迭代器而不是列表。

另一种方法是用于list强制复制密钥。这也可以在Python 3.x中使用:

for i in list(d):

In Python 2.x calling keys makes a copy of the key that you can iterate over while modifying the dict:

for i in d.keys():

Note that this doesn’t work in Python 3.x because keys returns an iterator instead of a list.

Another way is to use list to force a copy of the keys to be made. This one also works in Python 3.x:

for i in list(d):

回答 1

只需使用字典理解将相关项目复制到新字典中

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}

为此,在Python 3

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.items() if v}
>>> d
{'a': [1], 'b': [1, 2]}

Just use dictionary comprehension to copy the relevant items into a new dict

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.iteritems() if v}
>>> d
{'a': [1], 'b': [1, 2]}

For this in Python 3

>>> d
{'a': [1], 'c': [], 'b': [1, 2], 'd': []}
>>> d = { k : v for k,v in d.items() if v}
>>> d
{'a': [1], 'b': [1, 2]}

回答 2

您只需要使用“复制”:

这样,您就可以遍历原始词典字段,并且可以随时更改所需的字典(d dict)。它适用于每个python版本,因此更加清晰。

In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

In [2]: for i in d.copy():
   ...:     if not d[i]:
   ...:         d.pop(i)
   ...:         

In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}

You only need to use “copy”:

On that’s way you iterate over the original dictionary fields and on the fly can change the desired dict (d dict). It’s work on each python version, so it’s more clear.

In [1]: d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}

In [2]: for i in d.copy():
   ...:     if not d[i]:
   ...:         d.pop(i)
   ...:         

In [3]: d
Out[3]: {'a': [1], 'b': [1, 2]}

回答 3

我会尽量避免一开始就插入空列表,但是通常会使用:

d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty

如果2.7之前:

d = dict( (k, v) for k,v in d.iteritems() if v )

要不就:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]

I would try to avoid inserting empty lists in the first place, but, would generally use:

d = {k: v for k,v in d.iteritems() if v} # re-bind to non-empty

If prior to 2.7:

d = dict( (k, v) for k,v in d.iteritems() if v )

or just:

empty_key_vals = list(k for k in k,v in d.iteritems() if v)
for k in empty_key_vals:
    del[k]

回答 4

对于Python 3:

{k:v for k,v in d.items() if v}

For Python 3:

{k:v for k,v in d.items() if v}

回答 5

在for循环中更改字典时,无法迭代字典。进行列表投射并遍历该列表,它对我有用。

    for key in list(d):
        if not d[key]: 
            d.pop(key)

You cannot iterate through a dictionary while its changing during for loop. Make a casting to list and iterate over that list, it works for me.

    for key in list(d):
        if not d[key]: 
            d.pop(key)

回答 6

在这种情况下,我喜欢制作一个深层副本并在修改原始字典的同时循环遍历该副本。

如果查找字段在列表中,则可以枚举列表的for循环,然后将位置指定为索引以访问原始字典中的字段。

For situations like this, i like to make a deep copy and loop through that copy while modifying the original dict.

If the lookup field is within a list, you can enumerate in the for loop of the list and then specify the position as index to access the field in the original dict.


回答 7

这为我工作:

dict = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(dict.items()):
    if (value == ''):
        del dict[key]
print(dict)
# dict = {1: 'a', 3: 'b', 6: 'c'}  

将字典项目转换为列表会创建其项目列表,因此您可以对其进行迭代并避免使用RuntimeError

This worked for me:

dict = {1: 'a', 2: '', 3: 'b', 4: '', 5: '', 6: 'c'}
for key, value in list(dict.items()):
    if (value == ''):
        del dict[key]
print(dict)
# dict = {1: 'a', 3: 'b', 6: 'c'}  

Casting the dictionary items to list creates a list of its items, so you can iterate over it and avoid the RuntimeError.


回答 8

dictc = {“ stName”:“ asas”} keys = dictc.keys()用于键入列表(键):dictc [key.upper()] =“新值” print(str(dictc))

dictc={“stName”:”asas”} keys=dictc.keys() for key in list(keys): dictc[key.upper()] =’New value’ print(str(dictc))


回答 9

运行时错误的原因是,您无法在迭代期间更改数据结构时对其进行迭代。

实现所需内容的一种方法是,使用列表附加要删除的键,然后在字典中遍历列表时在字典上使用pop函数删除标识的键。

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
pop_list = []

for i in d:
        if not d[i]:
                pop_list.append(i)

for x in pop_list:
        d.pop(x)
print (d)

The reason for the runtime error is that you cannot iterate through a data structure while its structure is changing during iteration.

One way to achieve what you are looking for is to use list to append the keys you want to remove and then use pop function on dictionary to remove the identified key while iterating through the list.

d = {'a': [1], 'b': [1, 2], 'c': [], 'd':[]}
pop_list = []

for i in d:
        if not d[i]:
                pop_list.append(i)

for x in pop_list:
        d.pop(x)
print (d)

回答 10

Python 3不允许在迭代(使用上面的循环)字典时删除。有多种选择可做。一种简单的方法是更改​​以下行

for i in x.keys():

for i in list(x)

Python 3 does not allow deletion while iterating (using for loop above) dictionary. There are various alternatives to do; one simple way is the to change following line

for i in x.keys():

With

for i in list(x)

如何保持键/值与声明的顺序相同?

问题:如何保持键/值与声明的顺序相同?

我有一本按照特定顺序声明的字典,并希望一直保持该顺序。键/值实际上不能根据它们的值按顺序保留,我只希望按声明的顺序保留。

因此,如果我有字典:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

如果我查看它或遍历它,则不是按此顺序进行的,有什么方法可以确保Python保持我声明键/值的显式顺序?

I have a dictionary that I declared in a particular order and want to keep it in that order all the time. The keys/values can’t really be kept in order based on their value, I just want it in the order that I declared it.

So if I have the dictionary:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

It isn’t in that order if I view it or iterate through it, is there any way to make sure Python will keep the explicit order that I declared the keys/values in?


回答 0

从Python 3.6开始,标准dict类型默认会保留插入顺序。

定义

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

将产生字典,其中的键按源代码中列出的顺序排列。

这是通过将一个带有整数的简单数组用于稀疏哈希表来实现的,其中这些整数索引到另一个存储键值对(加上计算得出的哈希值)的数组中。后面的数组恰好按插入顺序存储项目,实际上,整个组合使用的内存少于Python 3.5及之前版本中使用的实现。有关详细信息,请参阅Raymond Hettinger原始想法帖子

在3.6中,这仍被视为实现细节;请参阅Python 3.6文档的新增功能

此新实现的顺序保留方面被认为是实现细节,因此不应依赖(将来可能会更改,但是希望在更改语言规范之前,先在几个版本中使用该新dict实现该语言,为所有当前和将来的Python实现强制要求保留顺序的语义;这还有助于保留与仍旧有效的随机迭代顺序的旧版本语言(例如Python 3.5)的向后兼容性。

Python 3.7将此实现细节提升为语言规范,因此现在必须dict保留与该版本或更高版本兼容的所有Python实现中的顺序。参见BDFL的声明

在某些情况下,您可能仍想使用collections.OrderedDict()该类,因为它在标准dict类型的基础上提供了一些附加功能。例如是可逆的(这扩展到视图对象),并支持重新排序(通过move_to_end()方法)。

From Python 3.6 onwards, the standard dict type maintains insertion order by default.

Defining

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

will result in a dictionary with the keys in the order listed in the source code.

This was achieved by using a simple array with integers for the sparse hash table, where those integers index into another array that stores the key-value pairs (plus the calculated hash). That latter array just happens to store the items in insertion order, and the whole combination actually uses less memory than the implementation used in Python 3.5 and before. See the original idea post by Raymond Hettinger for details.

In 3.6 this was still considered an implementation detail; see the What’s New in Python 3.6 documentation:

The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5).

Python 3.7 elevates this implementation detail to a language specification, so it is now mandatory that dict preserves order in all Python implementations compatible with that version or newer. See the pronouncement by the BDFL.

You may still want to use the collections.OrderedDict() class in certain cases, as it offers some additional functionality on top of the standard dict type. Such as as being reversible (this extends to the view objects), and supporting reordering (via the move_to_end() method).


回答 1

from collections import OrderedDict
OrderedDict((word, True) for word in words)

包含

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

如果值是True(或任何其他不可变对象),则还可以使用:

OrderedDict.fromkeys(words, True)
from collections import OrderedDict
OrderedDict((word, True) for word in words)

contains

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

If the values are True (or any other immutable object), you can also use:

OrderedDict.fromkeys(words, True)

回答 2

我不会解释理论部分,而是给出一个简单的示例。

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

Rather than explaining the theoretical part, I’ll give a simple example.

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

回答 3

请注意,此答案适用于python3.7之前的python版本。CPython 3.6在大多数情况下都将插入顺序作为实现细节来维护。从Python3.7开始,已经声明实现必须维护插入顺序以使其兼容。


python字典是无序的。如果需要有序字典,请尝试collections.OrderedDict

注意,OrderedDict是在python 2.7中引入的标准库。如果您使用的是python的旧版本,则可以在ActiveState上找到有序词典的食谱。

Note that this answer applies to python versions prior to python3.7. CPython 3.6 maintains insertion order under most circumstances as an implementation detail. Starting from Python3.7 onward, it has been declared that implementations MUST maintain insertion order to be compliant.


python dictionaries are unordered. If you want an ordered dictionary, try collections.OrderedDict.

Note that OrderedDict was introduced into the standard library in python 2.7. If you have an older version of python, you can find recipes for ordered dictionaries on ActiveState.


回答 4

字典将使用使搜索有效的顺序,您无法更改该顺序,

您可以只使用对象列表(在简单情况下为2元素元组,甚至是一个类),然后将项目附加到末尾。然后,您可以使用线性搜索在其中查找项目。

或者,您可以创建或使用为维护顺序而创建的其他数据结构。

Dictionaries will use an order that makes searching efficient, and you cant change that,

You could just use a list of objects (a 2 element tuple in a simple case, or even a class), and append items to the end. You can then use linear search to find items in it.

Alternatively you could create or use a different data structure created with the intention of maintaining order.


回答 5

我在尝试弄清楚如何使OrderedDict工作时遇到了这篇文章。用于Eclipse的PyDev根本找不到OrderedDict,所以我最终决定根据字典的键值创建一个元组,因为我希望对它们进行排序。当我需要输出列表时,我只需遍历元组的值,然后将元组中迭代的“键”插入字典中,即可按需要的顺序检索值。

例:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

这有点麻烦,但是我时间紧迫,这是我想出的解决方法。

注意:其他人建议的列表列表方法对我来说真的没有意义,因为列表是有序的和索引的(并且结构与字典不同)。

I came across this post while trying to figure out how to get OrderedDict to work. PyDev for Eclipse couldn’t find OrderedDict at all, so I ended up deciding to make a tuple of my dictionary’s key values as I would like them to be ordered. When I needed to output my list, I just iterated through the tuple’s values and plugged the iterated ‘key’ from the tuple into the dictionary to retrieve my values in the order I needed them.

example:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

It’s a tad cumbersome, but I’m pressed for time and it’s the workaround I came up with.

note: the list of lists approach that somebody else suggested does not really make sense to me, because lists are ordered and indexed (and are also a different structure than dictionaries).


回答 6

您实际上无法使用字典来完成所需的工作。您已经d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}创建了词典。我发现一旦创建就无法保持秩序。我所做的是用对象制作了一个json文件:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

我用了:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

然后使用:

print json.dumps(r)

核实。

You can’t really do what you want with a dictionary. You already have the dictionary d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}created. I found there was no way to keep in order once it is already created. What I did was make a json file instead with the object:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

I used:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

then used:

print json.dumps(r)

to verify.


回答 7

from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])

回答 8

另一种选择是使用Pandas,dataframe因为它可以保证像dict这样的结构中项目的顺序和索引位置。

Another alternative is to use Pandas dataframe as it guarantees the order and the index locations of the items in a dict-like structure.


回答 9

一般情况下,你可以设计一个类,像一本字典的行为,主要是实现方法__contains____getitem____delitem____setitem__和更多一些。该类可以具有您喜欢的任何行为,例如,对键使用排序的迭代器…

Generally, you can design a class that behaves like a dictionary, mainly be implementing the methods __contains__, __getitem__, __delitem__, __setitem__ and some more. That class can have any behaviour you like, for example prividing a sorted iterator over the keys …


回答 10

如果您希望按特定顺序拥有字典,则还可以创建一个列表列表,其中第一项为键,第二项为值,看起来像此示例

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

if you would like to have a dictionary in a specific order, you can also create a list of lists, where the first item will be the key, and the second item will be the value and will look like this example

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

回答 11

开发Django项目时遇到类似的问题。我无法使用OrderedDict,因为我正在运行旧版本的python,因此解决方案是使用Django的SortedDict类:

https://code.djangoproject.com/wiki/SortedDict

例如,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

注意:此答案最初来自2011年。如果您可以访问python 2.7或更高版本,则应该可以访问现在的standard collections.OrderedDict,该线程中的其他示例已经提供了其中的很多示例。

I had a similar problem when developing a Django project. I couldn’t use OrderedDict, because I was running an old version of python, so the solution was to use Django’s SortedDict class:

https://code.djangoproject.com/wiki/SortedDict

e.g.,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

Note: This answer is originally from 2011. If you have access to Python version 2.7 or higher, then you should have access to the now standard collections.OrderedDict, of which many examples have been provided by others in this thread.


回答 12

您可以做与字典一样的事情。

创建一个列表并清空字典:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items

You can do the same thing which i did for dictionary.

Create a list and empty dictionary:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items