2017-11-01 8 views
0

すべてのPythonオブジェクトは、いくつかのフィールドを持つC構造体として実装されています。参照カウントとオブジェクトの型へのポインタを含む16バイトのheaderは、常にこの構造体に存在します。これは少なくとも私の質問が制限されている64bitのCPython 3.xの場合です。CPythonオブジェクトの基礎となるC構造体表現の出力

私は、学問目的で楽しんで、渡されたオブジェクトobjのこの基礎となるstructをプリントアウトする関数print_object(obj)を探しています。

最も単純なPythonオブジェクトはおそらくfloatで、これは前述のヘッダーに追加されたC doubleです。このような単純なケースでは、私は​​とstructモジュール使用して自分自身のように関数を記述することができました:本質的には

import collections, ctypes, struct, sys 

header_fields = ['refcount', 'typeptr'] 
Float = collections.namedtuple('Float', header_fields + ['value']) 

def print_object(obj): 
    ptr = id(obj) 
    size = sys.getsizeof(obj) 
    byterep = ctypes.string_at(ptr, size) 
    header = struct.unpack('qq', byterep[:16]) 
    if isinstance(obj, float): 
     obj_struct = Float(*header, *struct.unpack('d', byterep[16:])) 
    elif isinstance(obj, int): 
     ... 
    print(obj_struct) 

# Try it out 
a = 1.23 
print_object(a) 
print('The typeptr should be equal to', id(float)) 
print('\nNow the refcount should have increased by 1:') 
b = a 
print_object(a) 

を、この関数は、オブジェクトの基本的なメモリを読み取り、C structなどのコピーを作成しますPython namedtupleは、Python自体を効果的に再表現しています。コードはPython 3.5以降で動作するはずです。
フロート(参照カウント=を:それは

フロート(参照カウント= 5、typeptr = 140429307606720、値= 1.23)
typeptrすぐ参照カウントは1だけ増加しているべきである140429307606720

に等しくなければならない印刷します6、typeptr = 140429307606720、値= 1.23)

上記print_object関数はfloatのための素晴らしい働き、同じ方法は、(I仮定?)他のすべてのタイプに拡張することができます。そこにあるライブラリ(あるいはおそらくPythonのstadardライブラリ)にもこのような機能が含まれていますか?

答えて

0

これを自動的に実行しようとすると、Python型のレイアウトを取得する一般的な方法がないという問題があります。ヘック、構造がどれほど大きいかを伝える一般的な方法さえありません。また、classステートメントで作成された型は、ほとんどが構造体のように機能しますが、そのインスタンスにはstructを使用していません。

あなたが使用したいタイプの構造体定義を自分で提供する必要があります。また、特に奇妙な表現を持つintstrのようなタイプのカスタム処理が必要です。

+0

さて、カスタムメイドの 'class'を無視しましょう。 'struct'のサイズに関しては、' sys.getsizeof(obj) 'が提供するものとまったく同じではありませんか? –

+0

@jmd_dk:いいえ。これには、オブジェクトに属していて実際に構造体の一部ではない他のメモリ(リストのバッキングバッファなど)が含まれます。 – user2357112