Як видалити ключ із словника Python?


Відповіді:


2836

Щоб видалити ключ незалежно від того, чи є він у словнику, використовуйте формулу з двома аргументами dict.pop():

my_dict.pop('key', None)

Це повернеться, my_dict[key]якщо keyіснує в словнику та Noneінше. Якщо другий параметр не вказаний (тобто my_dict.pop('key')) і keyне існує, a KeyErrorпідвищується.

Щоб видалити ключ, який гарантовано існує, ви також можете використовувати

del my_dict['key']

Це призведе до появи а, KeyErrorякщо ключ відсутній у словнику.


152
Іноді перевага використання pop()over del: вона повертає значення для цього ключа. Таким чином ви можете отримати та видалити запис із диктату в одному рядку коду.
kratenko

7
У питанні не потрібно зберігати значення. Це лише додало б зайвої складності. Відповідь від @zigg (нижче) набагато краща.
Сальваторе Косентіно

10
@SalvatoreCosentino Я не можу дотримуватися ваших аргументів. Наскільки код у цій відповіді складніший, ніж код у іншій відповіді?
Свен Марнах

33
@SalvatoreCosentino Ні, ігнорування поверненого значення функції зовсім неефективно. Зовсім навпаки - це рішення набагато швидше, ніж try/ exceptрішення, якщо ключ не існує. Можливо, ви знайдете те чи інше простішим для читання, що добре. Обидва є ідіоматичним Python, тому вибирайте все, що вам більше подобається. Але стверджувати, що ця відповідь є більш складною або неефективною просто не має сенсу.
Свен Марнах

5
@ user5359531 Я не розумію. Як це проблема? Жоден із методів вбудованих типів Python не повертається self, тому було б досить дивно, якби це було.
Свен Марнах

352

Зокрема, щоб відповісти "чи існує спосіб, що це стосується однієї лінії?"

if 'key' in my_dict: del my_dict['key']

... ну, ви запитали ;-)

Однак ви повинні врахувати, що цей спосіб видалення об'єкта з a неdict є атомним - можливо, він 'key'може бути в my_dictході ifоператора, але може бути видалений до того, як delбуде виконано, і в цьому випадку delвийде з ладу a KeyError. Враховуючи це, було б найбезпечніше будь-яке використанняdict.pop або щось подібне до цього

try:
    del my_dict['key']
except KeyError:
    pass

що, звичайно, однозначно не є однолінійним.


27
Так, popце, безумовно, більш стисло, хоча є одна ключова перевага зробити це таким чином: відразу зрозуміло, що він робить.
зигг

4
try/exceptЗатвердження є більш дорогим. Підвищення винятку відбувається повільно.
Кріс Баркер

16
@ChrisBarker Я виявив, якщо ключ існує, tryнезначно швидше, хоча якщо цього не відбувається, tryце справді набагато повільніше. popдосить послідовний, але повільніший за всіх, але tryз відсутнім ключем. Див. Gist.github.com/zigg/6280653 . Зрештою, це залежить від того, як часто ви очікуєте, що ключ буде насправді у словнику, і чи потрібна вам атомність, і, звичайно, чи ви берете участь у передчасній оптимізації;
zigg

9
Я вважаю, що значення ясності не слід нехтувати. +1 для цього.
Хуан Карлос Кото

2
щодо витрат на спробу / крім, ви також можете піти if 'key' in mydict: #then del.... Мені потрібно було витягнути ключ / вал із дикта, щоб правильно розібратися, поп не був ідеальним рішенням.
Марк

152

Знадобилося мені трохи часу, щоб зрозуміти, що саме my_dict.pop("key", None)робить. Тож я додам це як відповідь, щоб заощадити час Google на Googling:

pop(key[, default])

Якщо ключ у словнику, видаліть його та поверніть його значення, інакше поверніть за замовчуванням . Якщо за замовчуванням не вказано і клавіша відсутня у словнику, KeyErrorпіднімається a .

Документація


15
Просто введіть довідку (dict.pop) в інтерпретаторі python.
Девід Малдер

13
help () та dir () можуть бути вашими друзями, коли вам потрібно знати, що щось робить.
Девід Малдер

3
або dict.pop?в IPython.
Ерік Каплун

50

del my_dict[key]трохи швидше, ніж my_dict.pop(key)для видалення ключа зі словника, коли ключ існує

>>> import timeit
>>> setup = "d = {i: i for i in range(100000)}"

>>> timeit.timeit("del d[3]", setup=setup, number=1)
1.79e-06
>>> timeit.timeit("d.pop(3)", setup=setup, number=1)
2.09e-06
>>> timeit.timeit("d2 = {key: val for key, val in d.items() if key != 3}", setup=setup, number=1)
0.00786

Але коли ключ не існує if key in my_dict: del my_dict[key] , трохи швидше, ніж my_dict.pop(key, None). Обидва принаймні втричі швидші, ніж delу try/ a except:

>>> timeit.timeit("if 'missing key' in d: del d['missing key']", setup=setup)
0.0229
>>> timeit.timeit("d.pop('missing key', None)", setup=setup)
0.0426
>>> try_except = """
... try:
...     del d['missing key']
... except KeyError:
...     pass
... """
>>> timeit.timeit(try_except, setup=setup)
0.133

1
Вимірювати терміни такої швидкої операції досить дурно. Ваш код, ймовірно, не стане набагато швидшим, оскільки ви змінили popна "А" del. Створення словника повністю видалить із нього карликові матеріали.
Борис

1
@Boris - це корисно як загальна вправа.
ромашка

1
@daisy , що я говорю, що ви повинні вибрати найбільш читаний синтаксис не операція , яка знаходиться в 300 наносекунд швидше (що буквально різниця між delі popз першого набору таймингов вище)
Борис

Також ці операції настільки швидкі, що ці терміни не є надійними.
Борис

45

Якщо вам потрібно видалити багато клавіш зі словника в одному рядку коду, я вважаю, що використання map () є досить лаконічним і пітонічним для читання:

myDict = {'a':1,'b':2,'c':3,'d':4}
map(myDict.pop, ['a','c']) # The list of keys to remove
>>> myDict
{'b': 2, 'd': 4}

І якщо вам потрібно вловлювати помилки, коли ви вводите значення, яке відсутнє у словнику, використовуйте лямбда всередині карти (), як це:

map(lambda x: myDict.pop(x,None), ['a', 'c', 'e'])
[1, 3, None] # pop returns
>>> myDict
{'b': 2, 'd': 4}

або в python3, замість цього ви повинні використовувати розуміння списку:

[myDict.pop(x, None) for x in ['a', 'c', 'e']]

Це працює. І "e" не спричинив помилку, навіть якщо в myDict не було ключа "e".


42
У Python 3 це не вийде, оскільки mapдрузі ледачі і повертають ітератори. Використання mapдля побічних ефектів, як правило, вважається поганою практикою; стандартний for ... inцикл буде краще. Додаткову інформацію див. У розділі Перегляди та ітератори замість списків .
Грег Крімер

5
Незалежно від смаку та стилю практики, розуміння списків все ще має працювати в Py3 [myDict.pop(i, None) for i in ['a', 'c']], оскільки вони пропонують загальну альтернативу mapfilter).
Майкл Екока

@MichaelEkoka ви не повинні використовувати розуміння списку для їх побічних ефектів, використовуйте звичайний for ... inцикл.
Борис

@Boris Ви, мабуть, праві. Моя відповідь спеціально стосується використання map(), яке часто використовується для його побічних ефектів. Рекомендована альтернатива в Python - це розуміння списку, яке, на мою думку, все ще є досить зрозумілим і когнітивно зрозумілим як однолінійний (див. Питання). Обидві конструкції, що використовуються лише для їх побічних ефектів, справді призводять до марного переліку, який може бути неефективним. Що стосується Python3, я не знаю про вбудовану функцію, яка може безпечно та елегантно повторювати вираз генератора без дорогої побічної продукції, наприклад loop(d.pop(k) for k in ['a', 'b']).
Майкл Екока

Мене дивує, що моя найвигідніша відповідь за весь час включає деякі хаки, які я ніколи не використовую. Розуміння списку (варіант 3) - це, на мою думку, найменш поганий підхід. Скористайтеся цим.
Марк Максмайстер

19

Ви можете використовувати розуміння словника, щоб створити новий словник із вилученим ключем:

>>> my_dict = {k: v for k, v in my_dict.items() if k != 'key'}

Ви можете видалити за умовами. Немає помилки, якщо її keyнемає.



7

Ми можемо видалити ключ із словника Python за допомогою наступних підходів.

Використання delключового слова; це майже такий самий підхід, як і ви -

 myDict = {'one': 100, 'two': 200, 'three': 300 }
 print(myDict)  # {'one': 100, 'two': 200, 'three': 300}
 if myDict.get('one') : del myDict['one']
 print(myDict)  # {'two': 200, 'three': 300}

Або

Ми можемо зробити наступне:

Але слід пам’ятати, що в цьому процесі він фактично не видалить жодного ключа зі словника, а не зробить конкретний ключ виключеним із цього словника. Крім того, я помітив, що він повертає словник, який не був замовлений таким же, як myDict.

myDict = {'one': 100, 'two': 200, 'three': 300, 'four': 400, 'five': 500}
{key:value for key, value in myDict.items() if key != 'one'}

Якщо ми запустимо його в оболонці, він виконає щось на кшталт {'five': 500, 'four': 400, 'three': 300, 'two': 200}- зауважте, що це не так, як упорядковано myDict. Знову ж таки, якщо ми спробуємо надрукувати myDict, то ми можемо побачити всі ключі, включаючи які ми виключили зі словника таким підходом. Однак ми можемо скласти новий словник, призначивши наступне твердження змінної:

var = {key:value for key, value in myDict.items() if key != 'one'}

Тепер якщо ми спробуємо роздрукувати його, то він буде виконувати батьківський порядок:

print(var) # {'two': 200, 'three': 300, 'four': 400, 'five': 500}

Або

Використання pop()методу.

myDict = {'one': 100, 'two': 200, 'three': 300}
print(myDict)

if myDict.get('one') : myDict.pop('one')
print(myDict)  # {'two': 200, 'three': 300}

Різниця між delі popполягає в тому, що, використовуючи pop()метод, ми можемо фактично зберігати значення ключа, якщо потрібно, наприклад:

myDict = {'one': 100, 'two': 200, 'three': 300}
if myDict.get('one') : var = myDict.pop('one')
print(myDict) # {'two': 200, 'three': 300}
print(var)    # 100

Скористайтеся цією суттю для подальшого ознайомлення, якщо вам це стане в нагоді.


1
Не використовуйте if myDict.get('one')для перевірки наявності ключа! Він не вдається, якщо myDict ['one'] має значення фальси. Також дикти не мають притаманного порядку, тому не має сенсу згадувати про це.
Роб

@Rob дикти впорядковуються порядком вставки, починаючи з CPython 3.6 та всіх інших реалізацій Python, починаючи з 3.7.
Борис

4

Ви можете використовувати обробку винятків, якщо хочете бути багатослівним:

try: 
    del dict[key]

except KeyError: pass

Однак це повільніше, ніж pop()метод, якщо ключ не існує.

my_dict.pop('key', None)

Для декількох клавіш не має значення, але якщо ви робите це неодноразово, то останній спосіб - краща ставка.

Найшвидший підхід такий:

if 'key' in dict: 
    del myDict['key']

Але цей спосіб небезпечний тим, що якщо 'key'його усунути між двома рядками, KeyErrorбуде піднято тест.


1

Я віддаю перевагу незмінній версії

foo = {
    1:1,
    2:2,
    3:3
}
removeKeys = [1,2]
def woKeys(dct, keyIter):
    return {
        k:v
        for k,v in dct.items() if k not in keyIter
    }

>>> print(woKeys(foo, removeKeys))
{3: 3}
>>> print(foo)
{1: 1, 2: 2, 3: 3}

1

Інший спосіб - за допомогою елементів () + розуміння диктанту

Пункти () у поєднанні з розумінням диктату також можуть допомогти нам досягти завдання видалення пари ключ-значення, але, у нього є недолік того, що він не є технікою заміщення диктату. Насправді новий дикт, якщо він створений, за винятком ключа, який ми не хочемо включати.

test_dict = {"sai" : 22, "kiran" : 21, "vinod" : 21, "sangam" : 21} 

# Printing dictionary before removal 
print ("dictionary before performing remove is : " + str(test_dict)) 

# Using items() + dict comprehension to remove a dict. pair 
# removes  vinod
new_dict = {key:val for key, val in test_dict.items() if key != 'vinod'} 

# Printing dictionary after removal 
print ("dictionary after remove is : " + str(new_dict)) 

Вихід:

dictionary before performing remove is : {'sai': 22, 'kiran': 21, 'vinod': 21, 'sangam': 21}
dictionary after remove is : {'sai': 22, 'kiran': 21, 'sangam': 21}

0

Єдиний фільтр на клавіші

  • поверніть "ключ" і видаліть його з my_dict, якщо "ключ" існує в my_dict
  • return None, якщо "ключ" не існує в my_dict

це зміниться my_dictна місці (змінне)

my_dict.pop('key', None)

Кілька фільтрів на клавішах

створити новий дикт (незмінний)

dic1 = {
    "x":1,
    "y": 2,
    "z": 3
}

def func1(item):
    return  item[0]!= "x" and item[0] != "y"

print(
    dict(
        filter(
            lambda item: item[0] != "x" and item[0] != "y", 
            dic1.items()
            )
    )
)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.