पायथन में पुरानी शैली और नई शैली वर्गों के बीच क्या अंतर है?


जवाबों:


559

से नई शैली और क्लासिक कक्षाएं :

पायथन 2.1 तक, पुरानी शैली की कक्षाएं केवल उपयोगकर्ता के लिए उपलब्ध थीं।

(पुरानी शैली) वर्ग की अवधारणा प्रकार की अवधारणा से असंबंधित है: यदि xपुरानी शैली वर्ग का एक उदाहरण है, तो x.__class__ कक्षा को डिजाइन करता है x, लेकिन type(x)हमेशा होता है <type 'instance'>

यह इस तथ्य को दर्शाता है कि सभी पुराने-शैली के उदाहरण, स्वतंत्र रूप से अपनी कक्षा में, एक ही प्रकार में निर्मित होते हैं, उदाहरण के लिए।

कक्षा और प्रकार की अवधारणाओं को एकजुट करने के लिए पायथन 2.2 में नई शैली की कक्षाएं शुरू की गईं । एक नई शैली की क्लास बस एक उपयोगकर्ता-परिभाषित प्रकार है, और नहीं, कम नहीं।

यदि x एक नए-शैली वर्ग का एक उदाहरण है, तो type(x)आमतौर पर ऐसा ही होता है x.__class__(हालांकि इसकी गारंटी नहीं है - एक नए-शैली वर्ग के उदाहरण के लिए लौटाए गए मूल्य को ओवरराइड करने की अनुमति है x.__class__)।

नई शैली की कक्षाएं शुरू करने के लिए प्रमुख प्रेरणा एक पूर्ण मेटा-मॉडल के साथ एकीकृत ऑब्जेक्ट मॉडल प्रदान करना है

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

संगतता कारणों से, कक्षाएं अभी भी डिफ़ॉल्ट रूप से पुरानी शैली की हैं

नई शैली की कक्षाएं किसी अन्य नई शैली वर्ग (अर्थात एक प्रकार) को मूल वर्ग, या "शीर्ष-स्तरीय प्रकार" ऑब्जेक्ट के रूप में निर्दिष्ट करके बनाई जाती हैं यदि कोई अन्य माता-पिता की आवश्यकता नहीं है।

नई शैली की कक्षाओं का व्यवहार किस प्रकार के रिटर्न के अलावा कई महत्वपूर्ण विवरणों में पुरानी शैली की कक्षाओं से भिन्न होता है।

इन परिवर्तनों में से कुछ नए ऑब्जेक्ट मॉडल के लिए मौलिक हैं, जिस तरह से विशेष तरीकों को लागू किया जाता है। अन्य "फ़िक्सेस" हैं जो संगतता चिंताओं के लिए पहले लागू नहीं किए जा सकते हैं, जैसे कई उत्तराधिकार के मामले में विधि रिज़ॉल्यूशन ऑर्डर।

पायथन 3 में केवल नई शैली की कक्षाएं हैं

इससे कोई फर्क नहीं पड़ता कि आप उपवर्ग से हैं objectया नहीं, कक्षाएं पायथन 3 में नई शैली की हैं।


41
इनमें से कोई भी अंतर नई शैली की कक्षाओं का उपयोग करने के लिए आकर्षक कारणों की तरह नहीं है, फिर भी हर कोई कहता है कि आपको हमेशा नई शैली का उपयोग करना चाहिए। यदि मैं बतख टाइपिंग का उपयोग कर रहा हूं, तो मुझे कभी भी उपयोग करने की आवश्यकता नहीं है type(x)। यदि मैं एक प्रकार में निर्मित उप-वर्ग नहीं कर रहा हूं, तो मुझे कोई फायदा नहीं होता है कि मैं नई शैली की कक्षाएं देख सकता हूं। एक नुकसान है, जो अतिरिक्त टाइपिंग है (object)
पुनरावर्ती

78
super()पुरानी शैली की कक्षाओं में कुछ विशेषताएं काम नहीं करती हैं। उल्लेख नहीं करने के लिए, जैसा कि लेख कहता है, इसमें एमआरओ और विशेष तरीकों की तरह मूलभूत सुधार हैं, जो इसका उपयोग करने के लिए एक अच्छे कारण से अधिक है।
जॉन डो John

21
@ उपयोगकर्ता: पुरानी शैली की कक्षाएं 2.7 में वैसा ही व्यवहार करती हैं जैसा उन्होंने 2.1 में किया था- और, क्योंकि कुछ लोग क्वर्क्स भी याद करते हैं, और दस्तावेज़ीकरण अब उनमें से अधिकांश की चर्चा नहीं करता है, वे और भी बदतर हैं। ऊपर दिए गए प्रलेखन उद्धरण सीधे यह कहते हैं: "फ़िक्स" हैं जो पुरानी शैली की कक्षाओं पर लागू नहीं किए जा सकते हैं। जब तक आप उन क्वर्क में भागना चाहते हैं जो पायथन 2.1 के बाद से किसी और ने नहीं निपटाए हैं, और यह कि प्रलेखन अब भी नहीं बताता है, पुरानी शैली की कक्षाओं का उपयोग न करें।
6

10
यदि आप 2.7 में पुरानी शैली की कक्षाओं का उपयोग करते हैं, तो आप उस पर रुकने वाले क्वर्की
KT।

5
किसी को भी आश्चर्य होता है, पायथन 3 में ऑब्जेक्ट से स्पष्ट रूप से विरासत में लेने का एक अच्छा कारण यह है कि यह पायथन के कई संस्करणों का समर्थन आसान बनाता है।
jpmc26

308

घोषणा-वार:

नई-शैली की कक्षाएं ऑब्जेक्ट से , या किसी अन्य नए-शैली वर्ग से प्राप्त होती हैं।

class NewStyleClass(object):
    pass

class AnotherNewStyleClass(NewStyleClass):
    pass

पुरानी शैली की कक्षाएं नहीं।

class OldStyleClass():
    pass

पायथन 3 नोट:

पायथन 3 पुरानी शैली की कक्षाओं का समर्थन नहीं करता है, इसलिए या तो एक नई शैली की कक्षा में परिणाम ऊपर दिए गए हैं।


24
यदि एक नई शैली की कक्षा दूसरे नए-शैली वर्ग से विरासत में मिलती है, तो विस्तार से, यह विरासत में मिलती है object
एरोनस्टरलिंग

2
क्या यह पुरानी शैली के अजगर वर्ग का गलत उदाहरण है? class AnotherOldStyleClass: pass
अंकुर अग्रवाल

11
@abc मुझे विश्वास है कि class A: passऔर class A(): passकड़ाई से समकक्ष हैं। पहले का अर्थ है "A किसी भी मूल वर्ग का वंशानुक्रम नहीं करता है" और दूसरा अर्थ है "कोई मूल वर्ग का वंशानुक्रम " । यही कारण है कि करने के लिए काफी समान है not isऔरis not
eyquem

5
3.X के लिए, एक साइड नोट के रूप में, "ऑब्जेक्ट" की विरासत स्वचालित रूप से ग्रहण की जाती है (जिसका अर्थ है कि हमें 3.X में "ऑब्जेक्ट" को इनहेरिट करने का कोई तरीका नहीं है)। पिछड़े अनुकूलता कारण के लिए, हालांकि "वस्तु (") को वहां रखना बुरा नहीं है।
यो हिसियो

1
यदि हम विरासत में मिली कक्षाओं के बारे में तकनीकी जानकारी प्राप्त करने जा रहे हैं, तो इस उत्तर पर ध्यान देना चाहिए कि आप पुरानी शैली की कक्षा से विरासत में एक और पुरानी शैली की क्लास बनाएँ। (जैसा कि लिखा गया है, यह उत्तर उपयोगकर्ता को यह सवाल करने पर छोड़ देता है कि क्या आप पुराने शैली के वर्ग से विरासत में ले सकते हैं। आप कर सकते हैं।)
jpmc26

224

पुरानी और नई शैली की कक्षाओं के बीच महत्वपूर्ण व्यवहार बदलता है

  • सुपर गयी
  • MRO बदल गया (नीचे समझाया गया है)
  • वर्णनकर्ता जोड़े गए
  • नई शैली वर्ग की वस्तुओं को तब तक नहीं उठाया जा सकता है जब तक कि Exceptionउससे प्राप्त न हो (उदाहरण के नीचे)
  • __slots__ जोड़ा

एमआरओ (मेथड रेजोल्यूशन ऑर्डर) बदल गया

अन्य उत्तरों में इसका उल्लेख किया गया था, लेकिन यहां क्लासिक एमआरओ और सी 3 एमआरओ (नई शैली की कक्षाओं में प्रयुक्त) के बीच अंतर का एक ठोस उदाहरण दिया गया है।

प्रश्न वह क्रम है जिसमें गुण (जिसमें विधियाँ और सदस्य चर शामिल हैं) को एकाधिक वंशानुक्रम में खोजा जाता है।

क्लासिक कक्षाएं बाएं से दाएं की गहराई-पहली खोज करती हैं। पहले मैच पर रोक। उनके पास __mro__विशेषता नहीं है ।

class C: i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 0
assert C21().i == 2

try:
    C12.__mro__
except AttributeError:
    pass
else:
    assert False

नई शैली की कक्षाएं MRO एकल अंग्रेजी वाक्य में संश्लेषित करने के लिए अधिक जटिल है। इसे यहां विस्तार से समझाया गया है । इसका एक गुण यह है कि एक आधार वर्ग की खोज केवल एक बार उसके सभी व्युत्पन्न वर्गों के लिए की जाती है। उनके पास __mro__विशेषता है जो खोज क्रम को दर्शाता है।

class C(object): i = 0
class C1(C): pass
class C2(C): i = 2
class C12(C1, C2): pass
class C21(C2, C1): pass

assert C12().i == 2
assert C21().i == 2

assert C12.__mro__ == (C12, C1, C2, C, object)
assert C21.__mro__ == (C21, C2, C1, C, object)

जब तक नई शैली की वस्तुओं को नहीं उठाया जा सकता है Exception

पायथन 2.5 के आसपास कई कक्षाएं खड़ी की जा सकती थीं, और अजगर 2.6 के आसपास इसे हटा दिया गया था। पायथन 2.7.3 पर:

# OK, old:
class Old: pass
try:
    raise Old()
except Old:
    pass
else:
    assert False

# TypeError, new not derived from `Exception`.
class New(object): pass
try:
    raise New()
except TypeError:
    pass
else:
    assert False

# OK, derived from `Exception`.
class New(Exception): pass
try:
    raise New()
except New:
    pass
else:
    assert False

# `'str'` is a new style object, so you can't raise it:
try:
    raise 'str'
except TypeError:
    pass
else:
    assert False

8
अच्छा स्पष्ट सारांश, धन्यवाद। जब आप कहते हैं "अंग्रेजी में समझाना मुश्किल है" तो मुझे लगता है कि आप एक पोस्ट-डेप्थ-पहली खोज का वर्णन कर रहे हैं, जो पुराने-शैली वर्ग के विपरीत है जो एक प्री-डेप्थ-प्रथम खोज का उपयोग करता है। (प्रीऑर्डर का मतलब है कि हम अपने पहले बच्चे की खोज करें और पोस्टऑर्डर का मतलब है कि हम अपने आखिरी बच्चे के बाद खुद की खोज करें)।
स्टीव कार्टर

40

पुरानी शैली की कक्षाएं अभी भी विशेषता देखने के लिए थोड़ी तेज़ हैं। यह आमतौर पर महत्वपूर्ण नहीं है, लेकिन यह प्रदर्शन-संवेदनशील पायथन 2.x कोड में उपयोगी हो सकता है:

[3] में: ए श्रेणी:
   ...: __init __ (स्व):
   ...: self.a = 'hi there'
   ...:

[४] में: कक्षा बी (वस्तु):
   ...: __init __ (स्व):
   ...: self.a = 'hi there'
   ...:

[6] में: अबोज = ए ()
[7] में: बोबज = बी ()

[8] में:% टाइमिट aobj.a
10000000 लूप, 3: 78.7 ns प्रति लूप का सबसे अच्छा

[१०] में:% समयित bobj.a
10000000 लूप्स, सर्वश्रेष्ठ 3: 86.9 एनएस प्रति लूप

5
दिलचस्प है कि आपने व्यवहार में देखा है, मैंने अभी पढ़ा है कि यह इसलिए है क्योंकि नई शैली की कक्षाएं, एक बार जब उन्हें उदाहरण में विशेषता दिखाई देती है, तो यह पता लगाने के लिए कि क्या यह एक विवरण है, अर्थात्, यह काम करने के लिए एक अतिरिक्त लुकअप करना होगा वह विधि प्राप्त करें जिसे वापस करने के लिए मूल्य प्राप्त करने के लिए आह्वान किया जाना चाहिए। पुरानी शैली की कक्षाएं सरल बिना किसी अतिरिक्त संगणना के साथ मिली हुई वस्तु को लौटाती हैं (लेकिन तब वर्णनकर्ताओं का समर्थन नहीं करती हैं)। आप इस बेहतरीन पोस्ट में Guido python-history.blogspot.co.uk/2010/06/… द्वारा अधिक पढ़ सकते हैं , विशेष रूप से स्लॉट्स
xuloChavez

1
सीपीथॉन 2.7.2 के साथ सच नहीं लगता:%timeit aobj.a 10000000 loops, best of 3: 66.1 ns per loop %timeit bobj.a 10000000 loops, best of 3: 53.9 ns per loop
बेनेडिकट वाल्डवोगेल

1
मेरे लिए x86-64 लिनक्स पर सीपीथॉन 2.7.2 में अभी भी तेजी से।
१२:

41
प्रदर्शन संवेदनशील अनुप्रयोगों के लिए शुद्ध पायथन कोड पर भरोसा करना शायद एक बुरा विचार है। कोई नहीं कहता है: "मुझे तेज कोड की आवश्यकता है इसलिए मैं पुरानी शैली के पायथन वर्गों का उपयोग करूंगा।" Numpy को शुद्ध अजगर के रूप में नहीं गिना जाता है।
फिलिप क्लाउड

आईपीथॉन 2.7.6 में भी, यह सच नहीं है। '' '' ४ per 'एनएस बनाम ४५६ एनएस प्रति लूप' '' '
किमीोनोर

37

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

पायथन 3 में केवल नई शैली की कक्षा है। यहां तक ​​कि अगर आप एक 'पुरानी शैली की कक्षा' लिखते हैं, तो यह अंतर्निहित रूप से लिया जाता है object

नई शैली की कक्षाओं में पुरानी शैली की कक्षाओं में कुछ उन्नत सुविधाओं की कमी है, जैसे कि super, नई सी 3 मेरो , कुछ जादुई तरीके आदि।


24

यहाँ एक बहुत ही व्यावहारिक, सही / गलत अंतर है। निम्नलिखित कोड के दो संस्करणों के बीच एकमात्र अंतर यह है कि दूसरे संस्करण में व्यक्ति को ऑब्जेक्ट से विरासत में मिला है । इसके अलावा, दो संस्करण समान हैं, लेकिन विभिन्न परिणामों के साथ:

  1. पुरानी शैली की कक्षाएं

    class Person():
        _names_cache = {}
        def __init__(self,name):
            self.name = name
        def __new__(cls,name):
            return cls._names_cache.setdefault(name,object.__new__(cls,name))
    
    ahmed1 = Person("Ahmed")
    ahmed2 = Person("Ahmed")
    print ahmed1 is ahmed2
    print ahmed1
    print ahmed2
    
    
    >>> False
    <__main__.Person instance at 0xb74acf8c>
    <__main__.Person instance at 0xb74ac6cc>
    >>>
    
  2. नई शैली की कक्षाएं

    class Person(object):
        _names_cache = {}
        def __init__(self,name):
            self.name = name
        def __new__(cls,name):
            return cls._names_cache.setdefault(name,object.__new__(cls,name))
    
    ahmed1 = Person("Ahmed")
    ahmed2 = Person("Ahmed")
    print ahmed2 is ahmed1
    print ahmed1
    print ahmed2
    
    >>> True
    <__main__.Person object at 0xb74ac66c>
    <__main__.Person object at 0xb74ac66c>
    >>>

2
'_names_cache' क्या करता है? क्या आप एक संदर्भ साझा कर सकते हैं?
मुतईक

4
_names_cacheएक शब्दकोश है जो कैश (भविष्य की पुनर्प्राप्ति के लिए भंडार) है, हर नाम जिसे आप पास करते हैं Person.__new__। सेटडफ़ॉल्ट विधि (किसी भी शब्दकोश में परिभाषित) में दो तर्क होते हैं: एक कुंजी और एक मूल्य। यदि कुंजी तानाशाह में है, तो वह अपना मूल्य वापस कर देगा। यदि यह हुकुम में नहीं है, तो यह पहले दूसरे तर्क के रूप में पारित मूल्य पर सेट करेगा और फिर इसे वापस करेगा।
२४:१४ पर ychaouche

4
उपयोग गलत है। विचार एक नई वस्तु का निर्माण नहीं करना है यदि यह पहले से मौजूद है, लेकिन आपके मामले __new__()में हमेशा कहा जाता है, और यह हमेशा एक नई वस्तु का निर्माण करता है, और फिर इसे फेंकता है। इस मामले में एक ifबेहतर है .setdefault()
अमित उपाध्याय

लेकिन, मुझे नहीं मिला कि पुरानी शैली की कक्षा में आउटपुट में अंतर क्यों है, दोनों उदाहरण अलग-अलग थे, इस तरह से गलत लौटा, लेकिन नई शैली वर्ग में, दोनों उदाहरण समान हैं। कैसे ? नई शैली वर्ग में क्या बदलाव है, जिसने दो उदाहरणों को एक ही बना दिया है, जो पुरानी शैली वर्ग में नहीं था?
पाबित्रा पति

1
@PabitraPati: यह एक सस्ते प्रदर्शन की तरह है। __new__वास्तव में पुरानी शैली की कक्षाओं के लिए एक चीज नहीं है, यह उदाहरण के निर्माण में उपयोग नहीं किया जाता है (यह सिर्फ एक यादृच्छिक नाम है जो विशेष दिखता है, जैसे परिभाषित करना __spam__)। इसलिए पुरानी शैली के वर्ग का निर्माण केवल आह्वान करता है __init__, जबकि नई शैली के निर्माण का निर्माण __new__(नाम से सिंगलटन उदाहरण के लिए समन्वय) का निर्माण करना, और __init__इसे आरंभ करना है।
शैडो रेंजर

10

नई शैली की कक्षाएं इनहेरिट की जाती हैं objectऔर इसे पाइथन 2.2 के बाद (यानी के class Classname(object):बजाय class Classname:) लिखा जाना चाहिए । मुख्य परिवर्तन प्रकारों और वर्गों को एकजुट करना है, और इसका अच्छा दुष्प्रभाव यह है कि यह आपको अंतर्निहित प्रकारों से विरासत में प्राप्त करने की अनुमति देता है।

अधिक जानकारी के लिए descrintro पढ़ें ।


8

नई शैली की कक्षाएं उपयोग कर सकती हैं super(Foo, self)जहां Fooएक वर्ग है और selfउदाहरण है।

super(type[, object-or-type])

किसी प्रॉक्सी ऑब्जेक्ट को लौटाएं जो विधि को अभिभावक या सिबलिंग क्लास के प्रकार को कॉल करता है। यह उन विरासत वाले तरीकों तक पहुंचने के लिए उपयोगी है जिन्हें एक वर्ग में ओवरराइड किया गया है। खोज क्रम वही है जो गेटटार () द्वारा उपयोग किया जाता है सिवाय इसके कि प्रकार खुद ही छोड़ दिया जाता है।

और पायथन 3.x में आप बस super()किसी भी पैरामीटर के बिना एक वर्ग के अंदर उपयोग कर सकते हैं ।

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