将dict的键和值从unicode转换为str的最快方法?


81

我正在从一个代码“层”收到命令,对该命令进行一些计算/修改,然后再将其传递到另一个“层”。原始dict的键和“字符串”值是unicode,但是将它们传递到的层只接受str

这将经常被调用,所以我想知道什么是最快的转换方法:

{ u'spam': u'eggs', u'foo': True, u'bar': { u'baz': 97 } }

...至:

{ 'spam': 'eggs', 'foo': True, 'bar': { 'baz': 97 } }

……请记住,非“字符串”值必须保持其原始类型。

有什么想法吗?

Answers:


150
DATA = { u'spam': u'eggs', u'foo': frozenset([u'Gah!']), u'bar': { u'baz': 97 },
         u'list': [u'list', (True, u'Maybe'), set([u'and', u'a', u'set', 1])]}

def convert(data):
    if isinstance(data, basestring):
        return str(data)
    elif isinstance(data, collections.Mapping):
        return dict(map(convert, data.iteritems()))
    elif isinstance(data, collections.Iterable):
        return type(data)(map(convert, data))
    else:
        return data

print DATA
print convert(DATA)
# Prints:
# {u'list': [u'list', (True, u'Maybe'), set([u'and', u'a', u'set', 1])], u'foo': frozenset([u'Gah!']), u'bar': {u'baz': 97}, u'spam': u'eggs'}
# {'bar': {'baz': 97}, 'foo': frozenset(['Gah!']), 'list': ['list', (True, 'Maybe'), set(['and', 'a', 'set', 1])], 'spam': 'eggs'}

假设:

  • 您已经导入了collections模块,并可以利用其提供的抽象基类
  • 您很乐意使用默认编码进行转换(如果需要显式编码,请使用data.encode('utf-8')而不是str(data))。

如果您需要支持其他容器类型,希望可以很明显地遵循该模式并为其添加案例。


如果某些值是列表/集合/等,该怎么办?
菲利普·奥德汉

@Philip:为他们添加案例。答案已更新,然后再次更新以将容器嵌套在容器中。
RichieHindle

1
你忘元组和frozenset,RICHI
SilentGhost

3
为什么要使用type(data)(map(convert, data))代替map(convert, data)
Abbasov Alexander

4
@AbbasovAlexander:这样您就可以得到与输入的类型相同的元素-元组变成元组,列表变成列表,集合变成集合,依此类推。
RichieHindle

23

我知道我迟到了:

def convert_keys_to_string(dictionary):
    """Recursively converts dictionary keys to strings."""
    if not isinstance(dictionary, dict):
        return dictionary
    return dict((str(k), convert_keys_to_string(v)) 
        for k, v in dictionary.items())

1
是的,这似乎是正确的做法,内联和其他版本确实不足以用于实际场景。太糟糕了,没有可靠的内联无递归方法来完成此任务。还是基于python str(...)json约定?
jayunit100

1
这是我的最爱,只转换键,这就是我想要的。小错字:您需要在返回的dict()参数周围附加一个()。
ggll 2013年

此解决方案的唯一问题是,如果您的键不是全部字符串(即int类型)
MrWonderful

@MrWonderful,为什么?我看不到调用strint的任何问题
Germano

@Germano:当然,您可以在一个int上调用str(),但是您得到一个str ....不再是一个int。所以关键的类型会从int到海峡,这是可以改变原来的问题-不是改变UNICODE到海峡。
MrWonderful '16

13

如果您想内联执行此操作,并且不需要递归下降,则可以这样做:

DATA = { u'spam': u'eggs', u'foo': True, u'bar': { u'baz': 97 } }
print DATA
# "{ u'spam': u'eggs', u'foo': True, u'bar': { u'baz': 97 } }"

STRING_DATA = dict([(str(k), v) for k, v in data.items()])
print STRING_DATA
# "{ 'spam': 'eggs', 'foo': True, 'bar': { u'baz': 97 } }"

4
对于2.7及更高版本,可以将其简化如下:{ str(key):value for key,value in data.items() }
AnjoMan 2015年

4

对于非嵌套字典(由于标题未提及该情况,因此对其他人可能很有趣)

{str(k): str(v) for k, v in my_dict.items()}

1
{STR(K):STR(v)中K,V在my_dict.items()}
yardstick17

这有助于将我的密钥转换为需要与数据

3
def to_str(key, value):
    if isinstance(key, unicode):
        key = str(key)
    if isinstance(value, unicode):
        value = str(value)
    return key, value

将键和值传递给它,然后将递归添加到您的代码中以说明内部字典。


2

使其全部内联(非递归):

{str(k):(str(v) if isinstance(v, unicode) else v) for k,v in my_dict.items()}

0

只需使用 print(*(dict.keys()))

*可用于拆箱,例如清单。有关*的更多信息,请检查此答案


尽管此代码可能会解决这个问题,一个很好的答案应该解释什么代码的作用和如何它可以帮助。
BDL

0
>>> d = {u"a": u"b", u"c": u"d"}
>>> d
{u'a': u'b', u'c': u'd'}
>>> import json
>>> import yaml
>>> d = {u"a": u"b", u"c": u"d"}
>>> yaml.safe_load(json.dumps(d))
{'a': 'b', 'c': 'd'}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.