python प्रकार() और isinstance() के बीच अंतर क्या हैं?




oop inheritance (5)

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

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

isinstance(obj, Base)

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

isinstance(obj, (Base1, Base2))

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

type(obj) is Base

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

एक sidenote के रूप में, यह संभवतः अधिक उपयुक्त है

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 dict:
        # we're only going to test for dicts for now
        raise ValueError('only dicts are supported for now')

यदि हम एक ऐसे नियम में पारित करने का प्रयास करते हैं जो कि एक उप-वर्ग है (जैसा कि हम सक्षम होना चाहिए, अगर हम अपने कोड को लिस्कोव प्रतिस्थापन के सिद्धांत का पालन करने की उम्मीद कर रहे हैं, तो उप-प्रकारों को प्रकारों के लिए प्रतिस्थापित किया जा सकता है) हमारे कोड ब्रेक !:

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 उपयोग 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')]) देता है 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 -चेकिंग से बचना चाहते हैं और isinstance साथ टाइप-चेकिंग पसंद करते हैं - जब तक कि आपको वास्तव में किसी इंस्टेंस की सटीक कक्षा को जानने की आवश्यकता न हो।

https://code.i-harness.com

इन दो कोड टुकड़ों के बीच अंतर क्या हैं? 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()

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

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

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

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

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

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

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

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

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


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

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

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

if isinstance(b, basestring):
    do_something_else()

पाइथन दस्तावेज के अनुसार यहां एक बयान है:

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

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

तो isinstance() type() पर प्राथमिकता दी जानी चाहिए।


यहां बताया गया है कि 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 सत्य है।

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





types