Ответ 1
Вы можете использовать dict.update:
d.update({'a': 10, 'c': 200, 'c': 30})
Это приведет к перезаписыванию значений существующих ключей и добавлению новых пар ключ-значение для ключей, которые еще не существуют.
Можно ли присвоить значения более чем одним клавишам словаря более кратким способом, чем приведенный ниже?
Я имею в виду, пусть d
- словарь, инициализированный следующим образом:
d={'a':1,'b':2,'c':3}
Чтобы назначить значения нескольким клавишам, мне нужно сделать следующее:
d['a']=10
d['b']=200
d['c']=30
Могу ли я достичь такого же с чем-то вроде этого:
d['a','b','c']=10,200,30
Благодарю.
Вы можете использовать dict.update:
d.update({'a': 10, 'c': 200, 'c': 30})
Это приведет к перезаписыванию значений существующих ключей и добавлению новых пар ключ-значение для ключей, которые еще не существуют.
Вы всегда можете обернуть его в функцию:
def multiassign(d, keys, values):
d.update(zip(keys, values))
Даже если вы не знали об update
, вы можете написать это следующим образом:
def multiassign(d, keys, values):
for k, v in zip(keys, values):
d[k] = v
Или вы даже можете написать подклассом dict
который дает вам именно тот синтаксис, который вам нужен:
class EasyDict(dict):
def __getitem__(self, key):
if isinstance(key, tuple):
return [super().__getitem__(k) for k in key]
else:
return super().__getitem__(key)
def __setitem__(self, key, value):
if isinstance(key, tuple):
self.update(zip(key, value))
else:
super().__setitem__(key, value)
def __delitem__(self, key, value):
if isinstance(key, tuple):
for k in key: super().__delitem__(k)
else:
super().__setitem__(key, value)
Теперь:
>>> d = {'a': 1, 'd': 4}
>>> multiassign(d, ['a', 'b', 'c'], [10, 200, 300])
>>> d
{'a': 10, 'b': 200, 'c': 300, 'd': 4}
>>> d2 = EasyDict({'a': 1, 'd': 4})
>>> d2['a', 'b', 'c'] = 100, 200, 300
>>> d2
{'a': 10, 'b': 200, 'c': 300, 'd': 4}
Просто имейте в EasyDict
что, очевидно, больше не будет возможности использовать кортежи в качестве ключей в EasyDict
.
Кроме того, если вы собираетесь использовать это для чего-то серьезного, вы, вероятно, захотите улучшить обработку ошибок. (d['a', 'b'] = 1
даст критическое сообщение об zip argument #2 must support iteration
, d['a', 'b', 'c'] = 1, 2
будет молча работать и делать ничего для c
и т.д.)
Вы также можете просто использовать семантику множественных семантик:
d['a'], d['b'], d['c'] = 10, 200, 30
Сравнение скорости, от худшего до самого лучшего:
Python 3.5.3 |Continuum Analytics, Inc.| (default, May 15 2017, 10:43:23) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import numpy.random as nprnd
...: d = dict([(_, nprnd.rand()) for _ in range(1000)])
...: values = nprnd.randint(1000, size=10000)
...: keys = nprnd.randint(1000, size=10000)
...: def multiassign(d, keys, values):
...: for k, v in zip(keys, values):
...: d[k] = v
...:
...: d1 = dict(d)
...: %timeit multiassign(d1, keys, values)
...: d1 = dict(d)
...: %timeit {**d1, **{keys[i]: values[i] for i in range(len(keys))}}
...: d1 = dict(d)
...: %timeit d1.update(zip(keys, values))
...: d1 = dict(d)
...: %timeit {*d1.items(), *zip(keys, values)}
...: d1 = dict(d)
...: %timeit {**d1, **{key: value for key, value in zip(keys, values)}}
...: d1 = dict(d)
...: %timeit {**d1, **dict(zip(keys, values))}
4 ms ± 25.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.66 ms ± 29.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.17 ms ± 31.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.81 ms ± 98.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.38 ms ± 75.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1.96 ms ± 21 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Таким образом, явный победитель - это воссоздание словаря из словарей.
Вы можете использовать понимание словаря, например
letters, nos = ['a','b','c'], [1,2,3]
d = {letters[i]: nos[i] for i in range(len(nos))}
вывод:
{'a': 1, 'c': 3, 'b': 2}