web-dev-qa-db-ja.com

False値(0)がTrue(1)よりバイト単位で小さいのはなぜですか?

sysgetsizeof()をいじってみたところ、False(または_0_)はTrue(または_1_)。何故ですか?

_import sys

print("Zero: " + str(sys.getsizeof(0)))
print("One: " + str(sys.getsizeof(1)))
print("False: " + str(sys.getsizeof(False)))
print("True: " + str(sys.getsizeof(True)))

# Prints:
# Zero: 24
# One: 28
# False: 24
# True: 28
_

実際、他の数値(複数の数字で構成されるものもある)は28バイトです。

_for n in range(0, 12):
  print(str(n) + ": " + str(sys.getsizeof(n)))

# Prints:
# 0: 24
# 1: 28
# 2: 28
# 3: 28
# 4: 28
# 5: 28
# 6: 28
# 7: 28
# 8: 28
# 9: 28
# 10: 28
# 11: 28
_

さらに:sys.getsizeof(999999999)も28バイトです!ただし、sys.getsizeof(9999999999)は32です。

どうしたの?ブール値TrueFalseがそれぞれ_0_と_1_に内部的に変換されると思いますが、なぜ他の小さい整数とサイズがゼロでないのですか?

副次的な質問:これは、Python(3)がこれらの項目を表す方法に固有ですか、それともOSで数字がどのように表示されるか一般的にですか?

30
Bram Vanroy

Python intの値は任意のサイズであることを忘れないでください。それはどのように機能しますか?

まあ、CPythonでは1 intは、4バイトのチャンクの配列を持つ_PyLong_Object_で表されます2、それぞれ30ビットを保持 数の価値。

  • _0_はチャンクをまったく取りません。
  • _1_-_(1<<30)-1_は1つのチャンクを取ります。
  • _1<<30_-_(1<<60)-1_は2つのチャンクを取ります。

等々。

これは少し単純化されすぎています。詳細については、ソースの _longintrepr.h_ を参照してください。


Python 2には、intlongの2つの型があります。 intは、C 32ビット符号付き整数で表されます4 チャンクの配列ではなく、ヘッダーに直接埋め込まれます。 longはPython 3 intに似ています。

_0L_、_1L_などを使用して同じテストを実行し、long値を明示的に要求すると、Python 3と同じ結果が得られますが、L接尾辞、32ビットに収まるリテラルはintを提供し、大きすぎるリテラルのみがlongsを提供します。5 (つまり、_(1<<31)-1_はintですが、_1<<31_は2チャンクlongです。)


1.別の実装では、これは当てはまらない場合があります。 IIRC、JythonはCPythonとほぼ同じことを行いますが、IronPythonはC#の「bignum」実装を使用します。

2.なぜ32ビットではなく30ビットなのですか?主に、2つの "桁"のビット数が_**_で割り切れると仮定できる場合、powおよび_10_の実装がより簡単で高速になるためです。

3. C "struct hack" を使用します。技術的には、_Py_LongObject_は28バイトですが、_Py_LongObject_を割り当てる人はいません。それらは24、28、32、36などのバイトをmallocしてから_Py_LongObject *_にキャストします。

4.実際、Python intは、混乱を招くだけのCのlongです。したがって、C APIには、_PyInt_FromLong_(longは "32ビットint"を意味する)や_PyLong_FromSize_t_(longは "bignum"を意味する)などの機能が満載です。

5. Python 2.xの初期のバージョンでは、intlongがうまく統合されていませんでしたが、もう心配する必要はありません。

31
abarnert