Làm thế nào để kiểm tra nếu một biến là một từ điển trong Python?


214

Làm thế nào bạn sẽ kiểm tra nếu một biến là một từ điển trong python?

Ví dụ: tôi muốn nó lặp qua các giá trị trong từ điển cho đến khi tìm thấy từ điển. Sau đó, lặp qua cái mà nó tìm thấy:

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}
for k, v in dict.iteritems():
    if ###check if v is a dictionary:
        for k, v in v.iteritems():
            print(k, ' ', v)
    else:
        print(k, ' ', v)

Ngoài ra stackoverflow.com/questions/378927/ đá (được đánh dấu là bản sao của một ở trên).
NPE


40
Không, đó không phải là câu hỏi tương tự. Câu trả lời cho câu hỏi này và các câu hỏi khác được liệt kê ở đây đều chứa thông tin cơ bản giống nhau. Nhưng câu trả lời cho "Cách kiểm tra xem một biến có phải là từ điển trong python không" là "Sử dụng loại () hoặc isinstance ()" sau đó dẫn đến một câu hỏi mới, đó là sự khác biệt giữa loại () và isinstance () . Nhưng người hỏi câu hỏi đầu tiên không thể biết điều đó cho đến khi câu hỏi đầu tiên được trả lời. Ergo, các câu hỏi khác nhau, vấn đề quan trọng khi bạn đang tìm kiếm câu hỏi của bạn trên trang web.

13
Tôi đồng ý với @mbakeranalecta Tôi đến đây để tìm câu trả lời cho câu hỏi "Làm thế nào để kiểm tra một biến là một từ điển trong Python?" và tôi sẽ không bao giờ nghĩ sẽ nhìn câu trả lời của mình vào "Sự khác biệt giữa isinstance () và type () trong python".
lodebari

5
Để kiểm tra xem một biến có phải là từ điển hay không, có lẽ bạn nên sử dụng isinstance(v, collections.abc.Mapping). Nói cách khác, đây không phải là bản sao chính xác của "Sự khác biệt giữa isinstance () và type ()."
Josh Kelley

Câu trả lời:


279

Bạn có thể sử dụng if type(ele) is dicthoặc sử dụng isinstance(ele, dict)cái nào sẽ hoạt động nếu bạn đã phân lớp dict:

d = {'abc':'abc','def':{'ghi':'ghi','jkl':'jkl'}}
for ele in d.values():
    if isinstance(ele,dict):
       for k, v in ele.items():
           print(k,' ',v)

70
Tôi đã bỏ phiếu cho câu trả lời này vì câu trả lời đúng cho câu hỏi chung là : isinstance(ele, collections.Mapping). Nó hoạt động cho dict(), collections.OrderedDict()collections.UserDict(). Ví dụ trong câu hỏi đủ cụ thể để câu trả lời của Padriac hoạt động, nhưng nó không đủ tốt cho trường hợp chung.
Alexander Ryzhov

3
Tôi đánh giá thấp câu trả lời này bởi vì nếu bạn định gọi ele.items()tại sao bạn lại kiểm tra loại? EAFP / vịt gõ hoạt động ở đây, chỉ cần bọc for k,v in ele.items()trong try...except (AttributeError, TypeError). Nếu ngoại lệ được nêu ra, bạn biết elekhông có itemsđiều gì mang lại khả năng lặp lại ...
cowbert

@Padraic Cickyham Trường hợp cạnh giả định của bạn sẽ yêu cầu lớp tùy chỉnh "100% không phải là chính tả" của bạn có một items()phương thức 2. điều này rất tình cờ mang lại một lần lặp và 3. trong đó mỗi phần tử của lần lặp đó có thể được biểu diễn dưới dạng 2 -tuple. Tại thời điểm này, đối tượng tùy chỉnh của bạn đã thực hiện một nửa lệnh. Đối với các mục đích của mã được liệt kê, chúng tôi chỉ quan tâm đến việc mở rộng có điều kiện của phần tử lồng nhau và đối tượng tùy chỉnh của bạn đã thực hiện điều đó. (Có một chút mỉa mai khi bạn chỉ trích bình luận của @Alexander Ryzhov vì quá chung chung nhưng bây giờ nêu lên một trường hợp chung)
cowbert

1
@PadraicCastyham Tôi không muốn dạy những người chống chế độ Python không quen thuộc với các mẫu chống Python. Có rất ít trường hợp sử dụng trong Python yêu cầu đánh máy rõ ràng - hầu hết xuất phát từ việc kế thừa một triển khai xấu để bắt đầu với ('đối tượng thần, ghi đè lên cấu trúc thư viện / ngôn ngữ tiêu chuẩn, v.v.) Câu hỏi ban đầu tự nó là một vấn đề XY. Tại sao OP cần kiểm tra loại? Bởi vì theo mã của họ, những gì họ thực sự muốn làm là kiểm tra xem một mục trong bộ sưu tập của họ có hoạt động giống như một bộ sưu tập hay không (thực hiện items()mang lại một lần lặp lồng nhau).
cowbert

4
@AlexanderRyzhov Tại sao không đăng cách tiếp cận đó như một câu trả lời? BTW như Josh Kelley đã nhận xét ở trên gợi ý collections.abc.Mapping, một ghi chú có thể phù hợp rằng chúng giống nhau, nhưng collections.abckhông có sẵn trước Python 3.3. collections.Mappingbí danh vẫn có sẵn trong Python 3.6, nhưng không được ghi lại, vì vậy có lẽ người ta nên chọn collections.abc.Maping.
Yushin Washio

3

OP không loại trừ biến bắt đầu, vì vậy, để hoàn thiện ở đây là cách xử lý trường hợp chung xử lý một từ điển được cho là có thể bao gồm các mục làm từ điển.

Ngoài ra sau khi Python tinh khiết (3.8) đề nghị cách để thử nghiệm cho từ điển trong các ý kiến trên.

from collections.abc import Mapping

dict = {'abc': 'abc', 'def': {'ghi': 'ghi', 'jkl': 'jkl'}}

def parse_dict(in_dict): 
    if isinstance(in_dict, Mapping):
        for k, v in in_dict.items():
            if isinstance(v, Mapping):
                for k, v in v.items():
                    print(k, v)
            else:
                print(k, v)

parse_dict(dict)

dict.iteritems()không tồn tại trong Python 3, bạn nên sử dụng dict.items()thay thế.
Arkelis

@Arkelis Rất tiếc, chỉ cần sao chép / dán phần đó, cảm ơn vì đã chỉ ra - sửa ngay bây giờ.
CodeMantle

3

Làm thế nào bạn sẽ kiểm tra nếu một biến là một từ điển trong Python?

Đây là một câu hỏi xuất sắc, nhưng thật không may là câu trả lời được đánh giá cao nhất dẫn đến một khuyến nghị kém, type(obj) is dict .

(Lưu ý rằng bạn cũng không nên sử dụng dict làm tên biến - đó là tên của đối tượng dựng sẵn.)

Nếu bạn đang viết mã sẽ được nhập và sử dụng bởi người khác, đừng cho rằng họ sẽ sử dụng trực tiếp nội dung chính - làm cho giả định đó làm cho mã của bạn không linh hoạt hơn và trong trường hợp này, hãy tạo ra các lỗi dễ dàng ẩn mà không làm lỗi chương trình .

Tôi thực sự khuyên bạn, vì mục đích chính xác, duy trì và linh hoạt cho người dùng trong tương lai, không bao giờ có các biểu thức kém linh hoạt, không phổ biến trong mã của bạn khi có các biểu thức thành ngữ, linh hoạt hơn.

islà một bài kiểm tra cho danh tính đối tượng . Nó không hỗ trợ kế thừa, nó không hỗ trợ bất kỳ sự trừu tượng hóa nào và nó không hỗ trợ giao diện.

Vì vậy, tôi sẽ cung cấp một số tùy chọn mà làm.

Hỗ trợ thừa kế:

Đây là khuyến nghị đầu tiên tôi sẽ làm, vì nó cho phép cho người dùng để cung cấp lớp con riêng của họ dict, hoặc một OrderedDict, defaultdicthoặc Countertừ các bộ sưu tập mô-đun:

if isinstance(any_object, dict):

Nhưng thậm chí còn có nhiều lựa chọn linh hoạt hơn.

Hỗ trợ trừu tượng:

from collections.abc import Mapping

if isinstance(any_object, Mapping):

Điều này cho phép người dùng mã của bạn sử dụng triển khai tùy chỉnh Bản đồ trừu tượng của riêng họ, bao gồm bất kỳ lớp con nào của dict và vẫn có được hành vi chính xác.

Sử dụng giao diện

Bạn thường nghe lời khuyên OOP, "lập trình cho một giao diện".

Chiến lược này tận dụng tính đa hình của Python hoặc gõ vịt.

Vì vậy, chỉ cần cố gắng truy cập vào giao diện, bắt các lỗi dự kiến ​​cụ thể ( AttributeErrortrong trường hợp không có .itemsTypeErrortrong trường hợp itemskhông thể gọi được) với một dự phòng hợp lý - và bây giờ bất kỳ lớp nào thực hiện giao diện đó sẽ cung cấp cho bạn các mục của nó (ghi chú .iteritems()đã biến mất trong Python 3):

try:
    items = any_object.items()
except (AttributeError, TypeError):
    non_items_behavior(any_object)
else: # no exception raised
    for item in items: ...

Có lẽ bạn có thể nghĩ rằng việc sử dụng kiểu gõ vịt như thế này đi quá xa trong việc cho phép quá nhiều thông tin sai, và có thể, tùy thuộc vào mục tiêu của bạn cho mã này.

Phần kết luận

Không sử dụng isđể kiểm tra các loại cho luồng điều khiển tiêu chuẩn. Sử dụng isinstance, xem xét các khái niệm trừu tượng như Mappinghoặc MutableMapping, và xem xét tránh kiểm tra kiểu hoàn toàn, sử dụng giao diện trực tiếp.

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.