Type () ve isinstance () arasındaki farklar nelerdir?


1247

Bu iki kod parçası arasındaki farklar nelerdir?

Kullanma type():

import types

if type(a) is types.DictType:
    do_something()
if type(b) in types.StringTypes:
    do_something_else()

Kullanma isinstance():

if isinstance(a, dict):
    do_something()
if isinstance(b, str) or isinstance(b, unicode):
    do_something_else()

Not: Değilse strve unicode(sadece kontrol edebileceğiniz yerlerde basestring), birden fazla türe karşı kontrol etmek için bir demet kullanabilirsiniz. Olmadığını kontrol etmek için somethingIS intveya strkullanım isinstance(something, (int, str)).
xuiqzy

Yanıtlar:


1270

Diğer (zaten iyi!) Cevapların içeriğini özetlemek için, isinstancemirasa hitap eder (türetilmiş bir sınıfın örneği de temel sınıfın bir örneğidir), eşitliğini kontrol typeetmez (türlerin kimliğini talep eder ve örnekleri reddeder) alt tipler, AKA alt sınıfları).

Normalde, Python'da, kodunuzun mirasını desteklemesini istersiniz, elbette (miras çok kullanışlı olduğu için, kodunuzu kullanarak kodunuzu kullanmaktan kaçınmak kötü olurdu!), Bu yüzden sorunsuz bir şekilde desteklediği için s isinstancekimliğini kontrol etmekten daha az kötüdür. typemiras.

O değil de bu isinstanceolduğunu iyi , sen-o akla sadece var daha az kötü eşitlik türlerinin denetimini daha. Normal, Pythonic, tercih edilen çözüm neredeyse her zaman "ördek yazma" dır: bağımsız değişkeni istenen belirli bir türdeymiş gibi kullanmayı deneyin , argüman gerçekte değilse, ortaya çıkabilecek tüm istisnaları yakalayan bir try/ exceptifadesinde yapın yazın (veya güzel bir şekilde onu taklit eden başka bir tür ;-) ve exceptyan tümcesinde başka bir şey deneyin ("başka bir türdeymiş gibi" argümanını kullanarak).

basestring olduğu , ancak, mevcut oldukça özel bir durum-bir yerleşik type sadece sen kullanmasına izin isinstance(hem strve unicodealt sınıfını basestring). Dizeler dizilerdir (üzerlerinde döngü yapabilir, dizine ekleyebilir, dilimleyebilir, ...), ancak genellikle bunları "skaler" tipler olarak ele almak istersiniz - her türlü tedavi için biraz rahatsız edici (ancak makul sıklıkta bir kullanım durumu). dizeleri (ve belki de diğer skaler türleri, yani döngü yapamayacağınızı) tek bir şekilde, tüm kapları (listeler, kümeler, diktler, ...) başka bir şekilde ve basestringayrıca isinstancebunu yapmanıza yardımcı olur - bunun genel yapısı deyim şuna benzer:

if isinstance(x, basestring)
  return treatasscalar(x)
try:
  return treatasiter(iter(x))
except TypeError:
  return treatasscalar(x)

Bunun basestringbir Soyut Temel Sınıf ("ABC") olduğunu söyleyebilirsiniz - alt sınıflara somut bir işlevsellik sunmaz, bunun yerine esas olarak kullanım için bir "işaretleyici" olarak bulunur isinstance. Konsept, Python'da giderek büyüyen bir kavramdır, çünkü genellemesini tanıtan PEP 3119 kabul edildi ve Python 2.6 ve 3.0'dan başlayarak uygulandı.

PEP, ABC'lerin genellikle ördek yazmanın yerini alabileceklerini açıkça belirtirken, bunu yapmak için genellikle büyük bir baskı yoktur ( buraya bakın ). Bununla birlikte, son Python sürümlerinde uygulandığı haliyle ABC'ler ekstra güzellikler sunmaktadır: isinstance(ve issubclass) artık sadece "[türetilmiş bir sınıfın örneği" ifadesinden daha fazlasını ifade edebilir (özellikle, herhangi bir sınıf bir ABC ile "kaydedilebilir", böylece bir alt sınıf olarak ve örneklerini ABC örnekleri olarak gösterir); ve ABC'ler ayrıca Şablon Altyapısı tasarım deseni uygulamaları aracılığıyla gerçek alt sınıflara çok doğal bir şekilde ekstra rahatlık sunabilirler ( genel olarak ve özellikle ABC'lerden bağımsız olarak Python'da TM DP hakkında daha fazla bilgi için buraya ve buraya [[bölüm II]] bakınız ) .

Python 2.6'da sunulan ABC desteğinin altında yatan mekaniği için buraya bakın ; 3.1 sürümü için, çok benzer, buraya bakın . Her iki sürümde de, standart kütüphane modülü koleksiyonları (bu 3.1 sürümü — çok benzer 2.6 sürümü için buraya bakın ) birkaç yararlı ABC sunar.

Bu cevabın amacı için, ABC'ler hakkında tutulması gereken anahtar şey ( TMD işlevselliği için tartışmalı olarak daha doğal bir yerleşimin ötesinde, UserDict.DictMixin gibi mixin sınıflarının klasik Python alternatifine kıyasla ) çok daha fazlasını yapmaları isinstance(ve issubclass) çekici ve yaygın (Python 2.6'da ve ileriye doğru) eskiden olduğundan (2.5 ve öncesi) ve bu nedenle, aksine, yeni tip Python versiyonlarında kontrol eşitliğini daha önce olduğundan daha kötü bir uygulama haline getirin.


9
`` Bu, isinstance'ın iyi olduğu değil, unutmayın, tiplerin eşitliğini kontrol etmekten daha az kötü. Normal, Pythonic, tercih edilen çözüm neredeyse her zaman "ördek tipleme" dir. Bu oldukça sınırlı bir görüştür: örneğin türlerin dilbilgisini yansıttığı bir yorumlayıcıda isinstance () kullanmak için çok iyi durumlar vardır . "Pitonik" olmak her şey demek değildir!
Gene Callahan

2
basestring Python 3'te mevcut değil.
erobertc

@GeneCallahan, çok iyi vakalar olduğu için söylenenlerin iyi bir genel kural olmadığı anlamına gelmez. Önceden tip kontrol etmenin kesinlikle yeri olduğunu kabul ediyorum, ancak ördekler quack'e izin vermek çoğu vakayı daha esnek ve verimli bir şekilde kapsamalıdır .
Eric Ed Lohmar

@erobertc, Python 3.0'daki Yenilikler'e göre , "Yerleşik basestring soyut türü kaldırıldı. Bunun yerine str kullanın."
nörit

344

İşte yapamayacağınız bir isinstanceşey elde ettiğiniz bir örnek type:

class Vehicle:
    pass

class Truck(Vehicle):
    pass

bu durumda, bir kamyon nesnesi bir Araçtır, ancak şunu elde edersiniz:

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.

Başka bir deyişle, isinstancealt sınıflar için de geçerlidir.

Ayrıca bkz: Python'da bir nesnenin türü nasıl karşılaştırılır?


143
çünkü isInstance davranışını istemediğiniz bir durum var, ben "daha iyi" olmadığını iddia ediyorum. Sadece farklı bir şey yaparlar.
philgo20

27
-1, çünkü "isinstance tipten daha iyidir" yanıltıcı bir yorumdur. ilk bakışta " typekullanımdan kaldırıldı, isinstanceonun yerine kullanın" gibi anlaşılır . örneğin, tam olarak type()kontrol etmek istedim , ama kısa bir süre için yanlış yönlendirildim (ve biraz hata ayıklamak zorunda kaldım).
ceremcem

8
Farklı çalışma biçimlerine iyi bir örnek, ama sadece özel olarak ihtiyaç duyduğum type()ve olmadığım bir durumla karşılaştım isinstance(). Biri daha iyi değil; onlar farklı şeyler içindir.
EL_DON

103

Arasındaki farklar isinstance()ve type()Python?

İle tip kontrolü

isinstance(obj, Base)

alt sınıfların ve birden fazla olası tabanın kullanılmasına izin verir:

isinstance(obj, (Base1, Base2))

oysa tip kontrolü

type(obj) is Base

yalnızca başvurulan türü destekler.


Bir sidenote olarak, ismuhtemelen daha uygun

type(obj) == Base

çünkü sınıflar tek tektir.

Tip kontrolünden kaçının - Polimorfizm kullanın (ördek yazma)

Python'da genellikle argümanlarınız için herhangi bir türe izin vermek, beklendiği gibi davranmak ve nesne beklendiği gibi davranmazsa uygun bir hata oluşturur. Bu, ördek tipleme olarak da bilinen polimorfizm olarak bilinir.

def function_of_duck(duck):
    duck.quack()
    duck.swim()

Yukarıdaki kod işe yarıyorsa, argümanımızın bir ördek olduğunu varsayabiliriz. Böylece başka şeylerde geçebiliriz gerçek alt ördek türleri:

function_of_duck(mallard)

ya da ördek gibi çalışır:

function_of_duck(object_that_quacks_and_swims_like_a_duck)

ve kodumuz hala çalışıyor.

Ancak, açıkça yazım denetiminin yapılmasının istendiği bazı durumlar vardır. Belki de farklı nesne türleriyle ilgili mantıklı şeyleriniz vardır. Örneğin, Pandalar Dataframe nesnesi diktelerden veya kayıtlardan oluşturulabilir. Böyle bir durumda, kodunuzun düzgün bir şekilde işleyebilmesi için ne tür bir argüman aldığını bilmesi gerekir.

Yani, soruyu cevaplamak için:

Arasındaki farklar isinstance()ve type()Python?

Farkı göstermeme izin ver:

type

İşleviniz belirli bir argüman alırsa (yapıcılar için ortak bir kullanım örneği) belirli bir davranış sağlamanız gerektiğini varsayalım. Böyle bir türü kontrol ederseniz:

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')

Eğer bir alt sınıf olan bir diksiyon geçmeye çalışırsak dict(yapabileceğimiz gibi, kodumuzun Liskov İkame ilkesini izlemesini bekliyorsak , bu alt tipler türler için ikame edilebilir) kod kopuyor !:

from collections import OrderedDict

foo(OrderedDict([('foo', 'bar'), ('fizz', 'buzz')]))

hata veriyor!

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
ValueError: argument must be a dict

isinstance

Ancak kullanırsak isinstance, Liskov İkame'yi destekleyebiliriz !:

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')]))

İadeler OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

Soyut Temel Sınıflar

Aslında daha iyisini yapabiliriz. collectionsçeşitli türler için minimum protokolleri uygulayan Soyut Temel Sınıflar sağlar. Bizim durumumuzda, sadece Mappingprotokolü beklersek, aşağıdakileri yapabiliriz ve kodumuz daha da esnek hale gelir:

from collections import Mapping

def foo(a_dict):
    if not isinstance(a_dict, Mapping):
        raise ValueError('argument must be a dict')
    return a_dict

Yoruma verilen yanıt:

Türün birden fazla sınıfa karşı kontrol etmek için kullanılabileceği belirtilmelidir. type(obj) in (A, B, C)

Evet, türlerin eşitliğini test edebilirsiniz, ancak yukarıdakiler yerine, özellikle yalnızca bu türlere izin vermedikçe, kontrol akışı için çoklu tabanları kullanın:

isinstance(obj, (A, B, C))

Fark yine, isinstanceLiskov ikamesi olarak bilinen bir özellik olan programı bozmadan ebeveyn için ikame edilebilen alt sınıfları desteklemesidir.

Daha da iyisi, bağımlılıklarınızı ters çevirin ve belirli türleri kontrol etmeyin.

Sonuç

Bu nedenle, alt sınıfların değiştirilmesini desteklemek istediğimizden, çoğu durumda, bir örneğin kesin sınıfını gerçekten bilmeniz gerekmediği sürece type, tür denetiminden kaçınmak ve tür denetimini tercih etmek isinstanceistiyoruz.


Denetlediğiniz isinstance(instance, y)ve kullandığınız yerde_module.py dosyanız varsa from v.w.x import yve bu denetimi içeri aktarırsanız, ancak y_module.py dosyasına nasıl içe aktarıldığını yerine instancekullandığınızda from x import y, aynı sınıf olmasına rağmen isinstance denetimi başarısız olur.
toonarmycaptain

64

İkincisi tercih edilir, çünkü alt sınıfları düzgün bir şekilde idare eder. Aslında, örneğiniz daha da kolay yazılabilir çünkü isinstance()ikinci parametresi bir demet olabilir:

if isinstance(b, (str, unicode)):
    do_something_else()

veya basestringsoyut sınıfı kullanarak :

if isinstance(b, basestring):
    do_something_else()


9

Pratik kullanım farkı, bunların nasıl ele alındığıdır booleans:

Trueve Falsesadece anahtar ortalama o vardır 1ve 0içinde piton. Böylece,

isinstance(True, int)

ve

isinstance(False, int)

her ikisi de geri döner True. Her iki boole da bir tamsayı örneğidir. type()ancak, daha zekidir:

type(True) == int

döner False.


0

Gerçek farklılıklar için onu bulabiliriz code, ancak varsayılan davranışının uygulamasını bulamıyorum isinstance().

Ancak __instancecheck __ 'e göre benzer bir abc .__ instancecheck__ alabilirsiniz .

Yukarıdan abc.__instancecheck__, aşağıdaki testi kullandıktan sonra:

# 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

Bu sonucu alıyorum, çünkü type:

# according to `abc.__instancecheck__`, they are maybe different! I have not found negative one 
type(INSTANCE) ~= INSTANCE.__class__
type(CLASS) ~= CLASS.__class__

Şunun için 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: kullanımı karıştırmamak daha iyidir , project_dir kaynağından relative and absolutely importkullanın absolutely import(tarafından eklendi sys.path)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.