"ऑब्जेक्ट" वर्ग के उदाहरण पर विशेषताएँ सेट नहीं कर सकते


87

इसलिए, मैं इस प्रश्न का उत्तर देते समय पायथन के साथ खेल रहा था , और मुझे पता चला कि यह मान्य नहीं है:

o = object()
o.attr = 'hello'

एक के कारण AttributeError: 'object' object has no attribute 'attr'। हालाँकि, किसी भी वर्ग को ऑब्जेक्ट से विरासत में मिला है, यह मान्य है:

class Sub(object):
    pass

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

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


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

2
@ S.Lott: इस प्रश्न की पहली पंक्ति देखें। पूरी तरह से जिज्ञासा।
स्मैशरी

3
आपका शीर्षक भ्रामक है, आप objectवर्ग उदाहरणों पर विशेषता निर्धारित करने का प्रयास कर रहे हैं , objectवर्ग पर नहीं ।
ढिल

जवाबों:


129

मनमाने ढंग से विशेषता असाइनमेंट का समर्थन करने के लिए, एक वस्तु की जरूरत है __dict__: एक वस्तु से जुड़ा एक तानाशाह, जहां मनमाना विशेषताओं को संग्रहीत किया जा सकता है। अन्यथा, नई विशेषताओं को रखने के लिए कहीं नहीं है ।

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

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

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

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

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

>>> 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कथन (अधिक सटीक रूप से, डिफ़ॉल्ट मेटाक्लास type) उस वर्ग के प्रत्येक उदाहरण को (और इसलिए मनमाने गुण रखने की क्षमता ) से लैस नहीं करता है __dict__, बस एक परिमित , "स्लॉट्स" का कठोर सेट (मूल रूप से वे स्थान जो प्रत्येक दिए गए नामों के साथ किसी वस्तु का एक संदर्भ रख सकते हैं)।

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


5
यह बताता है कि तंत्र कैसे लागू किया जाता है लेकिन यह नहीं बताता है कि इसे इस तरह से क्यों लागू किया गया है। मैं कम से कम दो या तीन तरीकों के बारे में सोच सकता हूं ताकि मक्खी पर तानाशाही को लागू किया जा सके , जिसमें ओवरहेड नीचे नहीं होगा बल्कि कुछ सरलता होगी।
Георги Кременлиев

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


यह एक महान व्याख्या है, लेकिन फिर भी इसका जवाब नहीं है कि (या कैसे) Subमें __dict__विशेषता और वस्तु नहीं है, जो कि Subइनहेरिट से है object, उस विशेषता (और अन्य जैसे __module__) को विरासत में कैसे जोड़ा गया है? हो सकता है कि यह एक नया प्रश्न हो
रोड्रिगो ई। प्रिंसिपल

2
एक ऑब्जेक्ट __dict__केवल पहली बार बनाया गया है जब इसकी आवश्यकता होती है, इसलिए मेमोरी लागत की स्थिति काफी सरल नहीं है क्योंकि asizeofआउटपुट इसे दिखता है। ( asizeofसे बचने के लिए कैसे पता नहीं है __dict__भौतिकीकरण।) आप dict जब तक की जरूरत materialized हो रही नहीं देख सकते हैं इस उदाहरण है, और आप कोड रास्तों के लिए जिम्मेदार में से एक को देख सकते हैं __dict__भौतिकीकरण यहाँ
user2357112

17

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


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


4

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

डायट्स अपेक्षाकृत बड़े होते हैं।

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

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

यदि आप स्रोत कोड को देखते हैं तो आप देखेंगे कि यह देखने के लिए कई जांचें हैं कि वस्तु में कोई तानाशाही है या नहीं।


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'

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


0

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


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

बिंगो। ठीक यही मुद्दा है।
रयान

1
पायथन 3 में, प्रकार और वर्गों के बीच अंतर वास्तव में मौजूद नहीं है। इसलिए "टाइप" और "क्लास" अब काफी समानार्थी हैं। लेकिन आप अभी भी उन वर्गों के लिए विशेषताओं को नहीं जोड़ सकते हैं जिनके पास __dict__एलेक्स मार्टेली द्वारा दिए गए कारणों से नहीं है ।
PM 2Ring


-2

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

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