python - सूचियों की तुलना में ट्यूपल्स मेमोरी में कम जगह क्यों लेते हैं?
python-2.7 list (3)
MSeifert जवाब इसे मोटे तौर पर कवर करता है; इसे सरल रखने के लिए आप सोच सकते हैं:
tuple
अचल है।
एक बार सेट होने के बाद, आप इसे बदल नहीं सकते।
तो आप पहले से जानते हैं कि आपको उस ऑब्जेक्ट के लिए कितनी मेमोरी आवंटित करने की आवश्यकता है।
list
परस्पर है।
आप इसमें या इससे आइटम जोड़ या हटा सकते हैं।
इसे इसका आकार (आंतरिक निहितार्थ के लिए) जानना होगा।
यह आवश्यकतानुसार आकार देता है।
कोई मुफ्त भोजन नहीं है - ये क्षमताएं लागत के साथ आती हैं। इसलिए सूचियों के लिए स्मृति में ओवरहेड।
एक
tuple
पायथन में कम मेमोरी स्पेस लेता है:
>>> a = (1,2,3)
>>> a.__sizeof__()
48
जबकि
list
s में अधिक मेमोरी स्थान है:
>>> b = [1,2,3]
>>> b.__sizeof__()
64
आंतरिक रूप से पायथन मेमोरी प्रबंधन पर क्या होता है?
टपल का आकार उपसर्ग है, जिसका अर्थ है ट्यूल इनिशियलाइज़ेशन में इंटरप्रेटर निहित डेटा के लिए पर्याप्त जगह आवंटित करता है, और इसका अंत है, यह अपरिवर्तनीय (संशोधित नहीं किया जा सकता है), जबकि एक सूची एक उत्परिवर्ती वस्तु है इसलिए गतिशील का अर्थ है स्मृति का आबंटन, इसलिए हर बार जब आप सूची को जोड़ते हैं या सूची को संशोधित करने से बचते हैं (बदले हुए डेटा को रखने के लिए पर्याप्त स्थान आवंटित करते हैं और उस पर डेटा को कॉपी करते हैं), यह भविष्य के परिशिष्ट, संशोधनों, ... के लिए अतिरिक्त स्थान आवंटित करता है। इसे जोड़े।
मैं CPython कोडबेस में एक गहरा गोता लगाऊंगा ताकि हम देख सकें कि वास्तव में आकारों की गणना कैसे की जाती है। आपके विशिष्ट उदाहरण में , कोई अति-आवंटन नहीं किया गया है, इसलिए मैं उस पर स्पर्श नहीं करूंगा ।
मैं यहाँ 64-बिट मानों का उपयोग करने जा रहा हूँ, जैसे आप हैं।
list
s के लिए आकार की गणना निम्न फ़ंक्शन,
list_sizeof
:
static PyObject *
list_sizeof(PyListObject *self)
{
Py_ssize_t res;
res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * sizeof(void*);
return PyInt_FromSsize_t(res);
}
यहां
Py_TYPE(self)
एक मैक्रो है जो
self
के
ob_type
(
PyList_Type
लौटते
PyList_Type
) को
_PyObject_SIZE
है जबकि
_PyObject_SIZE
एक अन्य मैक्रो है जो उस प्रकार से
tp_basicsize
पकड़ लेता है।
tp_basicsize
की गणना
sizeof(PyListObject)
रूप में की जाती है, जहां
PyListObject
उदाहरण संरचना है।
PyListObject
संरचना
में तीन क्षेत्र हैं:
PyObject_VAR_HEAD # 24 bytes
PyObject **ob_item; # 8 bytes
Py_ssize_t allocated; # 8 bytes
इन टिप्पणियों (जो मैंने छंटनी की है) की व्याख्या करते हुए कि वे क्या हैं, उन्हें पढ़ने के लिए ऊपर दिए गए लिंक का पालन करें।
PyObject_VAR_HEAD
तीन 8 बाइट फ़ील्ड (
ob_refcount
,
ob_type
और
ob_size
) में फैलता है, इसलिए
24
बाइट योगदान देता है।
तो अब के लिए
res
है:
sizeof(PyListObject) + self->allocated * sizeof(void*)
या:
40 + self->allocated * sizeof(void*)
यदि सूची उदाहरण में ऐसे तत्व हैं जो आवंटित किए गए हैं।
दूसरा भाग उनके योगदान की गणना करता है।
self->allocated
, जैसा कि नाम से ही स्पष्ट है, आवंटित तत्वों की संख्या रखता है।
किसी भी तत्व के बिना, सूचियों के आकार की गणना की जाती है:
>>> [].__sizeof__()
40
उदाहरण की संरचना का आकार।
tuple
ऑब्जेक्ट्स
tuple_sizeof
फ़ंक्शन को परिभाषित नहीं करता है।
इसके बजाय, वे अपने आकार की गणना करने के लिए
object_sizeof
का उपयोग करते हैं:
static PyObject *
object_sizeof(PyObject *self, PyObject *args)
{
Py_ssize_t res, isize;
res = 0;
isize = self->ob_type->tp_itemsize;
if (isize > 0)
res = Py_SIZE(self) * isize;
res += self->ob_type->tp_basicsize;
return PyInt_FromSsize_t(res);
}
यह
list
एस के लिए के रूप में,
tp_basicsize
पकड़ लेता है और, यदि ऑब्जेक्ट में एक शून्य-शून्य
tp_itemsize
(जिसका अर्थ है कि चर-लंबाई के उदाहरण हैं), यह
Py_SIZE
में आइटमों की संख्या को गुणा करता है (जो इसे
Py_SIZE
माध्यम से
Py_SIZE
)
tp_itemsize
साथ।
tp_basicsize
फिर से
sizeof(PyTupleObject)
का उपयोग करता है जहां
PyTupleObject
संरचना में शामिल हैं
:
PyObject_VAR_HEAD # 24 bytes
PyObject *ob_item[1]; # 8 bytes
तो, बिना किसी तत्व के (अर्थात,
Py_SIZE
रिटर्न
0
) रिक्त ट्यूपल्स का आकार
sizeof(PyTupleObject)
बराबर है:
>>> ().__sizeof__()
24
है ना?
ठीक है, यहाँ एक विषमता है, जिसके लिए मुझे कोई स्पष्टीकरण नहीं मिला,
tp_basicsize
का
tuple
s वास्तव में इस प्रकार है:
sizeof(PyTupleObject) - sizeof(PyObject *)
अतिरिक्त
8
बाइट्स को
tp_basicsize
से क्यों हटाया जाता है, यह मुझे पता नहीं चल पाया है।
(संभावित स्पष्टीकरण के लिए MSeifert की टिप्पणी देखें)
लेकिन, यह मूल रूप से
आपके विशिष्ट उदाहरण में
अंतर
है
।
list
एस भी आवंटित तत्वों की एक संख्या के आसपास रहती है जो यह निर्धारित करने में मदद करती है कि फिर से कब आवंटित किया जाए।
अब, जब अतिरिक्त तत्व जोड़े जाते हैं, तो सूचियाँ वास्तव में O (1) प्राप्त करने के लिए इस ओवर-आवंटन का प्रदर्शन करती हैं। इससे MSeifert के उत्तर में बड़े आकार के परिणाम मिलते हैं।