Mengingat objek python yang berubah-ubah, apa cara terbaik untuk menentukan apakah itu angka? Siniis
didefinisikan sebagai acts like a number in certain circumstances
.
Misalnya, Anda menulis kelas vektor. Jika diberi vektor lain, Anda ingin mencari perkalian titik. Jika diberi skalar, Anda ingin menskalakan seluruh vektor.
Memeriksa apakah ada sesuatu yang int
, float
, long
, bool
menjengkelkan dan tidak mencakup ditetapkan pengguna objek yang mungkin bertindak seperti nomor. Tetapi, memeriksa __mul__
, misalnya, tidak cukup baik karena kelas vektor yang baru saja saya jelaskan akan __mul__
ditentukan, tetapi itu bukan jenis angka yang saya inginkan.
isinstance(value, Number) and type(value) != bool
Anda ingin memeriksa apakah ada objek
Jika Anda menggunakan Python 2.5 atau yang lebih lama, satu-satunya cara yang nyata adalah dengan memeriksa beberapa "keadaan tertentu" dan melihat.
Di 2.6 atau lebih baik, Anda dapat menggunakan
isinstance
dengan bilangan.Nomor - kelas dasar abstrak (ABC) yang ada persis untuk tujuan ini (lebih banyak ABC ada dicollections
modul untuk berbagai bentuk koleksi / kontainer, sekali lagi dimulai dengan 2.6; dan, juga hanya dalam rilis tersebut, Anda dapat dengan mudah menambahkan kelas dasar abstrak Anda sendiri jika perlu).Bach ke 2.5 dan sebelumnya, "dapat ditambahkan ke
0
dan tidak dapat diulang" bisa menjadi definisi yang baik dalam beberapa kasus. Tapi, Anda benar-benar perlu bertanya pada diri sendiri, apa yang Anda tanyakan sehingga apa yang ingin Anda anggap sebagai "angka" pasti bisa dilakukan , dan apa yang pasti tidak bisa dilakukan bisa dilakukan - dan periksa.Ini mungkin juga diperlukan di 2.6 atau yang lebih baru, mungkin untuk tujuan membuat pendaftaran Anda sendiri untuk menambahkan jenis yang Anda pedulikan yang belum didaftarkan
numbers.Numbers
- jika Anda ingin mengecualikan beberapa jenis yang mengklaim bahwa mereka adalah nomor tetapi Anda hanya tidak bisa menangani, itu bahkan lebih berhati-hati, karena ABC tidak memilikiunregister
metode [[misalnya Anda dapat membuat ABC Anda sendiriWeirdNum
dan mendaftarkan di sana semua jenis yang aneh untuk Anda, kemudian periksa terlebih dahulu untukisinstance
menebusnya sebelum Anda melanjutkan untuk memeriksaisinstance
normalnumbers.Number
untuk melanjutkan dengan sukses.BTW, jika dan ketika Anda perlu memeriksa apakah
x
bisa atau tidak bisa melakukan sesuatu, Anda biasanya harus mencoba sesuatu seperti:Kehadiran
__add__
per se memberi tahu Anda tidak ada yang berguna, karena misalnya semua urutan memilikinya untuk tujuan penggabungan dengan urutan lain. Pemeriksaan ini setara dengan definisi "bilangan adalah sesuatu yang urutan dari hal-hal seperti itu adalah argumen tunggal yang valid untuk fungsi bawaansum
", misalnya. Jenis yang benar-benar aneh (misalnya, yang memunculkan pengecualian "salah" saat dijumlahkan menjadi 0, seperti, katakanlah, aZeroDivisionError
atauValueError
& c) akan menyebarkan pengecualian, tetapi tidak apa-apa, beri tahu pengguna secepatnya bahwa jenis gila seperti itu tidak dapat diterima dalam keadaan baik perusahaan;-); tetapi, "vektor" yang dapat diringkas ke skalar (pustaka standar Python tidak memilikinya, tetapi tentu saja mereka populer sebagai ekstensi pihak ketiga) juga akan memberikan hasil yang salah di sini, jadi (mis.yang "tidak diizinkan untuk berulang" (misalnya, periksaiter(x)
kenaikan gajiTypeError
, atau untuk keberadaan metode khusus__iter__
- jika Anda berada di 2.5 atau lebih awal dan karenanya perlu pemeriksaan Anda sendiri).Sekilas tentang kerumitan seperti itu mungkin cukup untuk memotivasi Anda untuk mengandalkan kelas dasar abstrak kapan pun memungkinkan ... ;-).
sumber
Ini adalah contoh yang baik di mana pengecualian benar-benar menonjol. Lakukan saja apa yang akan Anda lakukan dengan tipe numerik dan tangkap
TypeError
dari yang lainnya.Tapi jelas, ini hanya memeriksa apakah suatu operasi berfungsi , bukan apakah masuk akal ! Satu-satunya solusi nyata untuk itu adalah jangan pernah mencampur jenis dan selalu tahu persis kelas tipe apa nilai Anda.
sumber
isinstance
sebenarnya dapat berguna dalam banyak kasus (== "periksa masuk akal" serta penerapan formal operasi). Pergeseran sulit untuk orang-orang lama yang hanya menggunakan Python, tetapi tren halus yang sangat penting dalam filosofi Python yang akan menjadi kesalahan serius untuk diabaikan.collections.Sequence
dan teman-teman). Tapi afaik, tidak ada kelas seperti itu untuk bilangan, vektor, atau objek matematika lainnya.Kalikan objek dengan nol. Setiap angka dikalikan nol adalah nol. Hasil lainnya berarti objek tersebut bukan angka (termasuk pengecualian)
Dengan demikian, penggunaan isNumber akan menghasilkan keluaran sebagai berikut:
Keluaran:
Mungkin ada beberapa objek non-angka di dunia yang mendefinisikan
__mul__
kembali nol ketika dikalikan dengan nol tetapi itu adalah pengecualian yang ekstrim. Solusi ini harus mencakup semua kode normal dan waras yang Anda buat / encouter.contoh numpy.array:
keluaran:
sumber
True * 0 == 0
int
jadi fungsi saya akan dengan benar mengatakan bahwa boolean adalah angka.Untuk menyusun ulang pertanyaan Anda, Anda mencoba untuk menentukan apakah sesuatu adalah kumpulan atau nilai tunggal. Mencoba membandingkan apakah sesuatu itu vektor atau angka membandingkan apel dengan jeruk - Saya dapat memiliki vektor string atau angka, dan saya dapat memiliki satu string atau satu nomor. Anda tertarik pada berapa banyak yang Anda miliki (1 atau lebih) , bukan jenis yang sebenarnya Anda miliki.
solusi saya untuk masalah ini adalah memeriksa apakah masukan adalah nilai tunggal atau kumpulan dengan memeriksa keberadaan
__len__
. Sebagai contoh:Atau, untuk pendekatan mengetik bebek, Anda dapat mencoba mengulanginya
foo
terlebih dahulu:Pada akhirnya, lebih mudah untuk menguji apakah sesuatu itu mirip vektor daripada menguji apakah sesuatu itu seperti skalar. Jika Anda memiliki nilai dari jenis yang berbeda (yaitu string, numerik, dll.) Yang masuk, maka logika program Anda mungkin memerlukan beberapa pekerjaan - bagaimana Anda akhirnya mencoba mengalikan string dengan vektor numerik di tempat pertama?
sumber
Untuk meringkas / mengevaluasi metode yang ada:
(Saya datang ke sini dengan pertanyaan ini )
Kode
sumber
float('nan'), 'nan', '123.45', '42', '42a', '0x8', '0xa'
math.isnan
Mungkin lebih baik melakukannya dengan cara lain: Anda memeriksa apakah itu vektor. Jika ya, Anda melakukan perkalian titik dan dalam semua kasus lain Anda mencoba perkalian skalar.
Memeriksa vektor itu mudah, karena itu harus dari jenis kelas vektor Anda (atau diwarisi darinya). Anda juga dapat mencoba melakukan perkalian titik terlebih dahulu, dan jika gagal (= ini bukan benar-benar vektor), maka kembali ke perkalian skalar.
sumber
Hanya untuk menambah. Mungkin kita bisa menggunakan kombinasi isinstance dan isdigit sebagai berikut untuk mengetahui apakah suatu nilai adalah angka (int, float, dll)
if isinstance (num1, int) atau isinstance (num1, float) atau num1.isdigit ():
sumber
Untuk kelas vektor hipotetis:
Misalkan
v
adalah vektor, dan kita mengalikannya denganx
. Jika masuk akal untuk mengalikan setiap komponenv
denganx
, kami mungkin bermaksud begitu, jadi coba dulu. Jika tidak, mungkin kita bisa memberi titik? Jika tidak, itu adalah kesalahan tipe.EDIT - kode di bawah ini tidak berfungsi, karena
2*[0]==[0,0]
alih-alih menaikkan fileTypeError
. Saya membiarkannya karena sudah dikomentari.sumber
x
adalah vektor maka[comp * x for comp in self]
akan menghasilkan produk luar darix
sebuahv
. Ini adalah tensor peringkat 2, bukan skalar.comp*x
akan skalax
olehcomp
, saya berasumsi bahwa itu akan menaikkan TypeError. Sayangnya, ini sebenarnya akan digabungkanx
dengancomp
waktu itu sendiri . Ups.x
adalah vektor maka ia harus memiliki__rmul__
metode (__rmul__ = __mul__
) sehinggacomp * x
harus menskalakanx
dengan cara yang sama seperti yangx * comp
dimaksudkan.Saya memiliki masalah serupa, saat menerapkan semacam kelas vektor. Salah satu cara untuk memeriksa suatu nomor adalah dengan mengubahnya menjadi satu, yaitu dengan menggunakan
Ini harus menolak kasus di mana x tidak dapat diubah menjadi angka; tetapi mungkin juga menolak jenis struktur mirip angka lain yang mungkin valid, misalnya bilangan kompleks.
sumber
Jika Anda ingin memanggil metode yang berbeda bergantung pada tipe argumen, lihat ke
multipledispatch
.Sayangnya, (setahu saya) kita tidak bisa menulis
@dispatch(Vector)
karena kita masih mendefinisikan tipenyaVector
, sehingga nama tipe itu belum ditentukan. Sebaliknya, saya menggunakan tipe dasarlist
, yang memungkinkan Anda bahkan menemukan perkalian titik dari aVector
dan alist
.sumber
Cara singkat dan sederhana:
Keluaran:
Jika objeknya adalah string, 'False' akan dikembalikan:
Keluaran:
sumber
Anda memiliki item data, katakanlah
rec_day
bahwa ketika ditulis ke file akan menjadifloat
. Tetapi selama pemrosesan program, ini bisa berupafloat
,int
ataustr
type (str
digunakan saat menginisialisasi record baru dan berisi nilai flag dummy).Anda kemudian dapat memeriksa untuk melihat apakah Anda memiliki nomor dengan ini
Saya telah menyusun program python dengan cara ini dan hanya memasukkan 'patch pemeliharaan' menggunakan ini sebagai pemeriksaan numerik. Apakah itu cara Pythonic? Kemungkinan besar tidak karena saya dulu memprogram di COBOL.
sumber
Anda bisa menggunakan fungsi isdigit ().
sumber