LoạiError: Đối tượng 'noneType' không thể lặp lại trong Python


145

Lỗi TypeError: 'NoneType' object is not iterablecó nghĩa là gì?

Tôi nhận được nó trên mã Python này:

def write_file(data, filename): # creates file and writes list to it
  with open(filename, 'wb') as outfile:
    writer = csv.writer(outfile)
    for row in data: # ABOVE ERROR IS THROWN HERE
      writer.writerow(row)

Đây là một trong những nỗi thất vọng khó chịu của tôi trong Python. Khi Noneđược ép thành chuỗi, nó phải tạo ra một chuỗi trống, hoàn toàn vô hại.
nehem

7
@nehemiah: Python được gõ mạnh (chỉ không được gõ tĩnh). Nonekhông bao giờ bị ép buộc với bất cứ điều gì . Có Nonehành vi âm thầm như các loại khác che giấu lỗi; điều đó trái ngược với "vô hại". Nếu bạn cần một trình giữ chỗ giả cho chuỗi trống, bạn có thể sử dụng ()hoặc ''/ "", cả hai đều là singletons và có thể được tải với giá rẻ như None. Nếu bạn muốn chọn tham gia để âm thầm coi bất cứ điều gì sai lệch là một chuỗi trống, bạn có thể làm điều đó for row in data or ():, nhưng không ai làm điều đó, bởi vì chuyển Noneđến một chức năng mong đợi một chuỗi là một lỗi không nên âm thầm vượt qua.
ShadowRanger

Câu trả lời:


203

Nó có nghĩa là giá trị của dataNone.


37
Đúng, nhưng tác giả kịch bản phổ biến dự định ở đây là hoàn toàn bỏ qua forvòng lặp thay vì đưa ra một ngoại lệ. Thiết kế của Python là thiếu sót ở đây. Khi Noneđược coi là một lần lặp, nó phải trả về danh sách trống ít nhất. Ngoại lệ này không bao giờ giúp được ai trong cuộc sống thực ngoài việc khiến chúng ta chen vào vài if data is not None:kiểu xử lý xấu xí .
nehem

Đối với một câu trả lời cụ thể hơn, nó có thể xảy ra nếu fieldlistcho DictWriterNone!
Arklur

30
Hãy thửfor i in data or []
BMW

4
@nehemiah: Thật ra, cách tiếp cận đúng không phải là kiểm tra xem datacó hay không None, mà là để ngoại lệ xảy ra. Bạn muốn người tiêu dùng API của bạn biết khi họ sử dụng không chính xác. Chấp nhận Nonenhư một chuỗi trống sẽ để cho những sai lầm như mylist = mylist.extend(morestuff), quản lý để che giấu lâu hơn; họ nghĩ rằng họ extended một list(và họ đã làm, nhưng ngay sau đó thay thế nó bằng None), sau đó vượt qua nó để chức năng của OP và thắc mắc tại sao các tập tin là trống rỗng, không có lỗi được nâng lên của bất cứ loại nào.
ShadowRanger

83

Giải thích về lỗi: đối tượng 'noneType' không thể lặp lại

Trong python2, noneType là loại Không có. Trong Python3 noneType là lớp Không có, ví dụ:

>>> print(type(None))     #Python2
<type 'NoneType'>         #In Python2 the type of None is the 'NoneType' type.

>>> print(type(None))     #Python3
<class 'NoneType'>        #In Python3, the type of None is the 'NoneType' class.

Lặp lại một biến có giá trị Không thất bại:

for a in None:
    print("k")     #TypeError: 'NoneType' object is not iterable

Các phương thức Python trả về noneType nếu chúng không trả về giá trị:

def foo():
    print("k")
a, b = foo()      #TypeError: 'NoneType' object is not iterable

Bạn cần kiểm tra các cấu trúc lặp của mình cho noneType như thế này:

a = None 
print(a is None)              #prints True
print(a is not None)          #prints False
print(a == None)              #prints True
print(a != None)              #prints False
print(isinstance(a, object))  #prints True
print(isinstance(a, str))     #prints False

Guido cho biết chỉ sử dụng isđể kiểm tra Noneismạnh mẽ hơn để kiểm tra danh tính. Đừng sử dụng các hoạt động bình đẳng bởi vì chúng có thể tạo ra viêm thực hiện bong bóng của riêng chúng. Nguyên tắc kiểu mã hóa của Python - PEP-008

Không ai là người lén lút và có thể lẻn vào từ lambdas:

import sys
b = lambda x : sys.stdout.write("k") 
for a in b(10): 
    pass            #TypeError: 'NoneType' object is not iterable 

NoneType không phải là một từ khóa hợp lệ:

a = NoneType     #NameError: name 'NoneType' is not defined

Nối Nonevà một chuỗi:

bar = "something"
foo = None
print foo + bar    #TypeError: cannot concatenate 'str' and 'NoneType' objects

Những gì đang xảy ra ở đây?

Trình thông dịch của Python đã chuyển đổi mã của bạn thành pyc byodeode. Máy ảo Python đã xử lý mã byte, nó gặp phải một cấu trúc lặp mà nói lặp lại qua một biến chứa Không có. Các hoạt động được thực hiện bằng cách gọi __iter__phương thức trên Không.

Không có __iter__phương thức nào được xác định, vì vậy máy ảo của Python cho bạn biết những gì nó thấy: rằng noneType không có __iter__phương thức.

Đây là lý do tại sao hệ tư tưởng gõ vịt của Python bị coi là xấu. Lập trình viên làm một cái gì đó hoàn toàn hợp lý với một biến và trong thời gian chạy, nó bị ô nhiễm bởi Không, máy ảo trăn cố gắng tiếp tục và tạo ra một loạt những điều vô nghĩa không liên quan trên thảm.

Java hoặc C ++ không có những vấn đề này bởi vì một chương trình như vậy sẽ không được phép biên dịch vì bạn chưa xác định phải làm gì khi Không có gì xảy ra. Python cung cấp cho lập trình viên rất nhiều dây để tự treo cổ bằng cách cho phép bạn làm nhiều việc không thể mong đợi để làm việc trong những trường hợp đặc biệt. Python là một người đàn ông có, nói có khi thưa ông khi điều đó ngăn bạn làm hại chính mình, giống như Java và C ++.


2
(a) Nhầm NoneTypelẫn và None(b) nghĩ rằng NameError: name 'NoneType' is not definedTypeError: cannot concatenate 'str' and 'NoneType' objectsgiống như TypeError: 'NoneType' object is not iterable(c) so sánh giữa Python và java là "một loạt những điều vô nghĩa không liên quan"
John Machin

3
Umm ... Java về cơ bản sẽ có các vấn đề giống hệt nhau nếu bạn chuyển nullđến một hàm mong đợi bất kỳ loại bộ sưu tập nào. C ++ sẽ có cùng một vấn đề (nhưng nói chung chỉ chết trong một segfault mà không báo cáo nguyên nhân) nullptr(phải thừa nhận, C ++ tốt hiếm khi sử dụng con trỏ, nhưng những gì bạn đã chứng minh là Python xấu và C ++ xấu cũng có thể chết khi chạy null. . Python đang làm điều đúng ở đây; đó không phải là "hàn gắn", đó là lỗi thời điểm bạn cố gắng sử dụng Nonecho bất cứ điều gì Nonekhông thể làm. Vấn đề của bạn không phải là với Python, nói chung là với các ngôn ngữ được gõ động.
ShadowRanger

63

Mã: Thông for row in data:
báo lỗi:TypeError: 'NoneType' object is not iterable

Đối tượng nào đang phàn nàn về nó? Lựa chọn của hai, rowdata. Trong for row in data, cái nào cần phải lặp lại? Chỉ data.

Có vấn đề datagì vậy? Loại của nó là NoneType. Chỉ Nonecó loại NoneType. Vì vậy data is None.

Bạn có thể xác minh điều này trong IDE hoặc bằng cách chèn ví dụ print "data is", repr(data)trước forcâu lệnh và chạy lại.

Hãy suy nghĩ về những gì bạn cần làm tiếp theo: "Không có dữ liệu" nên được trình bày như thế nào? Chúng tôi có viết một tập tin trống không? Chúng ta có đưa ra một ngoại lệ hoặc ghi lại một cảnh báo hoặc giữ im lặng?


18

Một điều khác có thể tạo ra lỗi này là khi bạn đang thiết lập một cái gì đó bằng với trả về từ một hàm, nhưng quên thực sự trả về bất cứ thứ gì.

Thí dụ:

def foo(dict_of_dicts):
    for key, row in dict_of_dicts.items():
        for key, inner_row in row.items():
            Do SomeThing
    #Whoops, forgot to return all my stuff

return1, return2, return3 = foo(dict_of_dicts)

Đây là một lỗi nhỏ khó phát hiện vì lỗi cũng có thể được tạo ra nếu biến hàng xảy ra là Không có trên một trong các lần lặp. Cách để phát hiện ra nó là dấu vết thất bại ở dòng cuối cùng và không nằm trong hàm.

Nếu bạn chỉ trả về một biến từ một hàm, tôi không chắc liệu lỗi có được tạo ra không ... Tôi nghi ngờ lỗi "Đối tượng noneType" không thể lặp lại trong Python "trong trường hợp này thực sự ngụ ý" Này, tôi đang thử lặp lại các giá trị trả về để gán chúng cho ba biến này theo thứ tự nhưng tôi chỉ nhận được Không có gì để lặp lại "


1
Đây chính xác là những gì đã đưa tôi đến đây. Vậy giải pháp Pythonic cho tình huống như vậy là gì?
Dr_Zaszuś

1
Có vẻ như có một số trợ giúp ở đây: stackoverflow.com/questions/1274875/ cấp
Dr_Zaszuś

8

Điều đó có nghĩa là biến dữ liệu đang truyền Không có (loại Không có Loại), tương đương với không có gì . Vì vậy, nó không thể được lặp lại như một danh sách, như bạn đang cố gắng làm.


1
Sẽ thật tuyệt nếu chỉ lặp đi lặp lại như một danh sách trống ... sẽ cần mã sạch hơn và ít kiểm tra lỗi hơn
deltanine

4
@deltanine Nó sẽ làm cho rất nhiều vấn đề trở nên khó phát hiện hơn tôi nghĩ. Tôi mừng vì không có gì khác với một lần lặp trống. Nếu bạn muốn hành vi được mô tả của mình, chỉ cần sử dụngfor row in data or []:
Đánh dấu

7

Bạn đang gọi write_file với các đối số như thế này:

write_file(foo, bar)

Nhưng bạn đã không xác định chính xác 'foo' hoặc bạn có một lỗi đánh máy trong mã của mình để nó tạo ra một biến trống mới và chuyển nó vào.


1

Đối với tôi đó là trường hợp có chiếc mũ Groovy của tôi thay vì chiếc Python 3.

Quên returntừ khóa ở cuối defhàm.

Đã không mã hóa Python 3 một cách nghiêm túc trong một vài tháng. Đã nghĩ rằng tuyên bố cuối cùng được đánh giá trong thói quen đã được trả lại theo cách Groovy.

Đã thực hiện một vài lần lặp, nhìn vào dấu vết ngăn xếp, chèn try: ... except TypeError: ...khối gỡ lỗi / bước mã thông báo để tìm ra điều gì sai.

Giải pháp cho tin nhắn chắc chắn không làm cho lỗi nhảy ra khỏi tôi.


Cảm ơn bạn. Đây chính xác là vấn đề của tôi. Tôi sắp phát điên ...
J. Brett Cickyham
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.