प्रकार () और आइंस्टीन () के बीच अंतर क्या हैं?


1247

इन दो कोड अंशों के बीच अंतर क्या हैं?

का उपयोग कर type():

import types

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

का उपयोग कर isinstance():

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

नोट: यदि यह नहीं है strऔर unicode(जहां आप सिर्फ जांच basestringकर सकते हैं), तो आप कई प्रकारों के खिलाफ जाँच के लिए टपल का उपयोग कर सकते हैं। यह जाँचने के लिए कि somethingक्या उपयोग है intया नहीं । strisinstance(something, (int, str))
xuiqzy

जवाबों:


1270

अन्य की सामग्री को संक्षेप में बताने के लिए (पहले से ही अच्छा है) उत्तर, isinstanceवंशानुक्रम के लिए पूरा करता है (एक व्युत्पन्न वर्ग का एक उदाहरण एक आधार वर्ग का एक उदाहरण है, भी), समानता की जांच typeनहीं करता है (यह प्रकार की पहचान की मांग करता है और उदाहरणों को अस्वीकार करता है) उपप्रकारों, AKA उपवर्गों)।

आम तौर पर, पायथन में, आप चाहते हैं कि आपका कोड वंशानुक्रम का समर्थन करे, बेशक (चूंकि वंशानुक्रम इतना आसान है, यह कोड को आपके द्वारा उपयोग करने से रोकना बुरा होगा!), इसलिए s isinstanceकी पहचान की जाँच करने की तुलना में कम बुरा है typeक्योंकि यह मूल रूप से समर्थन करता है! विरासत।

यह न कि isinstanceहै अच्छा , तो आप यह मन सिर्फ है कम बुरा प्रकार की समानता की जाँच की तुलना में। सामान्य, पाइथोनिक, पसंदीदा समाधान लगभग हमेशा "बतख टाइपिंग" होता है: तर्क का उपयोग करने का प्रयास करें जैसे कि यह एक निश्चित वांछित प्रकार का था, इसे सभी विवरणों को पकड़ने वाले try/ exceptकथन में करें यदि तर्क वास्तव में नहीं था तो उत्पन्न हो सकता है। टाइप करें (या कोई अन्य प्रकार अच्छी तरह से बत्तख की नकल करते हैं; ;-), और exceptक्लॉज़ में, कुछ और आज़माएं (तर्क का उपयोग करके) जैसे कि "यह किसी और प्रकार का था"।

basestring है , हालांकि, काफी एक विशेष मामला-एक builtin प्रकार है कि मौजूद है केवल आप का उपयोग करने देने isinstance(दोनों strऔर unicodeउपवर्ग basestring)। स्ट्रिंग्स सीक्वेंस हैं (आप उन पर लूप कर सकते हैं, उन्हें इंडेक्स कर सकते हैं, उन्हें स्लाइस कर सकते हैं, ...), लेकिन आप आम तौर पर उन्हें "स्केलर" प्रकार के रूप में व्यवहार करना चाहते हैं — यह सभी प्रकार के उपचार के लिए कुछ हद तक असंगत (लेकिन एक लगातार उपयोग के मामले) है। तार (और शायद अन्य स्केलर प्रकार, यानी, जिन्हें आप लूप नहीं कर सकते हैं) एक तरह से, सभी कंटेनरों (सूचियों, सेटों, डीकट्स, ...) को दूसरे तरीके से, और basestringप्लस isinstanceआपको ऐसा करने में मदद करता है - इस की समग्र संरचना मुहावरा कुछ इस तरह है:

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

आप कह सकते हैं कि basestringएक सार बेस क्लास ("एबीसी") है - यह उपवर्गों को कोई ठोस कार्यक्षमता प्रदान नहीं करता है, बल्कि "मार्कर" के रूप में मौजूद है, मुख्य रूप से उपयोग के लिए isinstancePEP 3119 के बाद से यह अवधारणा स्पष्ट रूप से पायथन में एक बढ़ती हुई है , जो कि इसके सामान्यीकरण का परिचय देती है, इसे स्वीकार किया गया और इसे पायथन 2.6 और 3.0 के साथ शुरू किया गया।

पीईपी यह स्पष्ट करता है कि, जबकि एबीसी अक्सर बतख टाइपिंग के लिए स्थानापन्न कर सकते हैं, आमतौर पर ऐसा करने के लिए कोई बड़ा दबाव नहीं है ( यहां देखें )। हाल के पायथन संस्करणों में लागू किए गए एबीसी हालांकि अतिरिक्त उपहार देते हैं: isinstance(और issubclass) अब केवल "एक व्युत्पन्न वर्ग" का उदाहरण दे सकते हैं (विशेष रूप से, किसी भी वर्ग को एबीसी के साथ "पंजीकृत" किया जा सकता है ताकि यह होगा एक उपवर्ग के रूप में दिखाएं, और एबीसी के उदाहरणों के रूप में इसके उदाहरण); और एबीसी भी टेम्पलेट विधि डिजाइन पैटर्न अनुप्रयोगों के माध्यम से एक बहुत ही स्वाभाविक तरीके से वास्तविक उपवर्गों अतिरिक्त सुविधा प्रदान कर सकते हैं (देखें यहाँ और यहाँ [[भाग द्वितीय]] टीएम डी पी के बारे में अधिक के लिए, सामान्य रूप में और विशेष रूप से अजगर में, एबीसी से स्वतंत्र) ।

Python 2.6 में पेश किए गए ABC समर्थन के अंतर्निहित यांत्रिकी के लिए, यहां देखें ; उनके 3.1 संस्करण के लिए, बहुत समान, यहां देखें । दोनों संस्करणों में, मानक पुस्तकालय मॉड्यूल संग्रह (यह बहुत समान 2.6 संस्करण के लिए 3.1 संस्करण है, यहां देखें ) कई उपयोगी एबीसी प्रदान करता है।

इस उत्तर के प्रयोजन के लिए, मुख्य बात कखग बनाए रखने के लिए (जैसे mixin कक्षाओं की क्लासिक अजगर विकल्प की तुलना में टीएम डी पी कार्यक्षमता के लिए एक यकीनन अधिक प्राकृतिक स्थान, परे UserDict.DictMixin ) है कि वे करते हैं isinstance(और issubclass) भी बहुत कुछ आकर्षक और व्यापक (Python 2.6 में और आगे जाने वाले) की तुलना में वे (2.5 और उससे पहले) में हुआ करते थे, और इसलिए, इसके विपरीत, हाल के पायथन संस्करणों में जाँच समानता को और भी बदतर बना देते हैं, जो पहले से ही हुआ करते थे।


9
'ऐसा नहीं है कि आइंस्टीन अच्छा है, आपको बुरा लगता है-यह समानता की जाँच करने से कम बुरा है। सामान्य, पाइथोनिक, पसंदीदा समाधान लगभग हमेशा "बतख टाइपिंग" है यह एक बल्कि सीमित दृश्य है: आइंस्टीन () का उपयोग करने के लिए बहुत अच्छे मामले हैं, कहते हैं, एक दुभाषिया जहां प्रकार व्याकरण को दर्शाते हैं। "पायथोनिक" होना सब कुछ नहीं है!
जीन कैलहान

2
बेसथ्रिंग पाइथन 3 में उपलब्ध नहीं है।
एरोबर्टेक

@GeneCallahan, क्योंकि बहुत अच्छे मामले हैं, इसका मतलब यह नहीं है कि जो कहा गया वह एक अच्छा सामान्य नियम नहीं है। मैं सहमत हूं कि समय से पहले टाइप करने की जाँच में निश्चित रूप से अपनी जगह है, लेकिन बत्तखों को शांत करने के लिए ज्यादातर मामलों को अधिक लचीले और कुशलता से कवर करना चाहिए ।
एरिक एड लोहमर

@erobertc, Python 3.0 में व्हाट्स न्यू के अनुसार , "बिल्ट-इन बेसिस्ट्रिंग अमूर्त प्रकार को हटा दिया गया था। इसके बजाय स्ट्रैप का उपयोग करें।"
neurite

344

यहाँ एक उदाहरण है जहाँ isinstanceकुछ हासिल typeनहीं किया जा सकता है:

class Vehicle:
    pass

class Truck(Vehicle):
    pass

इस मामले में, एक ट्रक ऑब्जेक्ट एक वाहन है, लेकिन आपको यह मिलेगा:

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.

दूसरे शब्दों में, isinstanceउपवर्गों के लिए भी सही है।

यह भी देखें: पायथन में किसी वस्तु के प्रकार की तुलना कैसे करें?


143
क्योंकि ऐसा मामला है जहाँ आप नहीं चाहते हैं कि इस तरह का व्यवहार मैं तर्क दे कि कोई "बेहतर" नहीं है। वे बस कुछ अलग करते हैं।
फिल्गो २०

27
-1, क्योंकि "टाइप से बेहतर है" एक भ्रामक टिप्पणी है। यह समझा जाता है कि " पहली नज़र में type, पदावनत, उपयोग के isinstanceबजाय" है। उदाहरण के लिए, जो मैं चाहता था वह बिल्कुल type()जाँच कर रहा था, लेकिन मुझे थोड़े समय के लिए गुमराह किया गया था (और उस कारण से थोड़ी सी बहस करनी पड़ी)।
सेरेमनी

8
यह एक अच्छा उदाहरण है कि वे कैसे अलग तरीके से काम करते हैं, लेकिन मैं सिर्फ एक मामले में भाग गया, जहां मुझे विशेष रूप से जरूरत थी type()और नहीं isinstance()। एक बेहतर नहीं है; वे अलग-अलग चीजों के लिए हैं।
EL_DON

103

पायथन में isinstance()और के बीच अंतर type()?

टाइप-चेकिंग के साथ

isinstance(obj, Base)

उपवर्गों और कई संभावित ठिकानों के उदाहरणों के लिए अनुमति देता है:

isinstance(obj, (Base1, Base2))

टाइप-चेकिंग के साथ

type(obj) is Base

केवल संदर्भित प्रकार का समर्थन करता है।


एक विचार के रूप में, isसंभावना से अधिक उपयुक्त है

type(obj) == Base

क्योंकि कक्षाएं एकल हैं।

टाइप-चेकिंग से बचें - पॉलिमॉर्फिज्म (डक-टाइपिंग) का उपयोग करें

पायथन में, आमतौर पर आप अपने तर्क के लिए किसी भी प्रकार की अनुमति देना चाहते हैं, इसे अपेक्षा के अनुसार व्यवहार करें, और यदि ऑब्जेक्ट अपेक्षा के अनुरूप व्यवहार नहीं करता है, तो यह एक उपयुक्त त्रुटि को बढ़ाएगा। इसे बहुरूपता के रूप में जाना जाता है, जिसे डक-टाइपिंग भी कहा जाता है।

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

यदि उपरोक्त कोड काम करता है, तो हम मान सकते हैं कि हमारा तर्क एक बतख है। इस प्रकार हम अन्य चीजों में पास हो सकते हैं, बतख के वास्तविक उप-प्रकार हैं:

function_of_duck(mallard)

या वह एक बतख की तरह काम करता है:

function_of_duck(object_that_quacks_and_swims_like_a_duck)

और हमारा कोड अभी भी काम करता है।

हालांकि, कुछ ऐसे मामले हैं जहां स्पष्ट रूप से टाइप-चेक करना वांछनीय है। शायद आपके पास विभिन्न वस्तु प्रकारों के साथ समझदार चीजें हैं। उदाहरण के लिए, पंडों डेटाफ़ॉर्म ऑब्जेक्ट का निर्माण डाइक या रिकॉर्ड से किया जा सकता है । ऐसे मामले में, आपके कोड को यह जानना होगा कि उसे किस प्रकार का तर्क मिल रहा है ताकि वह उसे ठीक से संभाल सके।

तो, सवाल का जवाब देने के लिए:

पायथन में isinstance()और के बीच अंतर type()?

मुझे अंतर प्रदर्शित करने की अनुमति दें:

type

यदि आपके फ़ंक्शन को एक निश्चित प्रकार का तर्क (निर्माणकर्ताओं के लिए एक सामान्य उपयोग-मामला) मिलता है, तो आपको एक निश्चित व्यवहार सुनिश्चित करने की आवश्यकता है। यदि आप इस प्रकार की जाँच करते हैं:

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

यदि हम एक ऐसे श्रुतलेख में उत्तीर्ण होने का प्रयास करते हैं जो dict(जैसा कि हमें सक्षम होना चाहिए, यदि हम लिस्कोव प्रतिस्थापन के सिद्धांत का पालन करने के लिए हमारे कोड की अपेक्षा कर रहे हैं, तो उप-प्रकारों को प्रतिस्थापित किया जा सकता है) हमारा कोड टूट जाता है!

from collections import OrderedDict

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

कोई त्रुटि उठाता है!

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

isinstance

लेकिन अगर हम उपयोग करते हैं isinstance, तो हम लिस्कोव प्रतिस्थापन का समर्थन कर सकते हैं! "

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

रिटर्न OrderedDict([('foo', 'bar'), ('fizz', 'buzz')])

सार आधार वर्ग

वास्तव में, हम और भी बेहतर कर सकते हैं। collectionsविभिन्न प्रकार के लिए न्यूनतम प्रोटोकॉल लागू करने वाले सार बेस कक्षाएं प्रदान करता है। हमारे मामले में, यदि हम केवल Mappingप्रोटोकॉल की उम्मीद करते हैं, तो हम निम्नलिखित कर सकते हैं, और हमारा कोड और भी अधिक लचीला हो जाता है:

from collections import Mapping

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

टिप्पणी करने के लिए प्रतिक्रिया:

यह ध्यान दिया जाना चाहिए कि प्रकार का उपयोग करके कई वर्गों के खिलाफ जांच करने के लिए किया जा सकता है type(obj) in (A, B, C)

हां, आप प्रकारों की समानता के लिए परीक्षण कर सकते हैं, लेकिन उपरोक्त के बजाय, नियंत्रण प्रवाह के लिए कई आधारों का उपयोग करें, जब तक कि आप विशेष रूप से केवल उन प्रकारों की अनुमति न दें:

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

फिर से, अंतर यह है कि isinstanceउपवर्गों का समर्थन करता है जिन्हें माता-पिता के लिए अन्यथा कार्यक्रम को तोड़ने के बिना प्रतिस्थापित किया जा सकता है, एक संपत्ति जिसे लिस्कोव प्रतिस्थापन कहा जाता है।

हालांकि, इससे भी बेहतर, अपनी निर्भरता को उल्टा करें और विशिष्ट प्रकारों की जांच बिल्कुल न करें।

निष्कर्ष

इसलिए जब से हम उपवर्गों को प्रतिस्थापित करने का समर्थन करना चाहते हैं, ज्यादातर मामलों में, हम टाइप-चेकिंग से बचना चाहते हैं typeऔर इसके साथ टाइप-चेकिंग पसंद करते हैं isinstance- जब तक कि आपको वास्तव में किसी उदाहरण की सटीक कक्षा जानने की आवश्यकता न हो।


यदि आपके पास आपका_मॉड्यूलहोम है जहां आप जांच करते हैं isinstance(instance, y)और उपयोग करते हैं from v.w.x import y, और आप उस चेक को आयात करते हैं, लेकिन जब आप तुरंत instanceउपयोग करते हैं, तो from x import yइसके बजाय कि आपके y_module.py में कैसे आयात किया गया था, आइंस्टीन चेक विफल हो जाएगा, भले ही यह एक ही वर्ग हो।
toonarmycaptain'

64

उत्तरार्द्ध को प्राथमिकता दी जाती है, क्योंकि यह उपवर्गों को ठीक से संभाल लेगा। वास्तव में, आपके उदाहरण को और भी आसानी से लिखा जा सकता है क्योंकि isinstance()दूसरा पैरामीटर टपल हो सकता है:

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

या, basestringअमूर्त वर्ग का उपयोग करते हुए :

if isinstance(b, basestring):
    do_something_else()

15

अजगर प्रलेखन के अनुसार यहाँ एक बयान है:

8.15। प्रकार - अंतर्निहित प्रकार के लिए नाम

पाइथन 2.2 में शुरू, बिल्ट-इन फ़ैक्टरी कार्य जैसे कि int()और str()इसी प्रकार के नाम भी हैं।

इसलिए isinstance()अधिक पसंद किया जाना चाहिए type()


9

व्यावहारिक उपयोग अंतर यह है कि वे कैसे संभालते हैं booleans:

Trueऔर Falseकेवल कीवर्ड हैं जो अर्थ 1और 0अजगर में हैं। इस प्रकार,

isinstance(True, int)

तथा

isinstance(False, int)

दोनों लौट आए True। दोनों बूलियन पूर्णांक का एक उदाहरण हैं। type()हालाँकि, अधिक चतुर है:

type(True) == int

लौटता है False


0

वास्तविक अंतरों के लिए, हम इसे खोज सकते हैं code, लेकिन मैं डिफ़ॉल्ट व्यवहार को लागू नहीं कर सकता isinstance()

हालाँकि हमें __instancecheck__ के अनुसार समान एक abc .__ instcheck__ मिल सकता है

ऊपर से abc.__instancecheck__, नीचे परीक्षण का उपयोग करने के बाद:

# 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

मुझे यह निष्कर्ष मिलता है, के लिए type:

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

के लिए 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: बेहतर मिश्रण का उपयोग नहीं करने के लिए relative and absolutely import, absolutely importproject_dir से उपयोग (द्वारा जोड़ा गया sys.path)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.