Objek TypeError: 'NoneType' tidak dapat diubah dengan Python

145

Apa artinya kesalahan TypeError: 'NoneType' object is not iterable?

Saya mengerti tentang kode Python ini:

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)
l --''''''---------------- '' '' '' '' '' '' '
sumber
Ini adalah salah satu kekecewaan saya yang menjengkelkan di Python. Ketika Nonedipaksa sebagai urutan itu harus menghasilkan urutan kosong, sama sekali tidak berbahaya.
nehem
7
@nehemiah: Python diketik dengan kuat (tidak diketik secara statis). Nonetidak pernah dipaksa untuk apa pun . Memiliki Nonediam-diam berperilaku seperti kesalahan jenis lain kulit; itu kebalikan dari "tidak berbahaya". Jika Anda membutuhkan placeholder palsu untuk urutan kosong, Anda dapat menggunakan ()atau ''/ "", keduanya merupakan lajang dan dapat dimuat semurah None. Jika Anda ingin memilih untuk secara diam-diam memperlakukan sesuatu yang salah sebagai urutan kosong, Anda bisa melakukannya for row in data or ():, tetapi tidak ada yang melakukannya, karena meneruskan Noneke fungsi yang mengharapkan urutan adalah kesalahan yang tidak boleh berlalu secara diam-diam.
ShadowRanger

Jawaban:

203

Itu berarti nilai datais None.

vanza
sumber
37
Benar, Tapi skenario umum yang penulis maksudkan di sini adalah benar-benar untuk melewatkan forloop alih-alih mengajukan pengecualian. Desain Python cacat di sini. Ketika Nonediperlakukan sebagai iterable itu harus mengembalikan daftar kosong setidaknya. Pengecualian ini tidak pernah membantu siapa pun dalam kehidupan nyata selain membuat kami memasukkan beberapa if data is not None:jenis penanganan yang jelek .
nehem
Untuk jawaban yang lebih konkrit, hal ini bisa terjadi jika fieldlistuntuk DictWriterini None!
Arklur
30
Cobafor i in data or []
BMW
4
@nehemiah: Sebenarnya, pendekatan yang benar adalah tidak memeriksa apakah dataada atau tidak None, tetapi membiarkan pengecualian terjadi. Anda ingin konsumen API Anda tahu kapan mereka salah menggunakannya. Menerima Nonesebagai urutan kosong akan membiarkan kesalahan seperti mylist = mylist.extend(morestuff), berhasil bersembunyi lebih lama; mereka pikir mereka extendmengedit list(dan mereka melakukannya, tetapi kemudian segera menggantinya dengan None), kemudian meneruskannya ke fungsi OP dan bertanya-tanya mengapa file tersebut kosong, tanpa kesalahan yang timbul dalam bentuk apa pun.
ShadowRanger
83

Penjelasan kesalahan: Objek 'NoneType' tidak dapat diubah

Dalam python2, NoneType adalah tipe None. Dalam Python3 NoneType adalah kelas None, misalnya:

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

Iterasi atas variabel yang memiliki nilai Tidak ada yang gagal:

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

Metode Python mengembalikan NoneType jika mereka tidak mengembalikan nilai:

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

Anda perlu memeriksa konstruksi perulangan Anda untuk NoneType seperti ini:

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 mengatakan hanya digunakan isuntuk memeriksa Nonekarena islebih kuat untuk memeriksa identitas. Jangan menggunakan operasi kesetaraan karena mereka dapat meludahkan implementasi bubble-up sendiri. Pedoman Gaya Pengodean Python - PEP-008

NoneTypes adalah Sneaky, dan dapat menyelinap masuk dari lambdas:

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

NoneType bukan kata kunci yang valid:

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

Rangkaian Nonedan string:

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

Apa yang terjadi di sini?

Penerjemah Python mengonversi kode Anda menjadi bytecode pyc. Mesin virtual Python memproses bytecode, ia menemukan looping construct yang mengatakan iterate pada variabel yang mengandung None. Operasi dilakukan dengan memohon__iter__ metode pada Tidak Ada.

Tidak ada yang tidak memiliki __iter__metode yang ditentukan, jadi mesin virtual Python memberi tahu Anda apa yang dilihatnya: bahwa NoneType tidak memiliki__iter__ metode.

Inilah sebabnya mengapa bebek-mengetik Python ideologi dianggap buruk. Programmer melakukan sesuatu yang sepenuhnya masuk akal dengan variabel dan pada saat runtime itu terkontaminasi oleh None, mesin virtual python mencoba untuk menjadi tentara, dan memunculkan sekelompok omong kosong yang tidak terkait di seluruh karpet.

Java atau C ++ tidak memiliki masalah ini karena program seperti itu tidak akan diizinkan untuk dikompilasi karena Anda belum menentukan apa yang harus dilakukan ketika Tidak ada yang terjadi. Python memberi banyak tali kepada programmer untuk menggantung dirinya sendiri dengan memungkinkan Anda melakukan banyak hal yang seharusnya tidak dapat diharapkan bekerja dalam keadaan luar biasa. Python adalah yes-man, mengatakan yes-sir ketika itu akan menghentikan Anda dari merugikan diri sendiri, seperti Java dan C ++.

Eric Leschinski
sumber
2
(a) Bingung NoneTypedan None(b) berpikir bahwa NameError: name 'NoneType' is not defineddan TypeError: cannot concatenate 'str' and 'NoneType' objectssama dengan TypeError: 'NoneType' object is not iterable(c) perbandingan antara Python dan java adalah "sekelompok omong kosong yang tidak berhubungan"
John Machin
3
Umm ... Java pada dasarnya akan memiliki masalah yang identik jika Anda beralih nullke fungsi yang mengharapkan jenis koleksi apa pun. C ++ akan memiliki masalah yang sama (tetapi umumnya hanya mati dalam segfault tanpa melaporkan penyebabnya) untuk nullptr(diakui, C ++ yang baik jarang menggunakan pointer, tetapi apa yang telah Anda tunjukkan adalah Python yang buruk, dan C ++ yang buruk dapat mati saat runtime dari nol juga) . Python melakukan hal yang benar di sini; itu bukan "serdadu", tetapi gagal saat Anda mencoba menggunakan Noneapa pun yang Nonetidak bisa dilakukan. Masalah Anda bukan dengan Python, itu dengan bahasa yang diketik secara dinamis pada umumnya.
ShadowRanger
63

Kode: for row in data:
Pesan kesalahan:TypeError: 'NoneType' object is not iterable

Obyek mana yang dikeluhkannya? Pilihan dua, rowdan data. Di for row in data, mana yang perlu diubah? Hanyadata .

Ada apa dengan ini data? Jenisnya adalah NoneType. Hanya Nonememiliki tipe NoneType. Begitudata is None .

Anda dapat memverifikasi ini dalam IDE, atau dengan memasukkan mis print "data is", repr(data)sebelum forpernyataan, dan menjalankan kembali.

Pikirkan tentang apa yang perlu Anda lakukan selanjutnya: Bagaimana seharusnya "tidak ada data" diwakili? Apakah kita menulis file kosong? Apakah kita membuat pengecualian atau mencatat peringatan atau tetap diam?

John Machin
sumber
18

Hal lain yang dapat menghasilkan kesalahan ini adalah ketika Anda menetapkan sesuatu yang sama dengan pengembalian dari suatu fungsi, tetapi lupa untuk benar-benar mengembalikan apa pun.

Contoh:

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)

Ini sedikit kesalahan yang sulit dikenali karena kesalahan juga dapat dihasilkan jika variabel baris tidak ada pada salah satu iterasi. Cara untuk menemukannya adalah bahwa jejak gagal pada baris terakhir dan tidak di dalam fungsi.

Jika Anda hanya mengembalikan satu variabel dari suatu fungsi, saya tidak yakin apakah kesalahan akan dihasilkan ... Saya menduga kesalahan "objek 'NoneType' tidak dapat diubah dengan Python" dalam kasus ini sebenarnya menyiratkan "Hei, saya mencoba untuk beralih pada nilai-nilai kembali untuk menempatkan mereka ke tiga variabel ini secara berurutan, tetapi saya hanya mendapatkan Tidak ada untuk beralih lagi "

Gunslingor atau
sumber
1
Inilah yang membawa saya ke sini. Jadi apa solusi Pythonic untuk situasi seperti itu?
Dr_Zaszuś
1
Sepertinya ada bantuan di sini: stackoverflow.com/questions/1274875/…
Dr_Zaszuś
8

Ini berarti bahwa variabel data melewati None (yang merupakan tipe NoneType), yang setara dengan nol . Jadi itu tidak dapat diubah sebagai daftar, seperti yang Anda coba lakukan.

tongkat
sumber
1
alangkah baiknya jika hanya diulang seperti daftar kosong ... akan membuat kode lebih bersih dan lebih sedikit pengecekan kesalahan
deltanine
4
@deltanine Itu akan membuat banyak masalah menjadi lebih sulit untuk dideteksi saya pikir. Saya senang Tidak ada yang berbeda dari iterable kosong. Jika Anda ingin perilaku yang dijelaskan, gunakan sajafor row in data or []:
Tandai
7

Anda memanggil write_file dengan argumen seperti ini:

write_file(foo, bar)

Tapi Anda belum mendefinisikan 'foo' dengan benar, atau Anda salah ketik dalam kode sehingga membuat variabel kosong baru dan meneruskannya.

clee
sumber
1

Bagi saya itu adalah kasus memiliki topi Groovy saya alih-alih yang Python 3 satu.

Lupa returnkata kunci di akhir adef fungsi.

Belum pernah mengkode Python 3 dengan sungguh-sungguh selama beberapa bulan. Sedang memikirkan pernyataan terakhir yang dievaluasi secara rutin dikembalikan sesuai cara Groovy.

Mengambil beberapa iterasi, melihat jejak stack, memasukkan try: ... except TypeError: ... blok debugging / melangkah melalui kode untuk mencari tahu apa yang salah.

Solusi untuk pesan itu tentu saja tidak membuat kesalahan melompat ke arahku.

JGFMK
sumber
Terima kasih. Ini persis masalah saya. Saya hampir menjadi gila ...
J. Brett Cunningham