2012-07-02 4 views
7

मैं पाइथन में दो अलग-अलग वर्गों के बीच आकार अंतर को सटीक/निश्चित रूप से खोजने का प्रयास कर रहा हूं। वे दोनों नई शैली कक्षाएं हैं, जिनके पास स्लॉट परिभाषित नहीं है। मैंने अपने आकार के अंतर को निर्धारित करने के लिए कई परीक्षणों की कोशिश की है, लेकिन वे हमेशा स्मृति उपयोग में समान होने लगते हैं।पाइथन में सटीक रूप से ऑब्जेक्ट आकार का आकलन करें - Sys.GetSize अगर काम नहीं कर रहा

अब तक मैंने कोई सकारात्मक नतीजे के साथ sys.GetSizeOf (obj) और हेपी के ढेर() फ़ंक्शन का प्रयास किया है। टेस्ट कोड के नीचे है:

import sys 
from guppy import hpy 

class test3(object): 
    def __init__(self): 
     self.one = 1 
     self.two = "two variable" 

class test4(object): 
    __slots__ = ('one', 'two') 
    def __init__(self): 
     self.one = 1 
     self.two = "two variable" 

test3_obj = test3() 
print "Sizeof test3_obj", sys.getsizeof(test3_obj) 

test4_obj = test4() 
print "Sizeof test4_obj", sys.getsizeof(test4_obj) 

arr_test3 = [] 
arr_test4 = [] 

for i in range(3000): 
    arr_test3.append(test3()) 
    arr_test4.append(test4()) 

h = hpy() 
print h.heap() 

आउटपुट:

Sizeof test3_obj 32 
Sizeof test4_obj 32 

Partition of a set of 34717 objects. Total size = 2589028 bytes. 
Index Count %  Size % Cumulative % Kind (class/dict of class) 
    0 11896 34 765040 30 765040 30 str 
    1 3001 9 420140 16 1185180 46 dict of __main__.test3 
    2 5573 16 225240 9 1410420 54 tuple 
    3 348 1 167376 6 1577796 61 dict (no owner) 
    4 1567 5 106556 4 1684352 65 types.CodeType 
    5  68 0 105136 4 1789488 69 dict of module 
    6 183 1 97428 4 1886916 73 dict of type 
    7 3001 9 96032 4 1982948 77 __main__.test3 
    8 3001 9 96032 4 2078980 80 __main__.test4 
    9 203 1 90360 3 2169340 84 type 
<99 more rows. Type e.g. '_.more' to view.> 

यह अजगर 2.6.0 के साथ सभी है। मैं भी व्यक्तिगत sizeofs संक्षेप द्वारा आकार निर्धारित करने की कोशिश करना वर्ग के sizeof तरीकों को ओवरराइड करने का प्रयास किया, लेकिन वह किसी भी अलग परिणाम नहीं किया:

sizeof विधि के साथ
class test4(object): 
    __slots__ = ('one', 'two') 
    def __init__(self): 
     self.one = 1 
     self.two = "two variable" 
    def __sizeof__(self): 
     return super(test4, self).__sizeof__() + self.one.__sizeof__() + self.two.__sizeof__() 

परिणाम अधिरोहित:

Sizeof test3_obj 80 
Sizeof test4_obj 80 

उत्तर

4

sys.getsizeof एक नंबर जो और अधिक विशिष्ट और कम उपयोगी से लोगों को लगता है है देता है। वास्तव में, यदि आप गुणों की संख्या छह तक बढ़ाते हैं, तो आपका test3_obj 32 पर रहता है, लेकिन test4_obj 48 बाइट्स तक कूदता है। ऐसा इसलिए होता है क्योंकि होटिज़ोफ टाइप को कार्यान्वित करने वाले पायओब्जेक्ट संरचना के आकार को वापस कर रहा है, जो test3_obj में गुणों को धारण करने वाले निर्देश शामिल नहीं है, लेकिन test4_obj के लिए, गुण एक dictOC में संग्रहीत नहीं होते हैं, इसलिए वे स्लॉट में संग्रहीत होते हैं, इसलिए वे आकार में के लिए जिम्मेदार हैं।

लेकिन __slots__ के साथ परिभाषित एक वर्ग बिना कक्षा के कम स्मृति लेता है, ठीक है क्योंकि गुणों को पकड़ने के लिए कोई निर्देश नहीं है।

__sizeof__ ओवरराइड क्यों करें? आप वास्तव में क्या करने की कोशिश कर रहे हैं?

+0

आकार का ओवरराइड यह देखने के लिए था कि शायद बिल्टिन आकार विधि विधि चर के आकार को सही ढंग से माप नहीं रही थी। –

+0

तो आप इस तरह के सरल-आइस ऑब्जेक्ट्स के बीच आकार अंतर निर्धारित करने का सबसे अच्छा तरीका क्या सुझाव देंगे? –

+0

यह निर्भर करता है कि आप आकार को क्यों जानना चाहते हैं। आप कौनसी समस्याएं हल करने की कोशिश कर रहे हैं? –

0

पहले कई ऑब्जेक्ट्स के बिना अपने ओएस मेमोरी मैनेजर में पायटन प्रक्रिया के आकार की जांच करें।

दूसरा एक प्रकार की कई वस्तुएं बनाते हैं और आकार को फिर से जांचते हैं।

तीसरा दूसरी तरह की कई वस्तुएं बनाते हैं और आकार की जांच करते हैं।

इसे दो बार दोहराएं और यदि प्रत्येक चरण के आकार उसी के बारे में रहते हैं तो आपको कुछ तुलनीय मिल गया है।

+0

मुझे उत्सुकता है कि यह किस प्रकार की सटीकता मुझे प्राप्त करेगी? इसके अलावा ... मुझे यह कई बार चलाने के लिए एक कुशल तरीका चाहिए, और फिर इसे औसत करने के लिए। –

0

आप स्मृति में अपनी वस्तुओं के आकार प्राप्त करने के लिए एक अलग कार्यान्वयन का उपयोग करना चाहें:

>>> import sys, array 
>>> sizeof = lambda obj: sum(map(sys.getsizeof, explore(obj, set()))) 
>>> def explore(obj, memo): 
    loc = id(obj) 
    if loc not in memo: 
     memo.add(loc) 
     yield obj 
     if isinstance(obj, memoryview): 
      yield from explore(obj.obj, memo) 
     elif not isinstance(obj, (range, str, bytes, bytearray, array.array)): 
      # Handle instances with slots. 
      try: 
       slots = obj.__slots__ 
      except AttributeError: 
       pass 
      else: 
       for name in slots: 
        try: 
         attr = getattr(obj, name) 
        except AttributeError: 
         pass 
        else: 
         yield from explore(attr, memo) 
      # Handle instances with dict. 
      try: 
       attrs = obj.__dict__ 
      except AttributeError: 
       pass 
      else: 
       yield from explore(attrs, memo) 
      # Handle dicts or iterables. 
      for name in 'keys', 'values', '__iter__': 
       try: 
        attr = getattr(obj, name) 
       except AttributeError: 
        pass 
       else: 
        for item in attr(): 
         yield from explore(item, memo) 


>>> class Test1: 
    def __init__(self): 
     self.one = 1 
     self.two = 'two variable' 


>>> class Test2: 
    __slots__ = 'one', 'two' 
    def __init__(self): 
     self.one = 1 
     self.two = 'two variable' 


>>> print('sizeof(Test1()) ==', sizeof(Test1())) 
sizeof(Test1()) == 361 
>>> print('sizeof(Test2()) ==', sizeof(Test2())) 
sizeof(Test2()) == 145 
>>> array_test1, array_test2 = [], [] 
>>> for _ in range(3000): 
    array_test1.append(Test1()) 
    array_test2.append(Test2()) 


>>> print('sizeof(array_test1) ==', sizeof(array_test1)) 
sizeof(array_test1) == 530929 
>>> print('sizeof(array_test2) ==', sizeof(array_test2)) 
sizeof(array_test2) == 194825 
>>> 

बस सुनिश्चित करें कि आप अगर आप एक जवाब वापस चाहते हैं इस कोड में कोई भी अनंत iterators नहीं देते हैं।

+0

"से उपज" क्या वह पायथन 3-विशिष्ट वाक्यविन्यास नहीं है? –

+0

हां, जब शेष कोड '2to3.py' के माध्यम से चलाया जा सकता है। जहां से 'उपज' उपलब्ध नहीं है, वहां पोर्टिंग करना काफी आसान होना चाहिए। –

+0

str को अपने एक-चार सबस्ट्रिंग आकारों को देखने के लिए पुनरावृत्त नहीं किया जाना चाहिए, मैंने एक संपादन का प्रस्ताव दिया जो इसे ध्यान में रखता है। – Adirio

0

मैं एक समान समस्या में भाग गया और गंदा काम करने के लिए अपना खुद का सहायक लिखना समाप्त कर दिया। इसे देखें here

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