2009-06-29 19 views
35

type(obj) और obj.__class__ के बीच क्या अंतर है? क्या type(obj) is not obj.__class__ की संभावना है?प्रकार (ओबीजे) और ओबीजे के बीच अंतर .__ वर्ग__

मैं एक ऐसा फ़ंक्शन लिखना चाहता हूं जो आपूर्ति की गई वस्तुओं पर सामान्य रूप से काम करता है, उसी प्रकार के डिफ़ॉल्ट मान का उपयोग दूसरे पैरामीटर के रूप में करता है। कौन सा बदलाव, # 1 या # 2 नीचे सही काम करने जा रहा है?

def f(a, b=None): 
    if b is None: 
    b = type(a)(1) # #1 
    b = a.__class__(1) # #2 

उत्तर

12

type(obj) और type.__class__ पुरानी शैली कक्षाओं के लिए एक ही व्यवहार नहीं करते:

>>> class a(object): 
...  pass 
... 
>>> class b(a): 
...  pass 
... 
>>> class c: 
...  pass 
... 
>>> ai=a() 
>>> bi=b() 
>>> ci=c() 
>>> type(ai) is ai.__class__ 
True 
>>> type(bi) is bi.__class__ 
True 
>>> type(ci) is ci.__class__ 
False 
+7

सबसे बड़ी विडंबना है Yairchu की टिप्पणी अब एक ही समस्या है क्योंकि उन्होंने स्वरूपण को स्विच किया है ..: पी –

+10

दिखाने के लिए कोई दिक्कत नहीं होगी * कैसे * वे अलग-अलग व्यवहार करते हैं, और शायद * क्यों *। सिर्फ यह कहकर * जब * वे अलग-अलग व्यवहार करते हैं तो आलसी जवाब लगता है, भले ही सही हो। – MestreLion

+1

उल्लेख करने लायक है यह केवल पायथन 2 में मुद्दा है। पायथन 3 में सभी तीन अभिव्यक्तियां सच होंगी। – Bob

30

पुरानी शैली कक्षाओं समस्या है, कराहती

>>> class old: pass 
... 
>>> x=old() 
>>> type(x) 
<type 'instance'> 
>>> x.__class__ 
<class __main__.old at 0x6a150> 
>>> 

नहीं एक समस्या पायथन 3 में के बाद से सभी वर्गों अब नई शैली हैं ;-)।

अजगर 2 में, एक वर्ग केवल नई शैली अगर यह (object और सहित विभिन्न निर्मित प्रकार जैसे dict, list, set, ...) या परोक्ष या स्पष्ट रूप एक और नई शैली वर्ग से विरासत है __metaclass__ से type सेट करता है।

+3

यह पाइथन 3 बार है, जिसे * हम * उपयोग करना चाहिए? –

+2

यदि आपका कोड एलेक्स द्वारा वर्णित सर्वोत्तम अभ्यास का पालन कर रहा है, तो 'टाइप() 'बेहतर होगा। पायथन 3 में, यह हमेशा सर्वोत्तम अभ्यास का पालन करता है, इसलिए पाइथन 3 में टाइप() का उपयोग करें। –

+0

@AaronHall क्या मैं यह मानने के लिए सही होगा कि 'टाइप()' का उपयोग करके '__class__' पर भी प्राथमिकता दी जाती है यदि मैं पाइथन लिख रहा हूं 2 कोड जहां मुझे पता है कि इसे केवल नए शैली के वर्गों के उदाहरणों के साथ बुलाया जाएगा? – kasperd

30

यह एक पुरानी सवाल है, लेकिन जवाब में से कोई भी है कि उल्लेख करने के लिए लगता है। सामान्य मामले में, यह संभव है एक नई शैली वर्ग type(instance) और instance.__class__ के लिए अलग-अलग मान के लिए:

class ClassA(object): 
    def display(self): 
     print("ClassA") 

class ClassB(object): 
    __class__ = ClassA 

    def display(self): 
     print("ClassB") 

instance = ClassB() 

print(type(instance)) 
print(instance.__class__) 
instance.display() 

आउटपुट:

<class '__main__.ClassB'> 
<class '__main__.ClassA'> 
ClassB 

कारण है कि ClassB__class__ अधिभावी है वर्णनकर्ता, हालांकि वस्तु में आंतरिक प्रकार का क्षेत्र नहीं बदला गया है। type(instance) सीधे उस प्रकार के फ़ील्ड से पढ़ता है, इसलिए यह सही मान देता है, जबकि instance.__class__ पाइथन द्वारा प्रदान किए गए मूल वर्णनकर्ता को प्रतिस्थापित करने वाले नए वर्णनकर्ता को संदर्भित करता है, जो आंतरिक प्रकार फ़ील्ड को पढ़ता है। उस आंतरिक प्रकार के क्षेत्र को पढ़ने के बजाय, यह एक हार्डकोडेड मान देता है।

+10

_Caveat lector_: इसे उदाहरण के रूप में लिया जाना चाहिए कि आपको '__class__' को ओवरराइड करने से क्यों बचना चाहिए! आप उस रेखा को कोड कर सकते हैं जो टूटने के लिए '__class__' का उपयोग करता है। –

+0

'__getattribute__' से भी प्रभावित है, जो' ओबीजे .__ वर्ग__' के अनुरोध को रोकता है लेकिन 'प्रकार (ओबीजे)' के लिए नहीं। – kdb

संबंधित मुद्दे