पायथन में पुरानी शैली और नई शैली वर्गों के बीच क्या अंतर है? मुझे एक या दूसरे का उपयोग कब करना चाहिए?
पायथन में पुरानी शैली और नई शैली वर्गों के बीच क्या अंतर है? मुझे एक या दूसरे का उपयोग कब करना चाहिए?
जवाबों:
से नई शैली और क्लासिक कक्षाएं :
पायथन 2.1 तक, पुरानी शैली की कक्षाएं केवल उपयोगकर्ता के लिए उपलब्ध थीं।
(पुरानी शैली) वर्ग की अवधारणा प्रकार की अवधारणा से असंबंधित है: यदि
x
पुरानी शैली वर्ग का एक उदाहरण है, तोx.__class__
कक्षा को डिजाइन करता हैx
, लेकिनtype(x)
हमेशा होता है<type 'instance'>
।यह इस तथ्य को दर्शाता है कि सभी पुराने-शैली के उदाहरण, स्वतंत्र रूप से अपनी कक्षा में, एक ही प्रकार में निर्मित होते हैं, उदाहरण के लिए।
कक्षा और प्रकार की अवधारणाओं को एकजुट करने के लिए पायथन 2.2 में नई शैली की कक्षाएं शुरू की गईं । एक नई शैली की क्लास बस एक उपयोगकर्ता-परिभाषित प्रकार है, और नहीं, कम नहीं।
यदि x एक नए-शैली वर्ग का एक उदाहरण है, तो
type(x)
आमतौर पर ऐसा ही होता हैx.__class__
(हालांकि इसकी गारंटी नहीं है - एक नए-शैली वर्ग के उदाहरण के लिए लौटाए गए मूल्य को ओवरराइड करने की अनुमति हैx.__class__
)।नई शैली की कक्षाएं शुरू करने के लिए प्रमुख प्रेरणा एक पूर्ण मेटा-मॉडल के साथ एकीकृत ऑब्जेक्ट मॉडल प्रदान करना है ।
इसमें कई तात्कालिक लाभ भी हैं, जैसे कि अधिकांश निर्मित प्रकारों को उपवर्ग करने की क्षमता, या "विवरणकर्ता" की शुरूआत, जो गणना किए गए गुणों को सक्षम करते हैं।
संगतता कारणों से, कक्षाएं अभी भी डिफ़ॉल्ट रूप से पुरानी शैली की हैं ।
नई शैली की कक्षाएं किसी अन्य नई शैली वर्ग (अर्थात एक प्रकार) को मूल वर्ग, या "शीर्ष-स्तरीय प्रकार" ऑब्जेक्ट के रूप में निर्दिष्ट करके बनाई जाती हैं यदि कोई अन्य माता-पिता की आवश्यकता नहीं है।
नई शैली की कक्षाओं का व्यवहार किस प्रकार के रिटर्न के अलावा कई महत्वपूर्ण विवरणों में पुरानी शैली की कक्षाओं से भिन्न होता है।
इन परिवर्तनों में से कुछ नए ऑब्जेक्ट मॉडल के लिए मौलिक हैं, जिस तरह से विशेष तरीकों को लागू किया जाता है। अन्य "फ़िक्सेस" हैं जो संगतता चिंताओं के लिए पहले लागू नहीं किए जा सकते हैं, जैसे कई उत्तराधिकार के मामले में विधि रिज़ॉल्यूशन ऑर्डर।
पायथन 3 में केवल नई शैली की कक्षाएं हैं ।
इससे कोई फर्क नहीं पड़ता कि आप उपवर्ग से हैं
object
या नहीं, कक्षाएं पायथन 3 में नई शैली की हैं।
super()
पुरानी शैली की कक्षाओं में कुछ विशेषताएं काम नहीं करती हैं। उल्लेख नहीं करने के लिए, जैसा कि लेख कहता है, इसमें एमआरओ और विशेष तरीकों की तरह मूलभूत सुधार हैं, जो इसका उपयोग करने के लिए एक अच्छे कारण से अधिक है।
घोषणा-वार:
नई-शैली की कक्षाएं ऑब्जेक्ट से , या किसी अन्य नए-शैली वर्ग से प्राप्त होती हैं।
class NewStyleClass(object):
pass
class AnotherNewStyleClass(NewStyleClass):
pass
पुरानी शैली की कक्षाएं नहीं।
class OldStyleClass():
pass
पायथन 3 नोट:
पायथन 3 पुरानी शैली की कक्षाओं का समर्थन नहीं करता है, इसलिए या तो एक नई शैली की कक्षा में परिणाम ऊपर दिए गए हैं।
object
।
class AnotherOldStyleClass: pass
class A: pass
और class A(): pass
कड़ाई से समकक्ष हैं। पहले का अर्थ है "A किसी भी मूल वर्ग का वंशानुक्रम नहीं करता है" और दूसरा अर्थ है "कोई मूल वर्ग का वंशानुक्रम " । यही कारण है कि करने के लिए काफी समान है not is
औरis not
पुरानी और नई शैली की कक्षाओं के बीच महत्वपूर्ण व्यवहार बदलता है
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
पुरानी शैली की कक्षाएं अभी भी विशेषता देखने के लिए थोड़ी तेज़ हैं। यह आमतौर पर महत्वपूर्ण नहीं है, लेकिन यह प्रदर्शन-संवेदनशील पायथन 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 एनएस प्रति लूप
%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
गुइडो ने द इनसाइड स्टोरी ऑन न्यू-स्टाइल क्लासेस लिखा है , जो पायथन में नए-शैली और पुराने-शैली वर्ग के बारे में एक बहुत अच्छा लेख है।
पायथन 3 में केवल नई शैली की कक्षा है। यहां तक कि अगर आप एक 'पुरानी शैली की कक्षा' लिखते हैं, तो यह अंतर्निहित रूप से लिया जाता है object
।
नई शैली की कक्षाओं में पुरानी शैली की कक्षाओं में कुछ उन्नत सुविधाओं की कमी है, जैसे कि super
, नई सी 3 मेरो , कुछ जादुई तरीके आदि।
यहाँ एक बहुत ही व्यावहारिक, सही / गलत अंतर है। निम्नलिखित कोड के दो संस्करणों के बीच एकमात्र अंतर यह है कि दूसरे संस्करण में व्यक्ति को ऑब्जेक्ट से विरासत में मिला है । इसके अलावा, दो संस्करण समान हैं, लेकिन विभिन्न परिणामों के साथ:
पुरानी शैली की कक्षाएं
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>
>>>
नई शैली की कक्षाएं
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>
>>>
_names_cache
एक शब्दकोश है जो कैश (भविष्य की पुनर्प्राप्ति के लिए भंडार) है, हर नाम जिसे आप पास करते हैं Person.__new__
। सेटडफ़ॉल्ट विधि (किसी भी शब्दकोश में परिभाषित) में दो तर्क होते हैं: एक कुंजी और एक मूल्य। यदि कुंजी तानाशाह में है, तो वह अपना मूल्य वापस कर देगा। यदि यह हुकुम में नहीं है, तो यह पहले दूसरे तर्क के रूप में पारित मूल्य पर सेट करेगा और फिर इसे वापस करेगा।
__new__()
में हमेशा कहा जाता है, और यह हमेशा एक नई वस्तु का निर्माण करता है, और फिर इसे फेंकता है। इस मामले में एक if
बेहतर है .setdefault()
।
__new__
वास्तव में पुरानी शैली की कक्षाओं के लिए एक चीज नहीं है, यह उदाहरण के निर्माण में उपयोग नहीं किया जाता है (यह सिर्फ एक यादृच्छिक नाम है जो विशेष दिखता है, जैसे परिभाषित करना __spam__
)। इसलिए पुरानी शैली के वर्ग का निर्माण केवल आह्वान करता है __init__
, जबकि नई शैली के निर्माण का निर्माण __new__
(नाम से सिंगलटन उदाहरण के लिए समन्वय) का निर्माण करना, और __init__
इसे आरंभ करना है।
नई शैली की कक्षाएं इनहेरिट की जाती हैं object
और इसे पाइथन 2.2 के बाद (यानी के class Classname(object):
बजाय class Classname:
) लिखा जाना चाहिए । मुख्य परिवर्तन प्रकारों और वर्गों को एकजुट करना है, और इसका अच्छा दुष्प्रभाव यह है कि यह आपको अंतर्निहित प्रकारों से विरासत में प्राप्त करने की अनुमति देता है।
अधिक जानकारी के लिए descrintro पढ़ें ।
नई शैली की कक्षाएं उपयोग कर सकती हैं super(Foo, self)
जहां Foo
एक वर्ग है और self
उदाहरण है।
super(type[, object-or-type])
किसी प्रॉक्सी ऑब्जेक्ट को लौटाएं जो विधि को अभिभावक या सिबलिंग क्लास के प्रकार को कॉल करता है। यह उन विरासत वाले तरीकों तक पहुंचने के लिए उपयोगी है जिन्हें एक वर्ग में ओवरराइड किया गया है। खोज क्रम वही है जो गेटटार () द्वारा उपयोग किया जाता है सिवाय इसके कि प्रकार खुद ही छोड़ दिया जाता है।
और पायथन 3.x में आप बस super()
किसी भी पैरामीटर के बिना एक वर्ग के अंदर उपयोग कर सकते हैं ।
type(x)
। यदि मैं एक प्रकार में निर्मित उप-वर्ग नहीं कर रहा हूं, तो मुझे कोई फायदा नहीं होता है कि मैं नई शैली की कक्षाएं देख सकता हूं। एक नुकसान है, जो अतिरिक्त टाइपिंग है(object)
।