Làm cách nào để xóa khóa khỏi từ điển Python?


1767

Khi xóa khóa khỏi từ điển, tôi sử dụng:

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

Có một cách để làm điều này?


24
Kịch bản điểm chuẩn cho các phương pháp khác nhau được đề xuất trong câu trả lời cho câu hỏi này: gist.github.com/zigg/6280653
zigg

Câu trả lời:


2841

Để xóa khóa bất kể nó có trong từ điển hay không, hãy sử dụng dạng hai đối số của dict.pop():

my_dict.pop('key', None)

Điều này sẽ trở lại my_dict[key]nếu keytồn tại trong từ điển, và Nonenếu không. Nếu tham số thứ hai không được chỉ định (ví dụ. my_dict.pop('key')) Và keykhông tồn tại, a KeyErrorđược nâng lên.

Để xóa khóa được đảm bảo tồn tại, bạn cũng có thể sử dụng

del my_dict['key']

Điều này sẽ tăng KeyErrornếu khóa không có trong từ điển.


153
Đôi khi một lợi thế của việc sử dụng pop()hơn del: nó trả về giá trị cho khóa đó. Bằng cách này, bạn có thể nhận và xóa một mục từ một dict trong một dòng mã.
kratenko

7
Trong câu hỏi không bắt buộc phải giữ giá trị. Điều này sẽ chỉ thêm sự phức tạp không cần thiết. Câu trả lời từ @zigg (bên dưới) tốt hơn nhiều.
Salvatore Cosentino

10
@SalvatoreCosentino Tôi không thể theo dõi lập luận của bạn. Làm thế nào là mã trong câu trả lời này phức tạp hơn mã trong câu trả lời khác?
Sven Marnach

33
@SalvatoreCosentino Không, bỏ qua giá trị trả về của hàm không hiệu quả chút nào. Hoàn toàn ngược lại - giải pháp này nhanh hơn nhiều so với giải pháp try/ exceptnếu khóa không tồn tại. Bạn có thể tìm thấy cái này hay cái khác dễ đọc hơn, điều này tốt. Cả hai đều là Python thành ngữ, vì vậy hãy chọn bất cứ thứ gì bạn thích. Nhưng tuyên bố rằng câu trả lời này phức tạp hơn hoặc không hiệu quả chỉ đơn giản là không có ý nghĩa.
Sven Marnach

5
@ user5359531 Tôi không hiểu. Làm thế nào đây là một vấn đề? Không có phương thức nào trong các kiểu dựng sẵn của Python trả về self, vì vậy sẽ rất ngạc nhiên nếu phương thức này thực hiện.
Sven Marnach

353

Cụ thể để trả lời "có một cách làm việc này không?"

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

... tốt, bạn đã hỏi ;-)

Tuy nhiên, bạn nên cân nhắc rằng cách xóa đối tượng này khỏi một đối tượng không phảidictnguyên tử'key'thể có my_dicttrong ifcâu lệnh, nhưng có thể bị xóa trước khi delđược thực thi, trong trường hợp đó delsẽ thất bại với a KeyError. Với điều này, sẽ an toàn nhất khi sử dụngdict.pop hoặc một cái gì đó dọc theo dòng

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

trong đó, tất nhiên, chắc chắn không phải là một lót.


27
Vâng, popchắc chắn là ngắn gọn hơn, mặc dù có một lợi thế chính khi làm theo cách này: nó ngay lập tức làm rõ những gì nó đang làm.
zigg

4
Các try/excepttuyên bố là đắt hơn. Tăng một ngoại lệ là chậm.
Chris Barker

16
@ChrisBarker Tôi đã tìm thấy nếu khóa tồn tại, trynhanh hơn một chút, mặc dù nếu không, trythực sự là một thỏa thuận tốt chậm hơn. poplà khá nhất quán nhưng chậm hơn tất cả nhưng tryvới một khóa không có mặt. Xem gist.github.com/zigg/6280653 . Cuối cùng, điều đó phụ thuộc vào mức độ thường xuyên mà bạn mong đợi khóa thực sự có trong từ điển, và liệu bạn có cần nguyên tử hay không và tất nhiên, liệu bạn có tham gia tối ưu hóa sớm hay không;)
zigg

9
Tôi tin rằng giá trị của sự rõ ràng không nên bỏ qua. +1 cho điều này.
Juan Carlos Coto

2
liên quan đến chi phí thử / ngoại trừ, bạn cũng có thể đi if 'key' in mydict: #then del.... Tôi cần phải rút ra một khóa / val từ một lệnh để phân tích chính xác, pop không phải là một giải pháp hoàn hảo.
Marc

153

Tôi phải mất một thời gian để tìm ra chính xác những gì my_dict.pop("key", None)đang làm. Vì vậy, tôi sẽ thêm câu hỏi này như một câu trả lời để tiết kiệm thời gian cho người khác:

pop(key[, default])

Nếu khóa có trong từ điển, hãy xóa nó và trả về giá trị của nó, nếu không thì trả về mặc định . Nếu mặc định không được đưa ra và khóa không có trong từ điển, a KeyErrorsẽ được nâng lên.

Tài liệu


15
Chỉ cần gõ trợ giúp (dict.pop) trong trình thông dịch python.
David Mulder

13
help () và dir () có thể là bạn của bạn khi bạn cần biết điều gì đó.
David Mulder

3
hoặc dict.pop?trong IPython.
Erik Kaplun

51

del my_dict[key]nhanh hơn một chút so my_dict.pop(key)với xóa khóa khỏi từ điển khi khóa tồn tại

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

Nhưng khi khóa không tồn tại if key in my_dict: del my_dict[key]thì nhanh hơn một chút my_dict.pop(key, None). Cả hai đều nhanh hơn ít nhất ba lần so với deltrong câu lệnh try/ 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
Đo thời gian của một hoạt động nhanh như vậy là khá ngu ngốc. Mã của bạn có thể sẽ không nhận được nhanh hơn nhiều vì bạn đã thay đổi popa del. Tạo từ điển sẽ hoàn toàn lùn xóa những thứ từ nó.
Boris

1
@Boris - điều này hữu ích như một bài tập chung.
cúc

1
@daisy điều tôi đang nói là bạn nên chọn cú pháp dễ đọc nhất chứ không phải thao tác nhanh hơn 300 nano giây (nghĩa là sự khác biệt giữa delpoptừ bộ thời gian đầu tiên ở trên)
Boris

Ngoài ra các hoạt động này nhanh đến mức những thời gian này không đáng tin cậy.
Boris

46

Nếu bạn cần xóa rất nhiều khóa khỏi từ điển trong một dòng mã, tôi nghĩ rằng việc sử dụng map () khá ngắn gọn và Pythonic có thể đọc được:

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}

Và nếu bạn cần bắt lỗi trong đó bạn bật một giá trị không có trong từ điển, hãy sử dụng lambda bên trong map () như thế này:

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

hoặc trong python3, bạn phải sử dụng một danh sách hiểu thay thế:

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

Nó hoạt động. Và 'e' không gây ra lỗi, mặc dù myDict không có khóa 'e'.


42
Điều này sẽ không hoạt động trong Python 3 vì mapvà bạn bè bây giờ lười biếng và trả về các trình vòng lặp. Sử dụng mapcho các tác dụng phụ thường được coi là thực hành kém; một for ... invòng lặp tiêu chuẩn sẽ tốt hơn. Xem Lượt xem và vòng lặp thay vì danh sách để biết thêm thông tin.
Greg Krimer 7/11/2015

5
Bất kể sở thích và phong cách thực hành, việc hiểu danh sách vẫn nên hoạt động trong Py3 [myDict.pop(i, None) for i in ['a', 'c']], vì chúng cung cấp một sự thay thế chung cho map(và filter).
Michael Ekoka

@MichaelEkoka bạn không nên sử dụng danh sách hiểu cho tác dụng phụ của chúng, hãy sử dụng một for ... invòng lặp thông thường .
Boris

@Boris Có lẽ bạn đúng. Câu trả lời của tôi đặc biệt liên quan đến việc sử dụng map(), thường được sử dụng cho các tác dụng phụ của nó. Sự thay thế được đề xuất trong Python sự hiểu biết danh sách, mà theo tôi vẫn khá dễ đọc và nhẹ về mặt nhận thức như một lớp lót (xem câu hỏi). Chỉ được sử dụng cho các tác dụng phụ của chúng, cả hai cấu trúc thực sự dẫn đến một danh sách vô dụng, có thể không hiệu quả. Kể từ Python3, tôi không biết về một hàm tích hợp có thể lặp lại một cách an toàn và tao nhã thông qua biểu thức trình tạo, mà không có sản phẩm phụ tốn kém, ví dụ loop(d.pop(k) for k in ['a', 'b']).
Michael Ekoka

Tôi thích thú rằng câu trả lời được đánh giá cao nhất mọi thời đại của tôi bao gồm một số hack tôi sẽ không bao giờ sử dụng. Theo tôi, cách hiểu danh sách (phương án 3) là cách tiếp cận ít tệ nhất. Sử dụng cái đó
Marc Maxmeister

20

Bạn có thể sử dụng khả năng hiểu từ điển để tạo một từ điển mới với khóa đó đã bị xóa:

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

Bạn có thể xóa theo điều kiện. Không có lỗi nếu keykhông tồn tại.



7

Chúng ta có thể xóa khóa khỏi từ điển Python bằng một số cách tiếp cận sau.

Sử dụng deltừ khóa; nó gần như giống như cách bạn đã làm -

 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}

Hoặc là

Chúng ta có thể làm như sau:

Nhưng người ta nên nhớ rằng, trong quá trình này thực sự nó sẽ không xóa bất kỳ khóa nào khỏi từ điển thay vì làm cho khóa cụ thể bị loại trừ khỏi từ điển đó. Ngoài ra, tôi quan sát thấy rằng nó trả về một từ điển không được đặt hàng giống như myDict.

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

Nếu chúng ta chạy nó trong shell, nó sẽ thực thi một cái gì đó giống như {'five': 500, 'four': 400, 'three': 300, 'two': 200}- lưu ý rằng nó không giống như thứ tự myDict. Một lần nữa nếu chúng ta cố gắng in myDict, thì chúng ta có thể thấy tất cả các khóa bao gồm cả chúng ta đã loại trừ khỏi từ điển theo phương pháp này. Tuy nhiên, chúng ta có thể tạo một từ điển mới bằng cách gán câu lệnh sau vào một biến:

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

Bây giờ nếu chúng ta cố gắng in nó, thì nó sẽ tuân theo thứ tự cha mẹ:

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

Hoặc là

Sử dụng pop()phương pháp.

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

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

Sự khác biệt giữa delpoplà, bằng cách sử dụng pop()phương thức, chúng ta thực sự có thể lưu trữ giá trị của khóa nếu cần, như sau:

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

Ngã ba này ý chính để tham khảo trong tương lai, nếu bạn thấy hữu ích này.


1
Đừng sử dụng if myDict.get('one')để kiểm tra nếu có chìa khóa! Không thành công nếu myDict ['one'] có giá trị falsey. Ngoài ra, dicts không có một trật tự vốn có, vì vậy không có ý nghĩa gì khi đề cập đến nó.
Cướp

@Rob dicts được sắp xếp theo thứ tự chèn bắt đầu bằng CPython 3.6 và tất cả các cài đặt Python khác bắt đầu bằng 3.7.
Boris

4

Bạn có thể sử dụng xử lý ngoại lệ nếu bạn muốn rất dài dòng:

try: 
    del dict[key]

except KeyError: pass

Tuy nhiên, điều này chậm hơn so với pop()phương thức, nếu khóa không tồn tại.

my_dict.pop('key', None)

Sẽ không có vấn đề gì đối với một vài chìa khóa, nhưng nếu bạn thực hiện việc này nhiều lần, thì phương pháp sau là cách tốt hơn.

Cách tiếp cận nhanh nhất là đây:

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

Nhưng phương pháp này là nguy hiểm vì nếu 'key'được loại bỏ ở giữa hai dòng, a KeyErrorsẽ được nâng lên.


1

Tôi thích phiên bản bất biến

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

Một cách khác là sử dụng vật phẩm () + hiểu chính tả

các mục () kết hợp với hiểu chính tả cũng có thể giúp chúng tôi đạt được nhiệm vụ xóa cặp khóa-giá trị, nhưng, nó có nhược điểm là không phải là một kỹ thuật đọc chính tả. Trên thực tế, một lệnh mới nếu được tạo ngoại trừ khóa chúng tôi không muốn đưa vào.

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)) 

Đầu ra:

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

0

Bộ lọc đơn trên phím

  • trả về "khóa" và xóa nó khỏi my_dict nếu "key" tồn tại trong my_dict
  • trả về Không nếu "khóa" không tồn tại trong my_dict

điều này sẽ thay đổi my_dicttại chỗ (có thể thay đổi)

my_dict.pop('key', None)

Nhiều bộ lọc trên các phím

tạo ra một lệnh mới (bất biến)

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()
            )
    )
)
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.