Apa perbedaan antara kedua fragmen kode?
Menggunakan jenis()
:
import types
if type(a) is types.DictType:
do_something()
if type(b) in types.StringTypes:
do_something_else()
Menggunakan isinstance()
:
if isinstance(a, dict):
do_something()
if isinstance(b, str) or isinstance(b, unicode):
do_something_else()
Untuk meringkas isi lainnya (sudah baik!) jawaban, isinstance
melayani untuk warisan (turunan dari kelas yang diturunkan is an instance dari kelas dasar, juga), saat memeriksa kesetaraan jenis
tidak (hal ini menuntut identitas jenis dan menolak kasus subtipe, ALIAS subclass).
Biasanya, dalam Python, anda ingin kode anda untuk mendukung warisan, tentu saja (karena warisan ini sangat berguna, itu akan buruk untuk berhenti menggunakan kode milik anda dari menggunakan itu!), jadi isinstance
kurang buruk dari memeriksa identitas `jenis ini karena mulus mendukung warisan.
It's tidak bahwa isinstance
adalah good, pikiran anda—'s hanya less bad dari memeriksa kesetaraan jenis. Normal, Pythonic, solusi yang lebih disukai hampir selalu "bebek mengetik": mencoba menggunakan argumen as if itu adalah dari jenis tertentu yang diinginkan, lakukan hal ini dalam mencoba
/kecuali
pernyataan menangkap semua pengecualian yang bisa timbul jika argumen tidak dalam kenyataan bahwa jenis (atau jenis lain baik bebek-meniru itu;-), dan di kecuali
klausa, mencoba sesuatu yang lain (menggunakan argumen "jika" itu adalah beberapa jenis lain).
basestring
adalah, namun, cukup khusus kasus—builtin jenis yang ada hanya untuk membiarkan anda menggunakan isinstance
(kedua str
dan unicode
subclass basestring
). String adalah urutan-urutan (anda bisa loop di atas mereka, indeks mereka, iris mereka, ...), tetapi pada umumnya anda ingin memperlakukan mereka sebagai "skalar" jenis—it's agak incovenient (tapi cukup sering menggunakan kasus) untuk mengobati segala jenis senar (dan mungkin yang lain skalar jenis, yaitu, orang-orang yang anda bisa't loop pada) satu arah, semua kontainer (daftar, set, dicts, ...) dengan cara lain, dan basestring
plus isinstance
membantu anda melakukan itu—struktur keseluruhan dari idiom ini adalah sesuatu seperti:
if isinstance(x, basestring)
return treatasscalar(x)
try:
return treatasiter(iter(x))
except TypeError:
return treatasscalar(x)
Anda bisa mengatakan bahwa basestring
adalah sebuah Abstract Dasar Class ("ABC")—hal ini tidak ada beton fungsi untuk subclass, melainkan ada sebagai "penanda", terutama untuk digunakan dengan isinstance
. Konsep ini jelas salah satu yang berkembang di Python, karena PEP 3119, yang memperkenalkan generalisasi dari itu, diterima dan telah dilaksanakan mulai dengan Python 2.6 dan 3.0.
PEP membuat jelas bahwa, sementara Abc sering dapat pengganti bebek mengetik, ada umumnya tidak ada tekanan yang besar untuk melakukan itu (lihat di sini). Abc sebagai diimplementasikan dalam beberapa versi Python namun menawarkan barang ekstra: isinstance
(dan issubclass
) sekarang dapat berarti lebih dari sekedar "[contoh] kelas yang diturunkan" (khususnya, setiap kelas dapat "terdaftar" dengan ABC sehingga akan tampil sebagai subclass, dan contoh-contoh sebagai contoh ABC); dan Abc juga dapat menawarkan kenyamanan ekstra yang sebenarnya subclass dalam cara yang sangat alami melalui Template Metode pola desain aplikasi (lihat di sini dan di sini [[bagian II]] untuk informasi lebih lanjut tentang TM DP, secara umum dan secara khusus di Python, independen dari Abc).
Untuk mendasari mekanisme ABC dukungan seperti yang ditawarkan di Python 2.6, lihat di sini; untuk versi 3.1, yang sangat mirip, lihat di sini. Dalam kedua versi, standar perpustakaan modul koleksi (yang's 3.1 versi—untuk sangat mirip versi 2.6, lihat di sini) menawarkan beberapa berguna Abc.
Untuk tujuan ini menjawab, hal penting untuk mempertahankan tentang Abc (di luar yang bisa dibilang lebih alami penempatan untuk TM DP fungsi, dibandingkan dengan klasik Python alternatif mixin kelas seperti UserDict.DictMixin) adalah bahwa mereka membuat isinstance
(dan issubclass
) jauh lebih menarik dan meresap (dalam Python 2.6 dan maju) dari mereka digunakan untuk menjadi (in 2.5 dan sebelumnya), dan oleh karena itu, sebaliknya, membuat memeriksa jenis kesetaraan yang lebih buruk berlatih dalam beberapa versi Python dari yang sudah digunakan untuk menjadi.
Berikut ini's contoh di mana isinstance
mencapai sesuatu yang jenis
tidak:
class Vehicle:
pass
class Truck(Vehicle):
pass
dalam kasus ini, sebuah truk objek Kendaraan, tapi anda'akan mendapatkan ini:
isinstance(Vehicle(), Vehicle) # returns True
type(Vehicle()) == Vehicle # returns True
isinstance(Truck(), Vehicle) # returns True
type(Truck()) == Vehicle # returns False, and this probably won't be what you want.
Dengan kata lain, isinstance
ini berlaku untuk subclass, terlalu.
Juga lihat: https://stackoverflow.com/q/707674/1341006
Perbedaan antara
isinstance()
danjenis()
dalam Python?
Jenis-memeriksa dengan
isinstance(obj, Base)
memungkinkan untuk instance dari subclass dan beberapa mungkin basa:
isinstance(obj, (Base1, Base2))
sedangkan jenis pemeriksaan dengan
type(obj) is Base
hanya mendukung jenis dirujuk.
Sebagai sidenote, adalah
ini mungkin lebih tepat daripada
type(obj) == Base
karena kelas-kelas yang lajang.
Di Python, biasanya anda ingin untuk memungkinkan setiap jenis argumen anda, memperlakukannya seperti yang diharapkan, dan jika objek doesn't berperilaku seperti yang diharapkan, hal ini akan meningkatkan kesalahan yang tepat. Hal ini dikenal sebagai polimorfisme, juga dikenal sebagai duck-typing.
def function_of_duck(duck):
duck.quack()
duck.swim()
Jika kode di atas bekerja, kita dapat menganggap argumen kami adalah bebek. Dengan demikian kita bisa lulus dalam hal-hal lain yang sebenarnya sub-jenis bebek:
function_of_duck(mallard)
atau yang bekerja seperti bebek:
function_of_duck(object_that_quacks_and_swims_like_a_duck)
dan kode kita masih bekerja.
Namun, ada beberapa kasus di mana hal ini diinginkan untuk secara eksplisit jenis-check. Mungkin anda memiliki hal-hal yang masuk akal untuk melakukannya dengan berbagai jenis objek. Misalnya, Panda Dataframe objek dapat dibangun dari dicts atau rekaman. Dalam kasus seperti itu, kode anda perlu tahu apa jenis argumen itu semakin sehingga dapat menangani itu.
Jadi, untuk menjawab pertanyaan:
isinstance()
dan jenis()
dalam Python?Izinkan saya untuk menunjukkan perbedaan:
jenis
Mengatakan anda perlu untuk memastikan perilaku tertentu jika fungsi anda mendapat jenis tertentu dari argumen (common use-case untuk konstruktor). Jika anda memeriksa untuk tipe seperti ini:
def foo(data):
'''accepts a dict to construct something, string support in future'''
if type(data) is not dict:
# we're only going to test for dicts for now
raise ValueError('only dicts are supported for now')
Jika kita mencoba untuk lulus dalam dict yang merupakan subclass dari dict
(seperti yang seharusnya kita dapat, jika kita're mengharapkan kode kita untuk mengikuti prinsip Liskov Substitusi, bahwa subtipe dapat diganti jenis) kode kita istirahat!:
from collections import OrderedDict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
menimbulkan kesalahan!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in foo
ValueError: argument must be a dict
isinstance
Tapi jika kita menggunakan isinstance
, kita dapat mendukung Liskov Substitusi!:
def foo(a_dict):
if not isinstance(a_dict, dict):
raise ValueError('argument must be a dict')
return a_dict
foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))
kembali OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])
Pada kenyataannya, kita dapat melakukan bahkan lebih baik. koleksi
menyediakan Abstrak Kelas Dasar yang menegakkan minimal protokol untuk berbagai jenis. Dalam kasus kami, jika kita hanya mengharapkan Pemetaan
protokol, kita dapat melakukan hal berikut, dan kode kita menjadi lebih fleksibel:
from collections import Mapping
def foo(a_dict):
if not isinstance(a_dict, Mapping):
raise ValueError('argument must be a dict')
return a_dict
perlu dicatat bahwa jenis ini dapat digunakan untuk memeriksa terhadap beberapa kelas menggunakan
jenis(obj) dalam (A, B, C)
Ya, anda dapat menguji kesetaraan jenis, tapi bukan di atas, menggunakan beberapa dasar untuk kontrol aliran, kecuali anda secara khusus hanya memungkinkan orang-orang jenis:
isinstance(obj, (A, B, C))
Bedanya, sekali lagi, adalah bahwa isinstance
mendukung subclass yang dapat diganti untuk orang tua tanpa dinyatakan melanggar program, properti yang dikenal sebagai Liskov substitusi.
Bahkan lebih baik, meskipun, invert ketergantungan dan don't check untuk tipe tertentu di semua.
Jadi karena kita ingin mendukung mengganti subclass, dalam kebanyakan kasus, kita ingin menghindari jenis-memeriksa dengan jenis
dan lebih memilih type-checking dengan isinstance
- kecuali jika anda benar-benar perlu untuk mengetahui dengan tepat kelas contoh.
Yang terakhir ini lebih disukai, karena itu akan menangani subclass dengan benar. Pada kenyataannya, anda misalnya dapat ditulis bahkan lebih mudah karena isinstance()
's parameter kedua mungkin tupel:
if isinstance(b, (str, unicode)):
do_something_else()
atau, menggunakan basestring
kelas abstrak:
if isinstance(b, basestring):
do_something_else()
Menurut dokumentasi python berikut ini adalah pernyataan:
8.15. jenis — nama-Nama jenis built-in
Mulai di Python 2.2, built-in pabrik fungsi seperti
int()
danstr()
juga nama-nama untuk sesuai jenis.
Jadi isinstance()
harus diutamakan di atas type()
.
Praktis penggunaan perbedaan adalah bagaimana mereka menangani boolean
:
Benar
dan Salah
adalah kata kunci yang berarti 1
dan 0
di python. Dengan demikian,
isinstance(Benar, int)
dan
isinstance(Palsu, int)
keduanya kembali Benar
. Kedua boolean adalah contoh dari integer. tipe()
, bagaimanapun, adalah lebih pintar:
jenis(Benar) == int
kembali Palsu
.
Untuk perbedaan yang nyata, kita dapat menemukan itu di kode
, tapi aku bisa't menemukan mengimplementasikan perilaku default isinstance()
.
Namun kita bisa mendapatkan yang mirip satu abc.__instancecheck__ menurut __instancecheck__.
Dari atas abc.__instancecheck__
, setelah menggunakan test di bawah ini:
# file tree
# /test/__init__.py
# /test/aaa/__init__.py
# /test/aaa/aa.py
class b():
pass
# /test/aaa/a.py
import sys
sys.path.append('/test')
from aaa.aa import b
from aa import b as c
d = b()
print(b, c, d.__class__)
for i in [b, c, object]:
print(i, '__subclasses__', i.__subclasses__())
print(i, '__mro__', i.__mro__)
print(i, '__subclasshook__', i.__subclasshook__(d.__class__))
print(i, '__subclasshook__', i.__subclasshook__(type(d)))
print(isinstance(d, b))
print(isinstance(d, c))
<class 'aaa.aa.b'> <class 'aa.b'> <class 'aaa.aa.b'>
<class 'aaa.aa.b'> __subclasses__ []
<class 'aaa.aa.b'> __mro__ (<class 'aaa.aa.b'>, <class 'object'>)
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aaa.aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasses__ []
<class 'aa.b'> __mro__ (<class 'aa.b'>, <class 'object'>)
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'aa.b'> __subclasshook__ NotImplemented
<class 'object'> __subclasses__ [..., <class 'aaa.aa.b'>, <class 'aa.b'>]
<class 'object'> __mro__ (<class 'object'>,)
<class 'object'> __subclasshook__ NotImplemented
<class 'object'> __subclasshook__ NotImplemented
True
False
Saya mendapatkan kesimpulan ini,
Untuk type
:
# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__
Untuk isinstance
:
# guess from `abc.__instancecheck__`
return any(c in cls.__mro__ or c in cls.__subclasses__ or cls.__subclasshook__(c) for c in {INSTANCE.__class__, type(INSTANCE)})
BTW: lebih baik untuk tidak mencampur menggunakan relatif dan benar-benar impor
, gunakan benar-benar impor
dari project_dir( ditambahkan oleh sys.path
)