__Slots__ का उपयोग?


762

__slots__पायथन में क्या उद्देश्य है - विशेष रूप से सम्मान के साथ कि मैं इसका उपयोग कब करना चाहूंगा, और कब नहीं?

जवाबों:


1018

पायथन में, इसका उद्देश्य क्या है __slots__और इससे बचने वाले मामलों में क्या करना चाहिए?

TLDR:

विशेष विशेषता __slots__आपको स्पष्ट रूप से यह बताने की अनुमति देती है कि आप कौन से उदाहरणों के साथ अपने ऑब्जेक्ट उदाहरणों की अपेक्षा करते हैं, अपेक्षित परिणाम के साथ:

  1. तेजी से विशेषता का उपयोग।
  2. स्मृति में स्थान की बचत

अंतरिक्ष की बचत से होती है

  1. के बजाय स्लॉट में मूल्य संदर्भ संग्रहीत करना __dict__
  2. यदि माता-पिता वर्ग उन्हें अस्वीकार करते हैं और आप घोषित करते हैं तो इनकार करना __dict__और __weakref__निर्माण करना __slots__

क्विक कैविट्स

लघु चेतावनी, आपको केवल एक वंशानुक्रम में एक विशेष स्लॉट को एक बार घोषित करना चाहिए। उदाहरण के लिए:

class Base:
    __slots__ = 'foo', 'bar'

class Right(Base):
    __slots__ = 'baz', 

class Wrong(Base):
    __slots__ = 'foo', 'bar', 'baz'        # redundant foo and bar

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

>>> from sys import getsizeof
>>> getsizeof(Right()), getsizeof(Wrong())
(56, 72)

इसका कारण यह है कि बेस के स्लॉट डिस्क्रिप्टर में गलत से अलग एक स्लॉट होता है। यह आमतौर पर नहीं आना चाहिए, लेकिन यह हो सकता है:

>>> w = Wrong()
>>> w.foo = 'foo'
>>> Base.foo.__get__(w)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: foo
>>> Wrong.foo.__get__(w)
'foo'

सबसे बड़ी चेतावनी कई उत्तराधिकारियों के लिए है - कई "पैरेंट क्लास के साथ नॉनमीप्टी स्लॉट्स" को जोड़ा नहीं जा सकता है।

इस प्रतिबंध को समायोजित करने के लिए, सर्वोत्तम प्रथाओं का पालन करें: सभी लेकिन एक या सभी माता-पिता के अमूर्त कारक को निकाल दें जो क्रमशः उनके ठोस वर्ग और आपके नए ठोस वर्ग को सामूहिक रूप से विरासत में मिलेगा - अमूर्त (ओं) को खाली स्लॉट्स देना (जैसे अमूर्त वर्ग वर्गों में) मानक पुस्तकालय)।

एक उदाहरण के लिए नीचे दिए गए कई उत्तराधिकार पर अनुभाग देखें।

आवश्यकताएँ:

  • __slots__वास्तव में नामित विशेषताओं को एक के बजाय स्लॉट में संग्रहीत किया __dict__जाना चाहिए, एक वर्ग को इनहेरिट करना होगा object

  • के निर्माण को रोकने के लिए __dict__, आपको इनहेरिट करना होगा objectऔर इनहेरिटेंस में सभी वर्गों को घोषित करना होगा __slots__और उनमें से किसी की भी '__dict__'एंट्री नहीं हो सकती है ।

यदि आप पढ़ते रहना चाहते हैं तो बहुत सारे विवरण हैं।

क्यों उपयोग करें __slots__: तेज़ विशेषता पहुंच।

पाइथन के निर्माता, गुइडो वैन रोसुम कहते हैं कि उन्होंने वास्तव में __slots__तेज विशेषता पहुंच के लिए बनाया था ।

यह औसत दर्जे का महत्वपूर्ण तेज पहुंच प्रदर्शित करने के लिए तुच्छ है:

import timeit

class Foo(object): __slots__ = 'foo',

class Bar(object): pass

slotted = Foo()
not_slotted = Bar()

def get_set_delete_fn(obj):
    def get_set_delete():
        obj.foo = 'foo'
        obj.foo
        del obj.foo
    return get_set_delete

तथा

>>> min(timeit.repeat(get_set_delete_fn(slotted)))
0.2846834529991611
>>> min(timeit.repeat(get_set_delete_fn(not_slotted)))
0.3664822799983085

उबंटू पर पायथन 3.5 में स्लॉटेड एक्सेस लगभग 30% तेज है।

>>> 0.3664822799983085 / 0.2846834529991611
1.2873325658284342

विंडोज पर पायथन 2 में मैंने इसे लगभग 15% तेजी से मापा है।

क्यों उपयोग करें __slots__: मेमोरी सेविंग

इसका दूसरा उद्देश्य __slots__स्मृति में उस स्थान को कम करना है जो प्रत्येक वस्तु का उदाहरण लेता है।

प्रलेखन में मेरा अपना योगदान स्पष्ट रूप से इसके पीछे के कारण बताता है :

उपयोग करने से बचाए गए स्थान __dict__महत्वपूर्ण हो सकते हैं।

SQLAlchemy बहुत सारी मेमोरी सेविंग का श्रेय देता है __slots__

इसे सत्यापित करने के लिए, उबंटू लिनक्स पर पायथन 2.7 के एनाकोंडा वितरण का उपयोग करते हुए guppy.hpy(उर्फ हीप) और sys.getsizeof, बिना __slots__घोषित किए एक वर्ग उदाहरण का आकार , और कुछ नहीं, 64 बाइट्स है। यही कारण है कि है नहीं शामिल __dict__। फिर से आलसी मूल्यांकन के लिए पाइथन को धन्यवाद दें, __dict__यह स्पष्ट रूप से अस्तित्व में नहीं है जब तक कि इसे संदर्भित नहीं किया जाता है, लेकिन डेटा के बिना कक्षाएं आमतौर पर बेकार होती हैं। जब अस्तित्व में कहा जाता है, तो __dict__विशेषता अतिरिक्त 280 बाइट्स की एक न्यूनतम होती है।

इसके विपरीत, एक वर्ग उदाहरण के साथ __slots__घोषित ()(कोई डेटा नहीं) केवल 16 बाइट्स है, और 56 कुल बाइट्स एक आइटम के साथ स्लॉट्स में, 64 दो के साथ।

64 बिट पायथन के लिए, मैं पायथन 2.7 और 3.6 में बाइट्स में मेमोरी खपत का वर्णन करता हूं, __slots__और __dict__प्रत्येक बिंदु के लिए और (कोई स्लॉट निर्धारित नहीं) जहां 3.6 में तानाशाही बढ़ती है (0, 1, और 2 विशेषताओं को छोड़कर):

       Python 2.7             Python 3.6
attrs  __slots__  __dict__*   __slots__  __dict__* | *(no slots defined)
none   16         56 + 272   16         56 + 112 | if __dict__ referenced
one    48         56 + 272    48         56 + 112
two    56         56 + 272    56         56 + 112
six    88         56 + 1040   88         56 + 152
11     128        56 + 1040   128        56 + 240
22     216        56 + 3344   216        56 + 408     
43     384        56 + 3344   384        56 + 752

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

मेरे नोटों की पूर्णता के लिए, ध्यान दें कि पायथन 2 में क्लास के 64 बाइट्स के नाम स्थान में प्रति स्लॉट और पायथन 3 में 72 बाइट्स में एक बार की लागत है, क्योंकि स्लॉट्स गुणों जैसे डेटा डिस्क्रिप्टर का उपयोग करते हैं, जिन्हें "सदस्य" कहा जाता है।

>>> Foo.foo
<member 'foo' of 'Foo' objects>
>>> type(Foo.foo)
<class 'member_descriptor'>
>>> getsizeof(Foo.foo)
72

का प्रदर्शन __slots__:

एक के निर्माण से इनकार करने के लिए __dict__, आपको उपवर्ग करना होगा object:

class Base(object): 
    __slots__ = ()

अभी:

>>> b = Base()
>>> b.a = 'a'
Traceback (most recent call last):
  File "<pyshell#38>", line 1, in <module>
    b.a = 'a'
AttributeError: 'Base' object has no attribute 'a'

या एक अन्य वर्ग को परिभाषित करता है जो परिभाषित करता है __slots__

class Child(Base):
    __slots__ = ('a',)

और अब:

c = Child()
c.a = 'a'

परंतु:

>>> c.b = 'b'
Traceback (most recent call last):
  File "<pyshell#42>", line 1, in <module>
    c.b = 'b'
AttributeError: 'Child' object has no attribute 'b'

अनुमति देने के लिए __dict__, जबकि slotted वस्तुओं उपवर्गीकरण, बस जोड़ने के निर्माण '__dict__'के लिए __slots__(ध्यान दें कि स्लॉट का आदेश दिया जाता है, और आप नहीं दोहराने स्लॉट कि माता-पिता की कक्षाओं में पहले से ही कर रहे हैं चाहिए):

class SlottedWithDict(Child): 
    __slots__ = ('__dict__', 'b')

swd = SlottedWithDict()
swd.a = 'a'
swd.b = 'b'
swd.c = 'c'

तथा

>>> swd.__dict__
{'c': 'c'}

या आपको __slots__अपने उपवर्ग में घोषित करने की आवश्यकता नहीं है , और आप अभी भी माता-पिता से स्लॉट का उपयोग करेंगे, लेकिन इसके निर्माण को प्रतिबंधित नहीं करेंगे __dict__:

class NoSlots(Child): pass
ns = NoSlots()
ns.a = 'a'
ns.b = 'b'

तथा:

>>> ns.__dict__
{'b': 'b'}

हालाँकि, __slots__एकाधिक वंशानुक्रम के लिए समस्याएँ हो सकती हैं:

class BaseA(object): 
    __slots__ = ('a',)

class BaseB(object): 
    __slots__ = ('b',)

क्योंकि दोनों गैर-खाली स्लॉट वाले माता-पिता से एक बच्चा वर्ग बनाना विफल रहता है:

>>> class Child(BaseA, BaseB): __slots__ = ()
Traceback (most recent call last):
  File "<pyshell#68>", line 1, in <module>
    class Child(BaseA, BaseB): __slots__ = ()
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

आप इस समस्या आ रही हों, आप हो सकता है बस को दूर__slots__ माता-पिता से , या यदि आपके पास माता-पिता का नियंत्रण है, तो उन्हें खाली स्लॉट दें, या अमूर्त को रिफ्लेक्टर दें:

from abc import ABC

class AbstractA(ABC):
    __slots__ = ()

class BaseA(AbstractA): 
    __slots__ = ('a',)

class AbstractB(ABC):
    __slots__ = ()

class BaseB(AbstractB): 
    __slots__ = ('b',)

class Child(AbstractA, AbstractB): 
    __slots__ = ('a', 'b')

c = Child() # no problem!

डायनामिक असाइनमेंट प्राप्त '__dict__'करने के __slots__लिए जोड़ें :

class Foo(object):
    __slots__ = 'bar', 'baz', '__dict__'

और अब:

>>> foo = Foo()
>>> foo.boink = 'boink'

के साथ '__dict__' स्लॉट्स में हम डायनामिक असाइनमेंट होने के साथ कुछ साइज़ बेनिफिट्स खो देते हैं और फिर भी उन नामों के लिए स्लॉट्स होते हैं जिनकी हम उम्मीद करते हैं।

जब आप किसी ऐसी वस्तु से विरासत में आते हैं, जिसे सुव्यवस्थित नहीं किया जाता है, तो आप उसी तरह के शब्दार्थ का उपयोग करते हैं जब आप __slots__उस नाम का उपयोग करते हैं__slots__ स्लॉटेड मानों के लिए हैं, जबकि किसी अन्य मान को उदाहरण के लिए रखा जाता है __dict__

से बचने के लिए __slots__क्योंकि आप मक्खी पर विशेषताओं को जोड़ने में सक्षम होना चाहते हैं वास्तव में एक अच्छा कारण नहीं है - बस जोड़ें"__dict__"__slots__ यदि आवश्यक हो तो ही इसे अपने साथ ।

आप इसी तरह से जोड़ सकते हैं __weakref__करने के लिए__slots__ स्पष्ट रूप से अगर आपको लगता है कि सुविधा की जरूरत है।

जब किसी नेमप्ले को उप-रिक्त कर रहा हो तो खाली ट्यूपल पर सेट करें:

नेमटुपल बिलिन अपरिवर्तनीय उदाहरण बनाते हैं जो बहुत हल्के होते हैं (अनिवार्य रूप से, टुपल्स का आकार) लेकिन लाभ प्राप्त करने के लिए, आपको इसे स्वयं करने की आवश्यकता होती है यदि आप उन्हें उपवर्ग करते हैं:

from collections import namedtuple
class MyNT(namedtuple('MyNT', 'bar baz')):
    """MyNT is an immutable and lightweight object"""
    __slots__ = ()

उपयोग:

>>> nt = MyNT('bar', 'baz')
>>> nt.bar
'bar'
>>> nt.baz
'baz'

और एक अनपेक्षित विशेषता को निर्दिष्ट करने की कोशिश करने से AttributeErrorहम पैदा होते हैं, क्योंकि __dict__:

>>> nt.quux = 'quux'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyNT' object has no attribute 'quux'

आप निर्माण को छोड़ने की अनुमति दे सकते हैं , लेकिन आप टपल के उप - वर्गों के साथ गैर-रिक्त का उपयोग नहीं कर सकते ।__dict____slots__ = ()__slots__

सबसे बड़ी कैवेट: एकाधिक विरासत

यहां तक ​​कि जब गैर-खाली स्लॉट कई माता-पिता के लिए समान होते हैं, तो उनका उपयोग एक साथ नहीं किया जा सकता है:

class Foo(object): 
    __slots__ = 'foo', 'bar'
class Bar(object):
    __slots__ = 'foo', 'bar' # alas, would work if empty, i.e. ()

>>> class Baz(Foo, Bar): pass
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    multiple bases have instance lay-out conflict

__slots__माता-पिता में एक रिक्त का उपयोग करना सबसे अधिक लचीलापन प्रदान करता है, जिससे बच्चे को रोकने या चुनने की अनुमति मिलती है ( '__dict__'गतिशील असाइनमेंट प्राप्त करने के लिए जोड़कर , ऊपर अनुभाग देखें) का निर्माण__dict__ :

class Foo(object): __slots__ = ()
class Bar(object): __slots__ = ()
class Baz(Foo, Bar): __slots__ = ('foo', 'bar')
b = Baz()
b.foo, b.bar = 'foo', 'bar'

आपके पास स्लॉट नहीं हैं - इसलिए यदि आप उन्हें जोड़ते हैं, और उन्हें बाद में हटा देते हैं, तो इससे कोई समस्या नहीं होनी चाहिए।

यहां एक अंग पर बाहर जाना : यदि आप मिक्सिंस की रचना कर रहे हैं या अमूर्त आधार वर्गों का उपयोग कर रहे हैं, जो कि तात्कालिक होने का इरादा नहीं है, तो __slots__उन माता-पिता में एक खाली उप-वर्ग के लिए लचीलेपन के मामले में जाने का सबसे अच्छा तरीका लगता है।

प्रदर्शित करने के लिए, पहले, आइए कोड के साथ एक वर्ग बनाएं जिसे हम कई उत्तराधिकार के तहत उपयोग करना चाहते हैं

class AbstractBase:
    __slots__ = ()
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def __repr__(self):
        return f'{type(self).__name__}({repr(self.a)}, {repr(self.b)})'

हम अपेक्षित स्लॉट्स को इनहेरिट और घोषित करके सीधे ऊपर का उपयोग कर सकते हैं:

class Foo(AbstractBase):
    __slots__ = 'a', 'b'

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

class AbstractBaseC:
    __slots__ = ()
    @property
    def c(self):
        print('getting c!')
        return self._c
    @c.setter
    def c(self, arg):
        print('setting c!')
        self._c = arg

अब यदि दोनों ठिकानों में गैर-रिक्त स्थान थे, तो हम नीचे नहीं कर सकते थे। (वास्तव में, अगर हम चाहते थे, हम AbstractBaseनॉनम खाली स्लॉट्स को ए और बी दे सकते थे, और उन्हें नीचे की घोषणा से छोड़ दिया - उन्हें छोड़ना गलत होगा):

class Concretion(AbstractBase, AbstractBaseC):
    __slots__ = 'a b _c'.split()

और अब हमारे पास कई उत्तराधिकार के माध्यम से कार्यक्षमता है, और अभी भी इनकार कर सकते हैं __dict__और __weakref__तात्कालिकता:

>>> c = Concretion('a', 'b')
>>> c.c = c
setting c!
>>> c.c
getting c!
Concretion('a', 'b')
>>> c.d = 'd'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Concretion' object has no attribute 'd'

स्लॉट से बचने के लिए अन्य मामले:

  • जब आप प्रदर्शन करना चाहते हैं तो उनसे बचें __class__ किसी अन्य वर्ग के साथ असाइनमेंट (जब तक कि स्लॉट लेआउट समान नहीं हों, तब तक उनके पास नहीं है (और आप उन्हें जोड़ नहीं सकते)। (मुझे यह सीखने में बहुत दिलचस्पी है कि यह कौन कर रहा है और क्यों।)
  • यदि आप लॉन्ग, टपल या स्ट्रैग जैसे वैरिएबल लेंथ बिल्डिंस को उप-वर्ग करना चाहते हैं, तो उन्हें अवॉइड करें और आप उन पर खूबियां जोड़ना चाहते हैं।
  • यदि आप उदाहरण चर के लिए वर्ग विशेषताओं के माध्यम से डिफ़ॉल्ट मान प्रदान करने पर जोर देते हैं तो उनसे बचें।

आप बाकी __slots__ दस्तावेज़ीकरण (3.7 देव डॉक्स सबसे वर्तमान हैं) से और अधिक छेड़छाड़ करने में सक्षम हो सकते हैं , जिसे मैंने हाल ही में महत्वपूर्ण योगदान दिया है।

अन्य उत्तरों की आलोचना

वर्तमान शीर्ष उत्तर पुरानी जानकारी का हवाला देते हैं और काफी हाथ से लहराते हैं और कुछ महत्वपूर्ण तरीकों से निशान को याद करते हैं।

"केवल उपयोग न करें __slots__ तब जब बहुत सी वस्तुओं को तत्काल"

मैं उद्धृत करता हूं:

"आप उपयोग करना चाहते हैं __slots__यदि आप एक ही वर्ग के ऑब्जेक्ट्स के बहुत (सैकड़ों, हजारों) को इंस्टेंट करने जा रहे हैं।"

सार बेस क्लास, उदाहरण के लिए, collectionsमॉड्यूल से, त्वरित नहीं __slots__हैं , फिर भी उनके लिए घोषित किए जाते हैं।

क्यों?

यदि कोई उपयोगकर्ता इनकार करना __dict__या __weakref__निर्माण करना चाहता है , तो वे चीजें मूल कक्षाओं में उपलब्ध नहीं होनी चाहिए।

__slots__ इंटरफेस या मिश्रण बनाते समय पुन: प्रयोज्य में योगदान देता है।

यह सच है कि कई पायथन उपयोगकर्ता पुन: प्रयोज्यता के लिए नहीं लिख रहे हैं, लेकिन जब आप होते हैं, तो अनावश्यक स्थान उपयोग से इनकार करने का विकल्प मूल्यवान है।

__slots__ अचार नहीं तोड़ता

किसी स्लेटेड ऑब्जेक्ट को अचार करते समय, आप पा सकते हैं कि यह एक भ्रामक शिकायत है TypeError:

>>> pickle.loads(pickle.dumps(f))
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled

यह वास्तव में गलत है। यह संदेश सबसे पुराने प्रोटोकॉल से आता है, जो डिफ़ॉल्ट है। आप -1तर्क के साथ नवीनतम प्रोटोकॉल का चयन कर सकते हैं । पायथन 2.7 में यह होगा 2(जिसे 2.3 में पेश किया गया था), और 3.6 में है 4

>>> pickle.loads(pickle.dumps(f, -1))
<__main__.Foo object at 0x1129C770>

पायथन 2.7 में:

>>> pickle.loads(pickle.dumps(f, 2))
<__main__.Foo object at 0x1129C770>

पायथन में 3.6

>>> pickle.loads(pickle.dumps(f, 4))
<__main__.Foo object at 0x1129C770>

इसलिए मैं इसे ध्यान में रखूंगा, क्योंकि यह एक हल की हुई समस्या है।

(2 अक्टूबर, 2016 तक) की आलोचना ने उत्तर स्वीकार कर लिया

पहला पैराग्राफ आधा लघु स्पष्टीकरण, आधा प्रेडिक्टिव है। यहाँ केवल वही हिस्सा है जो वास्तव में प्रश्न का उत्तर देता है

__slots__वस्तुओं में स्थान बचाने के लिए इसका उचित उपयोग है। एक गतिशील तानाशाही होने के बजाय जो किसी भी समय वस्तुओं को जोड़ने की अनुमति देती है, एक स्थिर संरचना है जो निर्माण के बाद परिवर्धन की अनुमति नहीं देती है। यह स्लॉट्स का उपयोग करने वाले प्रत्येक ऑब्जेक्ट के लिए एक तानाशाही के ओवरहेड को बचाता है

दूसरी छमाही इच्छाधारी सोच है, और निशान से दूर:

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

पाइथन वास्तव में इसके समान कुछ करता है, केवल __dict__जब यह एक्सेस किया जाता है, तब बनाता है, लेकिन बिना डेटा के बहुत से ऑब्जेक्ट बनाना काफी हास्यास्पद है।

दूसरा पैराग्राफ ओवरसाइज़ करता है और बचने के लिए वास्तविक कारणों को याद करता है __slots__। स्लॉट्स से बचने के लिए नीचे एक वास्तविक कारण नहीं है ( वास्तविक कारणों के लिए, ऊपर दिए गए मेरे उत्तर के बाकी देखें।)।

वे उन वस्तुओं के व्यवहार को बदल देते हैं जिनके पास स्लॉट्स होते हैं जिन्हें नियंत्रण शैतान और स्थिर टाइपिंग वेनिज़ द्वारा दुरुपयोग किया जा सकता है।

यह तब पायथन के साथ उस विकृत लक्ष्य को पूरा करने के अन्य तरीकों पर चर्चा करने के लिए आगे बढ़ता है, कुछ भी करने के लिए चर्चा नहीं करता है __slots__

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

स्मृति उपयोग प्रमाण

कुछ सामान्य वस्तुएँ और स्लेटेड वस्तुएँ बनाएँ:

>>> class Foo(object): pass
>>> class Bar(object): __slots__ = ()

उनमें से एक लाख को तुरंत:

>>> foos = [Foo() for f in xrange(1000000)]
>>> bars = [Bar() for b in xrange(1000000)]

के साथ निरीक्षण guppy.hpy().heap():

>>> guppy.hpy().heap()
Partition of a set of 2028259 objects. Total size = 99763360 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0 1000000  49 64000000  64  64000000  64 __main__.Foo
     1     169   0 16281480  16  80281480  80 list
     2 1000000  49 16000000  16  96281480  97 __main__.Bar
     3   12284   1   987472   1  97268952  97 str
...

नियमित वस्तुओं और उनके उपयोग __dict__और फिर से निरीक्षण करें:

>>> for f in foos:
...     f.__dict__
>>> guppy.hpy().heap()
Partition of a set of 3028258 objects. Total size = 379763480 bytes.
 Index  Count   %      Size    % Cumulative  % Kind (class / dict of class)
     0 1000000  33 280000000  74 280000000  74 dict of __main__.Foo
     1 1000000  33  64000000  17 344000000  91 __main__.Foo
     2     169   0  16281480   4 360281480  95 list
     3 1000000  33  16000000   4 376281480  99 __main__.Bar
     4   12284   0    987472   0 377268952  99 str
...

यह पायथन के इतिहास के अनुरूप है, पायथन 2.2 में यूनिफाइंग प्रकार और कक्षाओं से

यदि आप एक अंतर्निहित प्रकार को उप-वर्ग करते हैं, तो अतिरिक्त स्थान स्वचालित रूप से जोड़ने के लिए उदाहरणों में जोड़ा जाता है __dict__और __weakrefs__। ( __dict__जब तक आप इसे उपयोग नहीं करते हैं, तब तक इसे आरंभिक नहीं किया जाता है, इसलिए आपको अपने द्वारा बनाए गए प्रत्येक उदाहरण के लिए खाली शब्दकोश द्वारा कब्जा किए गए स्थान के बारे में चिंता नहीं करनी चाहिए।) यदि आपको इस अतिरिक्त स्थान की आवश्यकता नहीं है, तो आप वाक्यांश " __slots__ = []" जोड़ सकते हैं। आपकी कक्षा।


14
वाह, एक उत्तर का एक नरक - धन्यवाद! हालाँकि, मैंने class Child(BaseA, BaseB): __slots__ = ('a', 'b')एम्प्टी-स्लॉट-माता-पिता के साथ उदाहरण नहीं पकड़ा । क्यों यहाँ एक dictproxyके AttributeErrorलिए एक उठाया के बजाय बनाया है c?
स्कैंडिक्स

@ स्कैंडिक्स मेरे ध्यान में उस टाइपो को लाने के लिए धन्यवाद, यह पता चला कि सी एक तात्कालिकता नहीं थी, मैं शायद भूल गया कि मैं उस हिस्से को संपादित कर रहा था जब मैंने इसे पोस्ट इतिहास में सहेजा था। यह शायद जल्द ही पकड़ा गया होता अगर मैंने सही काम किया और कोड को अधिक कॉपी-पेस्ट करने योग्य बना दिया ... फिर से धन्यवाद!
हारून हॉल

38
यह उत्तर आधिकारिक पायथन प्रलेखन का हिस्सा होना चाहिए __slots__। गंभीरता से! धन्यवाद!
नाइटलाइफ

13
@NightElfik मानो या न मानो, मैं पर अजगर डॉक्स के लिए योगदान दिया __slots__: एक साल वापस बारे में github.com/python/cpython/pull/1819/files
हारून हॉल

शानदार विस्तृत जवाब। मेरा एक सवाल है: क्या किसी को डिफ़ॉल्ट के रूप में स्लॉट्स का उपयोग किया जाना चाहिए जब तक कि उपयोग कैवेट में से किसी एक को हिट नहीं करता है, या क्या आप कुछ जानते हैं कि क्या आप गति / मेमोरी के लिए संघर्ष करने जा रहे हैं? इसे दूसरे तरीके से रखने के लिए, क्या आपको एक नौसिखिया को उनके बारे में जानने और उन्हें शुरू से इस्तेमाल करने के लिए प्रोत्साहित करना चाहिए?
1919 freethebees

265

कोटिंग जैकब हॉलन :

__slots__वस्तुओं में स्थान बचाने के लिए इसका उचित उपयोग है। एक गतिशील तानाशाही होने के बजाय जो किसी भी समय वस्तुओं को जोड़ने की अनुमति देती है, एक स्थिर संरचना है जो निर्माण के बाद परिवर्धन की अनुमति नहीं देती है। [यह उपयोग __slots__हर वस्तु के लिए एक तानाशाही के उपरि को समाप्त करता है।] जबकि यह कभी-कभी एक उपयोगी अनुकूलन होता है, यह पूरी तरह से अनावश्यक होगा यदि पायथन दुभाषिया इतना गतिशील था कि इसे केवल तब ही तानाशाह की आवश्यकता होगी जब वास्तव में परिवर्धन थे। वस्तु।

दुर्भाग्य से स्लॉट्स के लिए एक साइड इफेक्ट है। वे उन वस्तुओं के व्यवहार को बदल देते हैं जिनके पास स्लॉट्स होते हैं जिन्हें नियंत्रण शैतान और स्थिर टाइपिंग वेनिज़ द्वारा दुरुपयोग किया जा सकता है। यह बुरा है, क्योंकि नियंत्रण शैतान को मेटाक्लासेस को गाली देनी चाहिए और स्थैतिक टाइपिंग वेनियां डेकोरेटर्स को गाली देनी चाहिए, क्योंकि पायथन में, कुछ करने का केवल एक स्पष्ट तरीका होना चाहिए।

CPython को स्मार्ट बनाना, बिना अंतरिक्ष को बचाने के __slots__लिए एक बड़ा उपक्रम है, जो संभवतः P3k (अभी तक) के बदलावों की सूची में नहीं है।


86
मैं "स्टैटिक टाइपिंग" / डेकोरेटर पॉइंट, सैंस पीजोरेटिव्स पर कुछ विस्तार देखना चाहता हूं। अनुपस्थित तीसरे पक्ष को उद्धृत करना अकारण है। __slots__स्थैतिक टाइपिंग के समान मुद्दों को संबोधित नहीं करता है। उदाहरण के लिए, C ++ में, यह सदस्य चर की घोषणा को प्रतिबंधित नहीं किया जा रहा है, यह उस चर के लिए एक अनपेक्षित प्रकार (और संकलित लागू) का असाइनमेंट है। मैं उपयोग नहीं कर रहा हूँ __slots__, बस बातचीत में दिलचस्पी है। धन्यवाद!
हाईवेलॉन

126

आप उपयोग करना चाहते हैं __slots__यदि आप एक ही वर्ग की वस्तुओं के बहुत (सैकड़ों, हजारों) पलटने जा रहे हैं। __slots__केवल मेमोरी ऑप्टिमाइज़ेशन टूल के रूप में मौजूद है।

यह __slots__विशेषता निर्माण के लिए विवश करने के लिए अत्यधिक हतोत्साहित है ।

__slots__डिफ़ॉल्ट (सबसे पुराना) अचार प्रोटोकॉल के साथ काम करने वाली वस्तुओं को अचार बनाना नहीं होगा; बाद के संस्करण को निर्दिष्ट करना आवश्यक है।

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


10
मैं अपने उत्तर में एक स्लेटेड वस्तु चुनता हूं और आपके उत्तर के पहले भाग को भी दिखाता हूं।
हारून हॉल

2
मैं आपकी बात देख रहा हूं, लेकिन स्लॉट तेजी से विशेषता पहुंच प्रदान करते हैं (जैसा कि अन्य ने कहा है)। उस स्थिति में आपको प्रदर्शन हासिल करने के लिए "एक ही वर्ग की वस्तुओं के बहुत से (सैकड़ों, हजारों)" पलटने की आवश्यकता नहीं है । इसके बजाय आपको जो कुछ भी चाहिए वह उसी उदाहरण के बहुत सारे (स्लोटेड) विशेषता तक पहुंच है। (कृपया मुझे गलत
समझें

61

प्रत्येक अजगर वस्तु में एक __dict__गुण है जो अन्य सभी विशेषताओं से युक्त एक शब्दकोश है। जैसे जब आप self.attrअजगर टाइप करते हैं तो वास्तव में कर रहे होते हैं self.__dict__['attr']। जैसा कि आप स्टोर करने के लिए एक शब्दकोश का उपयोग करने की कल्पना कर सकते हैं विशेषता इसे एक्सेस करने के लिए कुछ अतिरिक्त स्थान और समय लेती है।

हालाँकि, जब आप उपयोग करते हैं, तो __slots__उस वर्ग के लिए बनाई गई किसी भी वस्तु की __dict__विशेषता नहीं होगी । इसके बजाय, सभी विशेषता पहुंच सीधे पॉइंटर्स के माध्यम से की जाती है।

इसलिए यदि आप पूर्ण विकसित वर्ग के बजाय C शैली संरचना चाहते हैं, तो आप __slots__वस्तुओं के आकार और विशेषता पहुंच समय को कम करने के लिए उपयोग कर सकते हैं। एक अच्छा उदाहरण एक बिंदु वर्ग है जिसमें एक्स और वाई के गुण हैं। यदि आपके पास बहुत सारे बिंदु हैं, तो आप __slots__कुछ मेमोरी को संरक्षित करने के लिए उपयोग करने का प्रयास कर सकते हैं ।


10
नहीं, __slots__परिभाषित के साथ वर्ग का एक उदाहरण सी-शैली संरचना की तरह नहीं है । अनुक्रमित करने के लिए एक वर्ग-स्तरीय शब्दकोश मानचित्रण विशेषता नाम है, अन्यथा निम्नलिखित संभव नहीं होगा: class A(object): __slots__= "value",\n\na=A(); setattr(a, 'value', 1)मुझे वास्तव में लगता है कि इस उत्तर को स्पष्ट किया जाना चाहिए (यदि आप चाहें तो मैं यह कर सकता हूं)। इसके अलावा, मैं निश्चित नहीं हूं कि इससे instance.__hidden_attributes[instance.__class__[attrname]]ज्यादा तेज है instance.__dict__[attrname]
tzot 13

22

अन्य उत्तरों के अलावा, यहां एक उदाहरण दिया गया है __slots__:

>>> class Test(object):   #Must be new-style class!
...  __slots__ = ['x', 'y']
... 
>>> pt = Test()
>>> dir(pt)
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', 
 '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__slots__', '__str__', 'x', 'y']
>>> pt.x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: x
>>> pt.x = 1
>>> pt.x
1
>>> pt.z = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute 'z'
>>> pt.__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__dict__'
>>> pt.__slots__
['x', 'y']

इसलिए, __slots__इसे लागू करने के लिए , यह केवल एक अतिरिक्त लाइन लेता है (और अगर यह पहले से ही नहीं है तो अपनी कक्षा को एक नई शैली की कक्षा बना सकता है)। इस तरह आप कस्टम अचार कोड लिखने की कीमत पर, उन वर्गों की स्मृति पदचिह्न 5-गुना कम कर सकते हैं , यदि और जब आवश्यक हो।


11

फ़ंक्शन कॉल करते समय "नामित विधि प्रेषण" को समाप्त करने के लिए लाइब्रेरी कॉल के लिए स्लॉट बहुत उपयोगी होते हैं। यह SWIG प्रलेखन में उल्लेख किया गया है । उच्च निष्पादन पुस्तकालयों के लिए जो स्लॉट्स का उपयोग करके आमतौर पर तथाकथित फ़ंक्शन के लिए फ़ंक्शन ओवरहेड को कम करना चाहते हैं, बहुत तेज है।

अब यह सीधे ओपी प्रश्न से संबंधित नहीं हो सकता है। यह ऑब्जेक्ट पर स्लॉट्स सिंटैक्स का उपयोग करने की तुलना में एक्सटेंशन बनाने से अधिक संबंधित है । लेकिन यह स्लॉट के उपयोग के लिए तस्वीर को पूरा करने में मदद करता है और उनके पीछे के कुछ तर्क।


7

एक वर्ग उदाहरण की विशेषता में 3 गुण होते हैं: उदाहरण, विशेषता का नाम और विशेषता का मान।

में नियमित विशेषता का उपयोग , उदाहरण के एक शब्दकोश के रूप में कार्य करता है और के रूप में है कि शब्दकोश में कुंजी मान को देख विशेषता का नाम कार्य करता है।

उदाहरण (विशेषता) -> मान

में __slots__ पहुँच , विशेषता का नाम शब्दकोश के रूप में कार्य करता है और उदाहरण के रूप में कार्य करता है शब्दकोश में कुंजी मान को देख।

विशेषता (उदाहरण) -> मान

में फ्लाईवेट पैटर्न , विशेषता का नाम शब्दकोश के रूप में कार्य करता है और मूल्य है कि शब्दकोश में महत्वपूर्ण उदाहरण को देख के रूप में कार्य करता है।

विशेषता (मान) -> उदाहरण


यह एक अच्छा हिस्सा है, और किसी एक जवाब पर अच्छी तरह से फिट नहीं होगा जो कि फ्लाईवेट का भी सुझाव देता है, लेकिन यह स्वयं प्रश्न का पूर्ण उत्तर नहीं है। विशेष रूप से (प्रश्न के सिर्फ संदर्भ में): क्यों फ्लाईवेट, और "उन मामलों में जो एक से बचना चाहिए ..." हैं __slots__?
मेरलिन मॉर्गन-ग्राहम

@ मर्लिन मॉर्गन-ग्राहम, यह एक संकेत के रूप में कार्य करता है जिस पर लेने के लिए: नियमित पहुंच, __slots__, या फ्लाईवेट।
दिमित्री रुबनोविच

3

__slot__विशेषता का एक बहुत ही सरल उदाहरण ।

समस्या: बिना __slots__

यदि __slot__मेरी कक्षा में विशेषता नहीं है , तो मैं अपनी वस्तुओं में नई विशेषताएँ जोड़ सकता हूँ।

class Test:
    pass

obj1=Test()
obj2=Test()

print(obj1.__dict__)  #--> {}
obj1.x=12
print(obj1.__dict__)  # --> {'x': 12}
obj1.y=20
print(obj1.__dict__)  # --> {'x': 12, 'y': 20}

obj2.x=99
print(obj2.__dict__)  # --> {'x': 99}

यदि आप ऊपर दिए गए उदाहरण को देखते हैं, तो आप देख सकते हैं कि obj1 और obj2 की अपनी x और y विशेषताएँ हैं और अजगर ने dictप्रत्येक ऑब्जेक्ट ( obj1 और obj2 ) के लिए एक विशेषता भी बनाई है ।

मान लीजिए अगर मेरे क्लास टेस्ट में ऐसी हजारों वस्तुएं हैं? dictप्रत्येक ऑब्जेक्ट के लिए एक अतिरिक्त विशेषता बनाने से मेरे कोड में बहुत सारे ओवरहेड (मेमोरी, कंप्यूटिंग पावर आदि) हो जाएंगे।

समाधान: के साथ __slots__

अब निम्नलिखित उदाहरण में मेरे वर्ग टेस्ट में __slots__विशेषता है। अब मैं अपनी वस्तुओं (विशेषता को छोड़कर x) में नई विशेषताओं को नहीं जोड़ सकता और अजगर dictअब एक विशेषता नहीं बनाता है । यह प्रत्येक वस्तु के लिए ओवरहेड को समाप्त करता है, जो आपके पास कई ऑब्जेक्ट होने पर महत्वपूर्ण हो सकता है।

class Test:
    __slots__=("x")

obj1=Test()
obj2=Test()
obj1.x=12
print(obj1.x)  # --> 12
obj2.x=99
print(obj2.x)  # --> 99

obj1.y=28
print(obj1.y)  # --> AttributeError: 'Test' object has no attribute 'y'

2

एक और कुछ अस्पष्ट उपयोग __slots__ProxyTypes पैकेज से ऑब्जेक्ट प्रॉक्सी के लिए विशेषताओं को जोड़ना है, जो पहले PEAK प्रोजेक्ट का हिस्सा था। यह ObjectWrapperआपको किसी अन्य ऑब्जेक्ट को प्रॉक्सी करने की अनुमति देता है, लेकिन अनुमानित ऑब्जेक्ट के साथ सभी इंटरैक्शन को इंटरसेप्ट करता है। यह आमतौर पर बहुत अधिक उपयोग नहीं किया जाता है (और पायथन 3 समर्थन नहीं है), लेकिन हमने इसका उपयोग एक थ्रेड-आधारित पर एक एसिंक्स कार्यान्वयन के चारों ओर एक थ्रेड-सुरक्षित अवरोधक आवरण को लागू करने के लिए किया है, जो थ्रेड-सेफ का उपयोग करते हुए, ioloop के माध्यम से समीपस्थ वस्तु तक सभी पहुंच को बाउंस करता है। concurrent.Futureवस्तुओं को सिंक्रनाइज़ करने और परिणाम वापस करने के लिए।

डिफ़ॉल्ट रूप से प्रॉक्सी ऑब्जेक्ट तक किसी भी विशेषता का उपयोग आपको अनुमानित ऑब्जेक्ट से परिणाम देगा। यदि आपको प्रॉक्सी ऑब्जेक्ट पर एक विशेषता जोड़ने की आवश्यकता है, तो __slots__इसका उपयोग किया जा सकता है।

from peak.util.proxies import ObjectWrapper

class Original(object):
    def __init__(self):
        self.name = 'The Original'

class ProxyOriginal(ObjectWrapper):

    __slots__ = ['proxy_name']

    def __init__(self, subject, proxy_name):
        # proxy_info attributed added directly to the
        # Original instance, not the ProxyOriginal instance
        self.proxy_info = 'You are proxied by {}'.format(proxy_name)

        # proxy_name added to ProxyOriginal instance, since it is
        # defined in __slots__
        self.proxy_name = proxy_name

        super(ProxyOriginal, self).__init__(subject)

if __name__ == "__main__":
    original = Original()
    proxy = ProxyOriginal(original, 'Proxy Overlord')

    # Both statements print "The Original"
    print "original.name: ", original.name
    print "proxy.name: ", proxy.name

    # Both statements below print 
    # "You are proxied by Proxy Overlord", since the ProxyOriginal
    # __init__ sets it to the original object 
    print "original.proxy_info: ", original.proxy_info
    print "proxy.proxy_info: ", proxy.proxy_info

    # prints "Proxy Overlord"
    print "proxy.proxy_name: ", proxy.proxy_name
    # Raises AttributeError since proxy_name is only set on 
    # the proxy object
    print "original.proxy_name: ", proxy.proxy_name

1

आपके पास - अनिवार्य रूप से - के लिए कोई उपयोग नहीं है __slots__

उस समय के लिए जब आपको लगता है कि आपको आवश्यकता हो सकती है __slots__, आप वास्तव में लाइटवेट या फ्लाईवेट डिजाइन पैटर्न का उपयोग करना चाहते हैं । ये ऐसे मामले हैं जब आप शुद्ध रूप से पाइथन वस्तुओं का उपयोग नहीं करना चाहते हैं। इसके बजाय, आप एक सरणी, संरचना या सुन्न सरणी के चारों ओर एक पायथन ऑब्जेक्ट-जैसे आवरण चाहते हैं।

class Flyweight(object):

    def get(self, theData, index):
        return theData[index]

    def set(self, theData, index, value):
        theData[index]= value

वर्ग की तरह के आवरण में कोई विशेषता नहीं है - यह सिर्फ उन तरीकों को प्रदान करता है जो अंतर्निहित डेटा पर कार्य करते हैं। तरीकों को वर्ग विधियों में कम किया जा सकता है। वास्तव में, यह डेटा के अंतर्निहित सरणी पर काम करने वाले कार्यों को कम किया जा सकता है।


17
फ्लाईवेट के साथ __slots__क्या करना है ?
oefe

3
@oefe: मुझे निश्चित रूप से आपका सवाल नहीं है। मैं अपने जवाब को उद्धृत कर सकता हूं, अगर यह "जब आपको लगता है कि आपको स्लॉट्स की आवश्यकता हो सकती है , तो आप वास्तव में उपयोग करना चाहते हैं ... फ्लाईवेट डिजाइन पैटर्न"। यही फ्लाईवेट को स्लॉट्स के साथ करना है । क्या आपके पास अधिक विशिष्ट प्रश्न है?
एस.लॉट

21
@oefe: फ्लाईवेट और __slots__मेमोरी को बचाने के लिए दोनों अनुकूलन तकनीकें हैं। __slots__जब आपके पास कई ऑब्जेक्ट्स के साथ-साथ फ्लाईवेट डिज़ाइन पैटर्न के फायदे दिखाई देते हैं। दोनों एक ही समस्या को हल करते हैं।
jfs

7
क्या स्लॉट का उपयोग करने और मेमोरी की खपत और गति के बारे में फ्लाईवेट का उपयोग करने के बीच एक उपलब्ध तुलना है?
कोंतलाई

8
हालांकि फ्लाईवेट निश्चित रूप से कुछ संदर्भों में उपयोगी है, इस पर विश्वास करें या न करें, "जब मैं एक ज़िलियन ऑब्जेक्ट बनाता हूं तो मैं पायथन में मेमोरी का उपयोग कैसे कम कर सकता हूं" का उत्तर "हमेशा आपके ज़िलियन ऑब्जेक्ट्स के लिए पायथन का उपयोग न करें" है। कभी-कभी __slots__वास्तव में इसका उत्तर होता है, और जैसा कि एवगेनी बताते हैं, इसे एक सरल बाद में जोड़ा जा सकता है (जैसे आप पहले शुद्धता पर ध्यान केंद्रित कर सकते हैं, और फिर प्रदर्शन जोड़ सकते हैं)।
पैट्रिक मौपिन

0

मूल प्रश्न केवल स्मृति के बारे में नहीं सामान्य उपयोग के मामलों के बारे में था। तो यहां यह उल्लेख किया जाना चाहिए कि जब आप बड़ी मात्रा में ऑब्जेक्ट्स को डेटाबेस से या किसी डेटाबेस से पार्स कर रहे हों तो बड़ी मात्रा में ऑब्जेक्ट्स को इंस्टेंट करते समय आपको बेहतर प्रदर्शन भी मिलता है ।

यहां एक लाख प्रविष्टियों के साथ ऑब्जेक्ट ट्री बनाने, स्लॉट्स और बिना स्लॉट्स का उपयोग करने की तुलना है। एक संदर्भ के रूप में भी प्रदर्शन जब पेड़ों के लिए सादे dicts (OSX पर Py2.7.10):

********** RUN 1 **********
1.96036410332 <class 'css_tree_select.element.Element'>
3.02922606468 <class 'css_tree_select.element.ElementNoSlots'>
2.90828204155 dict
********** RUN 2 **********
1.77050495148 <class 'css_tree_select.element.Element'>
3.10655999184 <class 'css_tree_select.element.ElementNoSlots'>
2.84120798111 dict
********** RUN 3 **********
1.84069895744 <class 'css_tree_select.element.Element'>
3.21540498734 <class 'css_tree_select.element.ElementNoSlots'>
2.59615707397 dict
********** RUN 4 **********
1.75041103363 <class 'css_tree_select.element.Element'>
3.17366290092 <class 'css_tree_select.element.ElementNoSlots'>
2.70941114426 dict

परीक्षण कक्षाएं (पहचान, स्लॉट्स से प्राप्त):

class Element(object):
    __slots__ = ['_typ', 'id', 'parent', 'childs']
    def __init__(self, typ, id, parent=None):
        self._typ = typ
        self.id = id
        self.childs = []
        if parent:
            self.parent = parent
            parent.childs.append(self)

class ElementNoSlots(object): (same, w/o slots)

टेस्टकोड, वर्बोज़ मोड:

na, nb, nc = 100, 100, 100
for i in (1, 2, 3, 4):
    print '*' * 10, 'RUN', i, '*' * 10
    # tree with slot and no slot:
    for cls in Element, ElementNoSlots:
        t1 = time.time()
        root = cls('root', 'root')
        for i in xrange(na):
            ela = cls(typ='a', id=i, parent=root)
            for j in xrange(nb):
                elb = cls(typ='b', id=(i, j), parent=ela)
                for k in xrange(nc):
                    elc = cls(typ='c', id=(i, j, k), parent=elb)
        to =  time.time() - t1
        print to, cls
        del root

    # ref: tree with dicts only:
    t1 = time.time()
    droot = {'childs': []}
    for i in xrange(na):
        ela =  {'typ': 'a', id: i, 'childs': []}
        droot['childs'].append(ela)
        for j in xrange(nb):
            elb =  {'typ': 'b', id: (i, j), 'childs': []}
            ela['childs'].append(elb)
            for k in xrange(nc):
                elc =  {'typ': 'c', id: (i, j, k), 'childs': []}
                elb['childs'].append(elc)
    td = time.time() - t1
    print td, 'dict'
    del droot
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.