Apa cara terbaik untuk memeriksa apakah objek yang diberikan adalah tipe yang diberikan? Bagaimana dengan mengecek apakah objek diwarisi dari jenis yang diberikan?
Katakanlah saya punya objek o
. Bagaimana saya memeriksa apakah itu str
?
Apa cara terbaik untuk memeriksa apakah objek yang diberikan adalah tipe yang diberikan? Bagaimana dengan mengecek apakah objek diwarisi dari jenis yang diberikan?
Katakanlah saya punya objek o
. Bagaimana saya memeriksa apakah itu str
?
Jawaban:
Untuk memeriksa apakah o
turunan dari str
atau subkelas apa pun str
, gunakan isinstance (ini akan menjadi cara "kanonik"):
if isinstance(o, str):
Untuk memeriksa apakah jenisnya o
tepat str
(tidak termasuk subkelas):
if type(o) is str:
Berikut ini juga berfungsi, dan dapat berguna dalam beberapa kasus:
if issubclass(type(o), str):
Lihat Fungsi Bawaan dalam Referensi Pustaka Python untuk informasi yang relevan.
Satu lagi catatan: dalam hal ini, jika Anda menggunakan Python 2, Anda mungkin sebenarnya ingin menggunakan:
if isinstance(o, basestring):
karena ini juga akan menangkap string Unicode ( unicode
bukan subkelas str
; keduanya str
dan unicode
merupakan subklas dari basestring
). Perhatikan bahwa basestring
tidak ada lagi di Python 3, di mana ada pemisahan ketat string ( str
) dan data biner ( bytes
).
Atau, isinstance
terima tupel kelas. Ini akan kembali True
jika o
merupakan turunan dari subkelas dari (str, unicode)
:
if isinstance(o, (str, unicode)):
type(a) is Object
begitu bukankah itu benar juga isinstance(a, Object)
. Namun, jika type(a) is SubClassOfObject
, maka type(a) is Object == False
, tetapi isinstance(a, Object) == True
. Baik?
a is b
berarti a dan b adalah hal yang persis sama, yaitu referensi ke entitas yang sama dalam memori. Jadi a
dan b
harus kelas yang sama persis, bukan subclass, seperti dengan isinstance()
. Lihat misalnya stackoverflow.com/a/133024/1072212
Cara paling Pythonic untuk memeriksa jenis objek adalah ... bukan untuk memeriksanya.
Karena Python mendorong Bebek Mengetik , Anda harus try...except
menggunakan metode objek seperti yang Anda inginkan. Jadi, jika fungsi Anda mencari objek file yang dapat ditulis, jangan periksa apakah itu subkelas file
, coba gunakan .write()
metodenya!
Tentu saja, kadang-kadang abstraksi yang bagus ini rusak dan isinstance(obj, cls)
itulah yang Anda butuhkan. Tapi gunakan hemat.
if hasattr(ob, "write") and callable(ob.write):
Atau menyimpan akses dict ...func = getattr(ob, "write", None)
if callable(func): ...
hasattr
hanya menekan sebuah AttributeError - Lihat: docs.python.org/3.4/library/functions.html#hasattr
isinstance(o, str)
akan kembali True
jika o
merupakan str
atau dari jenis yang mewarisi dari str
.
type(o) is str
akan kembali True
jika dan hanya jika o
str. Ini akan kembali False
jika o
dari tipe yang mewarisi dari str
.
isinstance
dan type(var) == type('')
tidak jelas.
Setelah pertanyaan diajukan dan dijawab, ketik petunjuk ditambahkan ke Python . Ketik petunjuk dalam Python memungkinkan jenis diperiksa tetapi dengan cara yang sangat berbeda dari bahasa yang diketik secara statis. Ketik petunjuk dalam Python mengaitkan tipe argumen yang diharapkan dengan fungsi sebagai data yang dapat diakses runtime yang terkait dengan fungsi dan ini memungkinkan tipe diperiksa. Contoh sintaks petunjuk jenis:
def foo(i: int):
return i
foo(5)
foo('oops')
Dalam hal ini kami ingin memicu kesalahan foo('oops')
karena jenis argumen yang dijelaskan int
. Petunjuk tipe yang ditambahkan tidak menyebabkan kesalahan terjadi ketika skrip dijalankan secara normal. Namun, itu menambahkan atribut ke fungsi yang menggambarkan tipe yang diharapkan yang dapat ditanyakan oleh program lain dan digunakan untuk memeriksa kesalahan tipe.
Salah satu dari program lain yang dapat digunakan untuk menemukan kesalahan jenis adalah 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 "pejabat".)
Pengecekan tipe dengan cara ini berbeda dengan pengecekan tipe dalam bahasa yang dikompilasi secara statis. Karena tipe bersifat dinamis dalam Python, pengecekan tipe harus dilakukan saat runtime, yang membebankan biaya - bahkan pada program yang benar - jika kita bersikeras bahwa itu terjadi pada setiap kesempatan. Pemeriksaan tipe eksplisit juga mungkin lebih ketat dari yang dibutuhkan dan menyebabkan kesalahan yang tidak perlu (mis. Apakah argumennya benar-benar harus list
bertipe tepat atau adakah yang cukup memadai?).
Kelebihan dari pemeriksaan tipe 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 dinyatakan dengan dokumentasi eksternal (mudah-mudahan itu menyeluruh dan akurat) dan kesalahan dari jenis yang tidak kompatibel dapat terjadi jauh dari tempat asalnya.
Petunjuk tipe Python dimaksudkan untuk menawarkan kompromi di mana tipe dapat ditentukan dan diperiksa tetapi tidak ada biaya tambahan selama eksekusi kode biasa.
The typing
variabel paket penawaran jenis yang dapat digunakan dalam jenis petunjuk untuk mengekspresikan perilaku yang dibutuhkan tanpa memerlukan jenis tertentu. Sebagai contoh, 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, seringkali bahkan lebih Pythonic untuk tidak memeriksa jenis sama sekali dan bergantung pada mengetik bebek. Petunjuk jenis relatif baru dan juri masih keluar ketika mereka solusi paling Pythonic. Perbandingan yang relatif tidak kontroversial tetapi sangat umum: Petunjuk jenis memberikan bentuk dokumentasi yang dapat ditegakkan, memungkinkan kode untuk menghasilkan lebih awal dan lebih mudah untuk memahami kesalahan, dapat menangkap kesalahan yang tidak dapat diketik oleh bebek, dan dapat diperiksa secara statis (dalam kondisi yang tidak biasa akal tapi masih di luar runtime). Di sisi lain, mengetik bebek telah menjadi cara Pythonic untuk waktu yang lama, tidak memaksakan overhead kognitif dari mengetik statis, kurang verbose, dan akan menerima semua jenis yang layak dan kemudian beberapa.
mypy
merupakan modul Python yang digunakan importlib
untuk mengakses data itu. Apakah ini "pemeriksaan tipe statis" adalah pertanyaan filosofis tetapi berbeda dari apa yang kebanyakan diharapkan karena penerjemah bahasa normal dan mesin impor terlibat.
Berikut adalah contoh mengapa mengetik bebek itu jahat tanpa mengetahui kapan itu berbahaya. Misalnya: Berikut adalah kode Python (mungkin menghilangkan indentasi yang tepat), perhatikan bahwa situasi ini dapat dihindari dengan menjaga fungsi isinstance dan issubclassof 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()
class EvilDuck(Duck)
dan mengganti pembicaraan (). Atau lebih mungkin,, class ChineseCancerDuck(Duck)
dengan efek samping buruk yang tidak muncul sampai bertahun-tahun kemudian. Anda akan lebih baik hanya mengawasi anak Anda (dan benar-benar menguji mainannya :)
__file__
atribut (biasanya digunakan untuk mengidentifikasi objek seperti file) berarti sesuatu yang lain.
isinstance(o, str)
Saya pikir hal 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 menangkap AttributeError
. Kemudian ini akan memungkinkan Anda untuk memanggil metode Anda dengan objek lain (yang tampaknya tidak terkait) untuk menyelesaikan tugas yang berbeda, seperti mengejek objek untuk pengujian.
Saya sering menggunakan ini ketika mengambil data dari web urllib2.urlopen()
yang mengembalikan file seperti objek. Ini pada gilirannya dapat diteruskan ke hampir semua metode yang membaca dari suatu file, karena itu mengimplementasikan read()
metode yang sama seperti file nyata.
Tapi saya yakin ada waktu dan tempat untuk menggunakan isinstance()
, kalau tidak mungkin tidak akan ada :)
Untuk validasi jenis yang lebih kompleks, saya suka pendekatan pengesahan typeguard berdasarkan anotasi petunjuk jenis python:
from typeguard import check_type
from typing import List
try:
check_type('mylist', [1, 2], List[int])
except TypeError as e:
print(e)
Anda dapat melakukan validasi yang sangat kompleks dengan cara yang sangat bersih dan mudah dibaca.
check_type('foo', [1, 3.14], List[Union[int, float]])
# vs
isinstance(foo, list) and all(isinstance(a, (int, float)) for a in foo)
Anda dapat memeriksa jenis variabel menggunakan __name__ jenis.
Ex:
>>> a = [1,2,3,4]
>>> b = 1
>>> type(a).__name__
'list'
>>> type(a).__name__ == 'list'
True
>>> type(b).__name__ == 'list'
False
>>> type(b).__name__
'int'
Kepada Hugo:
Mungkin Anda maksudkan list
bukan array
, tetapi itu menunjuk ke seluruh masalah dengan pengecekan tipe - Anda tidak ingin tahu apakah objek yang dimaksud adalah daftar, Anda ingin tahu apakah itu semacam urutan atau apakah itu objek tunggal. Jadi cobalah untuk menggunakannya seperti urutan.
Katakanlah Anda ingin menambahkan objek ke urutan yang ada, atau jika itu adalah urutan objek, tambahkan semuanya
try:
my_sequence.extend(o)
except TypeError:
my_sequence.append(o)
Salah satu trik dengan ini adalah jika Anda bekerja dengan string dan / atau urutan string - itu rumit, karena string sering dianggap sebagai objek tunggal, tetapi juga urutan karakter. Lebih buruk dari itu, karena itu benar-benar rangkaian string panjang tunggal.
Saya biasanya memilih untuk mendesain API saya sehingga hanya menerima nilai tunggal atau urutan - itu membuat segalanya lebih mudah. Tidak sulit untuk menempatkan [ ]
nilai tunggal Anda ketika Anda meneruskannya jika perlu.
(Meskipun ini dapat menyebabkan kesalahan dengan string, karena mereka memang terlihat seperti urutan.)
Cara sederhana untuk memeriksa jenis adalah membandingkannya dengan sesuatu yang jenisnya Anda ketahui.
>>> a = 1
>>> type(a) == type(1)
True
>>> b = 'abc'
>>> type(b) == type('')
True
Saya pikir cara terbaik adalah mengetik variabel Anda dengan baik. Anda dapat melakukan ini dengan menggunakan pustaka "mengetik".
Contoh:
from typing import NewType
UserId = NewType ('UserId', int)
some_id = UserId (524313
) `
Anda dapat memeriksa dengan baris di bawah ini untuk memeriksa tipe karakter mana nilai yang diberikan adalah:
def chr_type(chrx):
if chrx.isalpha()==True:
return 'alpha'
elif chrx.isdigit()==True:
return 'numeric'
else:
return 'nothing'
chr_type("12)