在Python字典中截断键长度

0 投票
3 回答
1651 浏览
提问于 2025-04-18 08:25

我有一个Python字典,想把它放进mysql数据库里。问题是字典里的一个键(key)超过了64个字符,而mysql中列的最大长度就是64个字符。所以我需要把所有字典的键都截断到64个字符。

下面的代码在其他方面都能正常工作,但有一个键的长度超过了64个字符,那个键是:location_of_building_on_the_lot_if_garage_change_type_code_to_bgd_

data = {'x_coordinate': '1158020.73068669',
    'any_people_using_property_homeless_childen_gangs_': True,
    'police_district': '8',
    'location_of_building_on_the_lot_if_garage_change_type_code_to_bgd_': 'Front',
    'service_request_number': '14-00630589',
    'address_street_suffix': 'AVE',
    'y_coordinate': '1866585.99638448',
    'date_service_request_was_received': '2014-05-01T00:00:00',
    'address_street_number': '5719',
    'longitude': '-87.69612590561026',
    'latitude': '41.78965826126179',
    'address_street_name': 'FRANCISCO',
    'address_street_direction': 'S',
    'location': {'latitude': '41.78965826126179', 'needs_recoding': False, 'longitude': '-87.69612590561026'},
    'service_request_type': 'Vacant/Abandoned Building',
    'community_area': '63',
    'is_the_building_currently_vacant_or_occupied_': 'Vacant',
    'ward': '16',
    'is_building_open_or_boarded_': 'Open',
    'is_the_building_vacant_due_to_fire_': True,
    'zip_code': '60629'}


placeholders = ', '.join(['%s'] * len(data))
columns = ', '.join(data.keys())
sql = "INSERT INTO vacant_buildings (%s) VALUES (%s)" % (columns, placeholders)

我尝试把:

columns = ', '.join(data.keys())

改成

columns = ', '.join(data[:64].keys())

但出现了一个错误:TypeError: unhashable type

大家有什么想法吗?

3 个回答

0

虽然使用 .join() 可以解决这个问题,但它的速度比手动处理要慢一些:

columns = ''
for key in data.keys():
    columns += key[:64] +', '
sql = "INSERT INTO vacant_buildings (%s) VALUES (%s)" % (columns[:-2], placeholders)

这是因为 .join() 会对你已经遍历过的列表进行再次遍历,如果你处理的数据量很大,手动完成这个工作会快很多。

另外,注意 x[:-2] 在小数据插入时是可以的,但如果你把 VALUES 组合在一起,形成一个一次性执行的字符串,比如这样:

INSERT INTO table VALUES (1, 2, 3), (2,2,3), (3,2,3) ...

使用 data[:-2] 这个操作会变得非常慢,这时候如果能有一个计数器来检查你是否在列表的最后一个项目,那就太好了,这样就可以在最后跳过 +', '

如果你还要去掉一些值,最好在一个循环中完成,而不是两个:

for key, value in data.items():
    columns += key[:64] +', '

为了兼容未来的 Python 版本,建议使用 .format(),而不是 'something (%s) something else',因为后者已经过时了。

>>> a = [1, 2, 'test']
>>> '{} is {} with {}'.format(*a)
'1 is 2 with test'

总结:

手动构建你的字符串,而不是使用多个遍历函数来得到相同的结果。并且一定要使用 .format()!!

1

Pavel的回答很好,但如果你担心因为截断而导致的命名空间冲突,这里有个例子。

比如,location_of_building_on_the_lot_if_garage_change_type_code_to_bgd_location_of_building_on_the_lot_if_garage_change_type_code_to_bgd_hahaha这两个键在截断之前是不同的,直到你截断它们,这时它们就变成了相同的键。

keys = []
for k in data.keys():
    newKey = k[:64]
    count = 1
    while newKey in keys:
        alteration = str(count)
        newKey = newKey[:-len(alteration)] + alteration
        count += 1
    keys.append(newKey)

columns = ', '.join(keys)
2

你想要截断的是键(也就是字符串),而不是数据(数据是一个字典,它没有“长度”这个说法,指的不是“字符”)。

columns = ', '.join(d[:64] for d in data.keys())

撰写回答