Pertanyaan Apa cara kanonik untuk memeriksa jenis dengan Python?


Apa cara terbaik untuk memeriksa apakah objek yang diberikan adalah tipe yang diberikan? Bagaimana dengan memeriksa apakah objek mewarisi dari tipe yang diberikan?

Katakanlah saya memiliki objek o. Bagaimana saya memeriksa apakah itu a str?


886
2017-09-30 11:00


asal


Jawaban:


Untuk memeriksa apakah o adalah contoh dari str atau subkelas mana pun dari str, gunakan ini berlaku (ini akan menjadi cara "kanonik"):

if isinstance(o, str):

Untuk memeriksa apakah jenis o persis str:

if type(o) is str:

Hal berikut juga berfungsi, dan dapat berguna dalam beberapa kasus:

if issubclass(type(o), str):

if type(o) in ([str] + str.__subclasses__()):

Lihat Fungsi Terpasang dalam Referensi Perpustakaan Python untuk informasi yang relevan.

Satu lagi catatan: dalam hal ini, jika Anda menggunakan python 2, Anda mungkin benar-benar ingin menggunakan:

if isinstance(o, basestring):

karena ini juga akan menangkap string Unicode (unicode bukan subkelas dari str; kedua str dan unicode adalah subclass dari basestring). Perhatikan itu basestring tidak ada lagi di python 3, di mana ada pemisahan yang ketat string (str) dan data biner (bytes).

Kalau tidak, isinstance menerima tupel kelas. Ini akan mengembalikan True jika x adalah turunan dari setiap subkelas dari salah satu (str, unicode):

if isinstance(o, (str, unicode)):

1104
2017-09-30 11:07



Itu paling Cara Pythonic untuk memeriksa jenis objek adalah ... tidak untuk memeriksanya.

Sejak Python mendorong Bebek Mengetik, Anda hanya harus mencoba menggunakan metode objek dengan cara Anda ingin menggunakannya. Jadi jika fungsi Anda mencari objek file yang bisa ditulis, tidak periksa bahwa itu adalah subkelas file, coba gunakan saja .write() metode!

Tentu saja, kadang-kadang abstraksi yang bagus ini memecah dan isinstance(obj, cls) adalah apa yang kamu butuhkan. Tetapi gunakan dengan hemat.


142
2017-09-30 17:40



isinstance(o, str) akan kembali true jika o adalah str atau tipe yang mewarisi dari str.

type(o) is str akan kembali true jika dan hanya jika o adalah sebuah str. Itu akan kembali false jika o adalah tipe yang mewarisi dari str. ----


38
2017-09-30 11:05



Setelah pertanyaan diajukan dan dijawab, petunjuk jenis ditambahkan ke Python. Ketik petunjuk dengan Python memungkinkan jenis untuk diperiksa tetapi dengan cara yang sangat berbeda dari bahasa yang diketik secara statis. Ketik petunjuk dalam Python mengaitkan jenis argumen yang diharapkan dengan fungsi sebagai data yang dapat diakses runtime yang terkait dengan fungsi dan ini memungkinkan untuk jenis yang akan diperiksa. Contoh sintaksis petunjuk jenis:

def foo(i: int):
    return i

foo(5)
foo('oops')

Dalam hal ini kita ingin kesalahan dipicu foo('oops') karena tipe argumen yang beranotasi adalah int. Petunjuk tipe tambahan tidak sebab kesalahan terjadi ketika skrip dijalankan secara normal. Namun, ia menambahkan atribut ke fungsi yang menjelaskan jenis yang diharapkan yang dapat ditanyakan dan digunakan oleh program lain untuk memeriksa kesalahan jenis.

Salah satu program lain yang dapat digunakan untuk menemukan kesalahan tipe ini mypy:

mypy script.py
script.py:12: error: Argument 1 to "foo" has incompatible type "str"; expected "int"

(Anda mungkin perlu menginstal mypy dari manajer paket Anda. Saya tidak berpikir itu datang dengan CPython tetapi tampaknya memiliki beberapa tingkat "resmi".)

Jenis pemeriksaan dengan cara ini berbeda dari jenis pemeriksaan dalam bahasa dikompilasi yang diketik secara statis. Karena jenisnya dinamis dalam Python, pengecekan jenis harus dilakukan saat runtime, yang membebankan biaya - bahkan pada program yang benar - jika kita bersikeras bahwa itu terjadi di setiap kesempatan. Pemeriksaan jenis eksplisit juga dapat lebih ketat daripada yang diperlukan dan menyebabkan kesalahan yang tidak perlu (mis. Apakah argumen benar-benar harus tepat list ketik atau apa saja yang cukup?).

Sisi positif dari pemeriksaan jenis eksplisit adalah bahwa ia dapat menangkap kesalahan lebih awal dan memberikan pesan kesalahan yang lebih jelas daripada mengetik bebek. Persyaratan yang tepat dari jenis bebek hanya dapat diekspresikan dengan dokumentasi eksternal (semoga menyeluruh dan akurat) dan kesalahan dari jenis yang tidak kompatibel dapat terjadi jauh dari tempat asalnya.

Petunjuk jenis Python dimaksudkan untuk menawarkan kompromi di mana jenis dapat ditentukan dan diperiksa tetapi tidak ada biaya tambahan selama eksekusi kode biasa.

Itu typing paket menawarkan variabel jenis yang dapat digunakan dalam petunjuk jenis untuk mengekspresikan perilaku yang dibutuhkan tanpa memerlukan jenis tertentu. Misalnya, itu termasuk variabel seperti Iterable dan Callable untuk petunjuk untuk menentukan kebutuhan untuk jenis apa pun dengan perilaku tersebut.

Meskipun petunjuk jenis adalah cara yang paling Pythonic untuk memeriksa jenis, sering kali lebih banyak Pythonic untuk tidak memeriksa jenis sama sekali dan bergantung pada mengetik bebek. Petunjuk jenis relatif baru dan juri masih belum tahu kapan mereka adalah solusi Pythonic paling banyak. Perbandingan yang relatif tidak kontroversial tetapi sangat umum: Ketik petunjuk memberikan bentuk dokumentasi yang dapat ditegakkan, memungkinkan kode untuk menghasilkan lebih awal dan lebih mudah untuk memahami kesalahan, dapat menangkap kesalahan bahwa mengetik bebek tidak dapat, dan dapat diperiksa secara statis (dalam akal tapi masih di luar waktu proses). Di sisi lain, mengetik bebek telah menjadi cara Pythonic untuk waktu yang lama, tidak memaksakan overhead kognitif mengetik statis, kurang verbose, dan akan menerima semua jenis yang layak dan kemudian beberapa.


17
2018-05-06 16:12



Berikut ini contoh mengapa mengetik bebek itu jahat tanpa mengetahui kapan itu berbahaya. Sebagai contoh: Berikut adalah kode Python (mungkin mengabaikan indentasi yang tepat), perhatikan bahwa ini Situasi dapat dihindari dengan memperhatikan isinstance dan issubclassfungsi untuk memastikan bahwa ketika Anda benar-benar membutuhkan bebek, Anda tidak mendapatkan bom.

class Bomb:
    def __init__(self):
        ""

    def talk(self):
        self.explode()

    def explode(self):
        print "BOOM!, The bomb explodes."

class Duck:
    def __init__(self):
        ""
    def talk(self):
        print "I am a duck, I will not blow up if you ask me to talk."    

class Kid:
    kids_duck = None

    def __init__(self):
        print "Kid comes around a corner and asks you for money so he could buy a duck."

    def takeDuck(self, duck):
        self.kids_duck = duck
        print "The kid accepts the duck, and happily skips along"

    def doYourThing(self):
        print "The kid tries to get the duck to talk"
        self.kids_duck.talk()

myKid = Kid()
myBomb = Bomb()
myKid.takeDuck(myBomb)
myKid.doYourThing()

12
2018-01-25 23:54



isinstance(o, str)

Tautkan ke dokumen


10
2017-09-30 11:01



Saya pikir hal yang keren tentang menggunakan bahasa dinamis seperti Python adalah Anda benar-benar tidak perlu memeriksa sesuatu seperti itu.

Saya hanya akan memanggil metode yang diperlukan pada objek Anda dan menangkapnya AttributeError. Nanti ini akan memungkinkan Anda untuk memanggil metode Anda dengan objek lain (yang tampaknya tidak berhubungan) untuk menyelesaikan tugas yang berbeda, seperti mengejek objek untuk pengujian.

Saya telah menggunakan ini banyak ketika mendapatkan data dari web dengan urllib2.urlopen() yang mengembalikan a file seperti obyek. Ini pada gilirannya dapat diteruskan ke hampir semua metode yang membaca dari file, karena mengimplementasikannya sama read() metode sebagai file nyata.

Tapi saya yakin ada waktu dan tempat untuk menggunakannya isinstance(), selain itu mungkin tidak akan ada :)


5
2017-09-30 13:33