簡體   English   中英

為什么SimpleNamespace的大小與空類的大小不同?

[英]Why does SimpleNamespace have a different size than that of an empty class?

考慮以下:

In [1]: import types

In [2]: class A:
    ...:     pass
    ...:

In [3]: a1 = A()

In [4]: a1.a, a1.b, a1.c = 1, 2, 3

In [5]: a2 = types.SimpleNamespace(a=1,b=2,c=3)

In [6]: sys.getsizeof(a1)
Out[6]: 56

In [7]: sys.getsizeof(a2)
Out[7]: 48

這種尺寸差異來自哪里? 看着:

In [10]: types.__file__
Out[10]: '/Users/juan/anaconda3/lib/python3.5/types.py'

我發現:

import sys

# Iterators in Python aren't a matter of type but of protocol.  A large
# and changing number of builtin types implement *some* flavor of
# iterator.  Don't check the type!  Use hasattr to check for both
# "__iter__" and "__next__" attributes instead.

def _f(): pass
FunctionType = type(_f)
LambdaType = type(lambda: None)         # Same as FunctionType
CodeType = type(_f.__code__)
MappingProxyType = type(type.__dict__)
SimpleNamespace = type(sys.implementation)

好吧,這里什么都沒有:

>>> import sys
>>> sys.implementation
namespace(cache_tag='cpython-35', hexversion=50660080, name='cpython', version=sys.version_info(major=3, minor=5, micro=2, releaselevel='final', serial=0))
>>> type(sys.implementation)
<class 'types.SimpleNamespace'>

我好像在追逐自己的尾巴。

我能夠找到這個相關的問題 ,但沒有回答我的特定查詢。

我在64位系統上使用CPython 3.5。 對於某些錯誤的引用,這8個字節似乎是正確的大小,我無法指出。

請考慮以下具有不同大小的類:

class A_dict:
    pass

class A_slot_0:
    __slots__ = []

class A_slot_1:
    __slots__ = ["a"]

class A_slot_2:
    __slots__ = ["a", "b"]

其中每個都有不同的基本內存占用:

>>> [cls.__basicsize__ for cls in [A_dict, A_slot_0, A_slot_1, A_slot_2]]
>>> [32, 16, 24, 32]

為什么? type_new的源代碼中(在typeobject.c ),它負責創建底層類型並計算實例的基本大小,我們看到tp_basicsize計算如下:

  • 底層類型的tp_basicsizeobject ... 16字節);
  • 每個插槽的另一個sizeof(PyObject *) ;
  • 如果需要__dict__則為sizeof(PyObject *) ;
  • 如果定義了__weakref__則為sizeof(PyObject *) ;

A_dict這樣的普通類將定義__dict____weakref__ ,而具有插槽的類默認沒有__weakref__ 因此,普通A_dict的大小是32個字節。 您可以認為它實際上由PyObject_HEAD和兩個指針組成。

現在,考慮一個SimpleNamespace ,它在namespaceobject.c定義。 這里的類型很簡單:

typedef struct {
    PyObject_HEAD
    PyObject *ns_dict;
} _PyNamespaceObject;

並且tp_basicsize被定義為sizeof(_PyNamespaceObject) ,使得它比普通對象大一個指針,因而是24個字節。

注意:

這里的區別實際上是A_dict提供了對弱引用的支持,而types.SimpleNamespace則沒有。

>>> weakref.ref(types.SimpleNamespace())
TypeError: cannot create weak reference to 'types.SimpleNamespace' object

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM