Cách nhanh nhất để chuyển đổi các khóa và giá trị của dict từ `unicode` thành` str`?


81

Tôi đang nhận một mệnh lệnh từ một "lớp" mã mà trên đó một số tính toán / sửa đổi được thực hiện trước khi chuyển nó sang "lớp" khác. Các khóa và giá trị "chuỗi" của dict ban đầu là unicode, nhưng lớp mà chúng đang được chuyển vào chỉ chấp nhận str.

Điều này sẽ được gọi thường xuyên, vì vậy tôi muốn biết cách nhanh nhất để chuyển đổi một cái gì đó như:

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

...đến:

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

... ghi nhớ các giá trị không phải "chuỗi" cần phải giữ nguyên như kiểu ban đầu của chúng.

Có suy nghĩ gì không?

Câu trả lời:


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'}

Các giả định:

  • Bạn đã nhập mô-đun bộ sưu tập và có thể sử dụng các lớp cơ sở trừu tượng mà nó cung cấp
  • Bạn rất vui khi chuyển đổi bằng cách sử dụng mã hóa mặc định (sử dụng data.encode('utf-8')thay vì str(data)nếu bạn cần một mã hóa rõ ràng).

Nếu bạn cần hỗ trợ các loại vùng chứa khác, hy vọng rằng cách làm theo mẫu và thêm trường hợp cho chúng là điều hiển nhiên.


Và người ta sẽ làm gì nếu một số giá trị là danh sách / bộ / v.v.?
Phillip B Oldham

@Philip: Thêm trường hợp cho chúng. Đã cập nhật câu trả lời và sau đó được cập nhật lại cho các vùng chứa lồng nhau trong các vùng chứa.
RichieHindle

1
bạn quên tuple và frozenset, Richi
SilentGhost

3
Tại sao bạn sử dụng type(data)(map(convert, data))thay thế map(convert, data)?
Abbasov Alexander

4
@AbbasovAlexander: Để bạn lấy lại cùng loại mà bạn đã nhập - một bộ trở thành một bộ, một danh sách trở thành một danh sách, một bộ trở thành một tập hợp, v.v.
RichieHindle

23

Tôi biết tôi đến muộn với cái này:

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
Yup, đây có vẻ là cách làm đúng, nội tuyến và các phiên bản khác thực sự không đủ cho các kịch bản trong thế giới thực. Thật tệ là không có cách đệ quy nội tuyến đáng tin cậy để thực hiện điều này. Hoặc có thể có dựa trên quy ước json python str (...)?
jayunit 100

1
Đây là mục yêu thích của tôi, để chỉ chuyển đổi các phím, đó là những gì tôi đang tìm kiếm. Lỗi chính tả nhỏ: bạn cần thêm một () xung quanh đối số dict () được trả về.
ggll

Vấn đề duy nhất với giải pháp này là nếu các khóa của bạn KHÔNG phải là tất cả các chuỗi (tức là kiểu int)
MrWonderful

@MrWonderful và tại sao lại như vậy? Tôi không thể thấy bất kỳ sự cố nào khi gọi strvào số int
Germano

@Germano: Tất nhiên bạn có thể gọi str () trên int, nhưng bạn nhận được str .... không phải là int nữa. Vì vậy, loại khóa sẽ được thay đổi từ int thành str, điều này còn hơn cả việc thay đổi unicode thành str - câu hỏi ban đầu.
MrWonderful

13

Nếu bạn muốn thực hiện điều này nội tuyến và không cần truy xuất đệ quy, điều này có thể hoạt động:

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
Đối với 2.7 trở đi, điều này có thể được đơn giản hóa như sau:{ str(key):value for key,value in data.items() }
AnjoMan

4

cho một chính tả không lồng nhau (vì tiêu đề không đề cập đến trường hợp đó, nó có thể thú vị đối với những người khác)

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

1
{str (k): str (v) cho k, v trong my_dict.items ()}
yardstick17

Điều này đã giúp chuyển đổi các khóa của tôi thành các chuỗi mà tôi cần để so sánh với cột khung dữ liệu của mình
megamind

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

chuyển khóa và giá trị cho nó và thêm đệ quy vào mã của bạn để tính cho từ điển bên trong.


2

Để làm cho tất cả nội tuyến (không đệ quy):

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

0

Chỉ dùng print(*(dict.keys()))

Dấu * có thể được sử dụng để giải nén các thùng chứa, ví dụ danh sách. Để biết thêm thông tin về * hãy kiểm tra câu trả lời SO này .


Mặc dù mã này có thể giải quyết được vấn đề, một câu trả lời tốt nên giải thích những gì mã lệnh thực hiện và cách nó giúp.
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'}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.