2009-10-07 11 views
64

तो, जबकि this question का जवाब दे रहा अजगर के साथ चारों ओर खेल रहा था, और मुझे पता चला कि यह मान्य नहीं है। हालांकि, किसी भी वर्ग के साथ वस्तु से विरासत में मिला है, यह मान्य है:वस्तु वर्ग के गुण सेट कर सकता हूँ नहीं

class Sub(object): 
    pass 

s = Sub() 
s.attr = 'hello' 

मुद्रण s.attr प्रदर्शित करता है 'हैलो' के रूप में उम्मीद। यह एक केस क्यों है? पाइथन भाषा विनिर्देश में क्या निर्दिष्ट करता है कि आप वेनिला ऑब्जेक्ट्स को विशेषताओं को असाइन नहीं कर सकते हैं?

+0

शुद्ध अनुमान: 'ऑब्जेक्ट' प्रकार अपरिवर्तनीय है और नए गुण जोड़े नहीं जा सकते हैं? ऐसा लगता है कि यह सबसे ज्यादा समझ में आता है। –

+2

@ एसएलॉट: इस प्रश्न की पहली पंक्ति देखें। शुद्ध जिज्ञासा। – Smashery

+2

आपका शीर्षक भ्रामक है, आप 'ऑब्जेक्ट' वर्ग पर नहीं, 'ऑब्जेक्ट' क्लास उदाहरणों पर विशेषताओं को सेट करने का प्रयास कर रहे हैं। – dhill

उत्तर

107

मनमाने ढंग से विशेषता असाइनमेंट का समर्थन करने के लिए, किसी ऑब्जेक्ट को __dict__ की आवश्यकता होती है: ऑब्जेक्ट से जुड़े एक तीर, जहां मनमाने ढंग से गुण संग्रहीत किए जा सकते हैं। अन्यथा, कहीं भी नई विशेषताएं डालें। (dict के बाद से ही यह किया था, भयानक परिपत्र निर्भरता समस्या से पहले, और सबसे सब कुछ की तरह, object से विरासत ;-), इस हर काठी होगा -

object का एक उदाहरण करता एक __dict__ आसपास नहीं कैरी पाइथन में ऑब्जेक्ट के साथ ऑब्जेक्ट, जिसका मतलब का एक ओवरहेड होगा, जो बाइट्स प्रति ऑब्जेक्ट है, जिसमें वर्तमान में कोई हथियार नहीं है या आवश्यक है (अनिवार्य रूप से, उन सभी ऑब्जेक्ट्स जिनमें मनमाने ढंग से असाइन करने योग्य गुण नहीं हैं, उन्हें एक निर्देश या आवश्यकता नहीं है)।

उदाहरण के लिए, उत्कृष्ट pympler परियोजना का उपयोग कर, हम कुछ माप कर सकते हैं (यदि आप इसे here से SVN के माध्यम से प्राप्त कर सकते हैं) ...:

>>> from pympler import asizeof 
>>> asizeof.asizeof({}) 
144 
>>> asizeof.asizeof(23) 
16 

आप 144 को लेने के लिए हर int नहीं चाहता है, है ना सिर्फ 16 साल की बजाय बाइट्स -)

अब, जब आप चीजों को बदलना एक वर्ग (जो भी से इनहेरिट) बनाने के लिए, ...:

>>> class dint(int): pass 
... 
>>> asizeof.asizeof(dint(23)) 
184 

... __dict__ अब जोड़ा गया है (प्लस, थोड़ा अधिक ओवरहेड) - इसलिए dint इंस्टेंस में मनमाना गुण हो सकते हैं, लेकिन आप उस लचीलेपन के लिए काफी जगह चुकाते हैं।

तो क्या होगा यदि आप int एस एक अतिरिक्त विशेषता foobar ... के साथ क्या चाहते हैं? यह एक दुर्लभ जरूरत है, लेकिन अजगर उद्देश्य के लिए एक विशेष तंत्र की पेशकश करता है ...

>>> class fint(int): 
... __slots__ = 'foobar', 
... def __init__(self, x): self.foobar=x+100 
... 
>>> asizeof.asizeof(fint(23)) 
80 

... काफी के रूप में एक int के रूप में छोटे नहीं, मन आप! (या यहां तक ​​कि दो int एस, self और एक self.foobar - दूसरा वाला पुन: असाइन किया जा सकता है), लेकिन dint से निश्चित रूप से काफी बेहतर है।

वर्ग __slots__ विशेष विशेषता (तार का एक अनुक्रम), तो class बयान (अधिक सटीक, डिफ़ॉल्ट metaclass, type) नहीं एक __dict__ साथ उस वर्ग के प्रत्येक उदाहरण से लैस होते हैं (और इसलिए मनमानी विशेषताओं की क्षमता), दिए गए नामों के साथ "स्लॉट" (मूल रूप से वे स्थान जो प्रत्येक वस्तु के संदर्भ में हो सकते हैं) का एक सीमित, कठोर सेट।

खो लचीलेपन के लिए विदेशी मुद्रा में, आप उदाहरण के प्रति बाइट्स का एक बहुत लाभ (शायद सार्थक केवल यदि आप उदाहरणों के आसपास gallivanting के zillions है, लेकिन, वहाँ कि के लिए उपयोग के मामलों रहे हैं)।

+5

यह बताता है कि तंत्र कैसे कार्यान्वित किया जाता है लेकिन यह स्पष्ट नहीं करता कि इसे इस तरह क्यों लागू किया जाता है।मैं फ्लाई पर __dict__ जोड़ने को लागू करने के कम से कम दो या तीन तरीकों के बारे में सोच सकता हूं, जिसमें ओवरहेड डाउनसाइड नहीं होगा लेकिन कुछ सादगी जोड़ देगा। –

+0

ध्यान दें कि गैर-खाली '__slots__' चर-लंबाई प्रकारों जैसे' str', 'tuple', और पायथन 3 में भी 'int' के साथ काम नहीं करता है। – arekolek

+0

अच्छा और धन्यवाद! [यदि किसी ऑब्जेक्ट में '__dict__' नहीं है, तो क्या उसके वर्ग में' __slot__' विशेषता होनी चाहिए?] (Https://stackoverflow.com/q/46575174/156458) – Tim

-1

यह (आईएमओ) पायथन के साथ मौलिक सीमाओं में से एक है - आप कक्षाओं को फिर से खोल नहीं सकते हैं। मेरा मानना ​​है कि वास्तविक समस्या, हालांकि, इस तथ्य के कारण होती है कि सी में लागू कक्षाओं को रनटाइम पर संशोधित नहीं किया जा सकता है ... सबक्लास, आधार वर्ग नहीं कर सकते हैं।

1

ऐसा इसलिए है क्योंकि ऑब्जेक्ट एक "प्रकार" है, न कि कक्षा। आम तौर पर, सभी कक्षाएं जो सी एक्सटेंशन में परिभाषित की जाती हैं (जैसे सभी अंतर्निहित डेटाटाइप, और नुकीले सरणी जैसी चीजें) मनमाने ढंग से विशेषताओं को जोड़ने की अनुमति नहीं देती हैं।

+0

लेकिन ऑब्जेक्ट() एक ऑब्जेक्ट है, जैसे उप() एक ऑब्जेक्ट है। मेरी समझ यह है कि दोनों एस और ओ वस्तुएं हैं। तो एस और ओ के बीच मौलिक अंतर क्या है? क्या यह एक तत्काल प्रकार है और दूसरा एक तत्काल वर्ग है? – Smashery

+0

बिंगो। यह बिल्कुल मुद्दा है। – Ryan

1

तो, मेरे अपने प्रश्न की जांच कर रही है, मैं इस अजगर भाषा के बारे में पता चला: आप पूर्णांक जैसी चीजों से विरासत सकते हैं, और आप एक ही व्यवहार देखें:

>>> class MyInt(int): 
     pass 

>>> x = MyInt() 
>>> print x 
0 
>>> x.hello = 4 
>>> print x.hello 
4 
>>> x = x + 1 
>>> print x 
1 
>>> print x.hello 
Traceback (most recent call last): 
    File "<interactive input>", line 1, in <module> 
AttributeError: 'int' object has no attribute 'hello' 

मैं त्रुटि मान पर अंत वजह से है ऐड फ़ंक्शन एक int देता है, इसलिए मुझे __add__ जैसे कार्यों को ओवरराइड करना होगा और इस तरह मेरे कस्टम विशेषताओं को बनाए रखने के लिए। लेकिन यह सब अब मुझे समझ में आता है (मुझे लगता है), जब मैं "वस्तु" जैसे "वस्तु" के बारे में सोचता हूं।

5

यह केवल अनुकूलन के कारण है।

डिब्बे अपेक्षाकृत बड़े हैं।

>>> import sys 
>>> sys.getsizeof((lambda:1).__dict__) 
140 

सी में परिभाषित अधिकांश (शायद सभी) वर्गों में अनुकूलन के लिए कोई नियम नहीं है।

यदि आप source code पर देखते हैं तो आप देखेंगे कि ऑब्जेक्ट में कोई नियम है या नहीं, यह देखने के लिए कई चेक हैं।

16

जैसा कि अन्य उत्तरदाताओं ने कहा है, object में __dict__ नहीं है। objectका बेस क्लास प्रकार है, जिसमें int या str शामिल हैं। इस प्रकार जो कुछ भी object द्वारा प्रदान किया जाता है, वह भी उनके लिए बोझ होगा। वैकल्पिक__dict__ जितना आसान कुछ भी प्रत्येक मान के लिए एक अतिरिक्त सूचक की आवश्यकता होगी; यह सिस्टम में प्रत्येक ऑब्जेक्ट के लिए बहुत सीमित उपयोगिता के लिए अतिरिक्त 4-8 बाइट मेमोरी बर्बाद कर देगा।


इसके बजाय एक डमी वर्ग का एक उदाहरण कर रही है, अजगर 3.3+ में, आप (और चाहिए) इस के लिए types.SimpleNamespace उपयोग कर सकते हैं।

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