たとえばnamedtupleでこれと同じことを行うことは可能ですか?
「同じ」が何を意味するかによって異なります。namedtuple
同じフィールドを持つタイプを簡単に作成できます。
S2 = collections.namedtuple('S2', ['A2', 'B2', 'C2'])
S1 = collections.namedtuple('S1', ['A', 'B', 'C'])
ただし、それらは明らかに同じ型ではなく、同じ動作をしません。
まず、これらのフィールドは通常の Python 属性 (および通常のtuple
メンバー) であり、静的な型を持たないことを意味します。任意の型の値を保持できます。
したがって、これを行うことができます:
s2 = S2([ctypes.c_uint16(i) for i in range(10)],
[ctypes.c_uint32(i) for i in range(10)],
[ctypes.c_uint32(i) for i in range(10)])
s1 = S1(ctypes.c_uint16(1), ctypes.c_uint32(2), s2)
しかし、これを行うこともできます:
s2 = S2('a', 'b', 'c')
s1 = S1('d', 'e', s2)
… あるいは:
s1 = S1('d', 'e', 'f')
また、最初の例でさえ、実際には配列ではなくlist
10 個の値の s を作成したことに注意してください。それが必要な場合は、明示的にキャストする必要があります。ctypes
ctypes
第二に、namedtuple
s は s の拡張tuple
です。つまり、それらは不変であるため、これを行うことはできません。
s1.C = s2
そして最も重要なのは、 aを anamedtuple
として使用できないことctypes.Structure
です。これを C 関数に渡すことはできませんstruct.pack
。特定のバイナリ形式でシリアル化したい場合は、手動でロジック (たとえば、 の周り)を作成する必要があります。
リストはnamedtupleでどのように処理されますか?
前述のように、 a のメンバーはnamedtuple
静的に型指定されておらず、任意の型の値を保持できます。したがって、通常のクラス インスタンス、グローバル変数などと同じように処理tuple
さlist
れlist
ますlist
。
はい、その stuct.pack が必要です。しかし、s1の最後の値がs2構造への参照であることをどのように指摘すべきかわかりません。
namedtuple
横から見ると、上記の例のようにS2
、 の値としてインスタンスを使用するだけS1.C
です。繰り返しますが、a の項目/属性は、namedtuple
他の属性/変数/その他とまったく同じです。Python では、オブジェクトへの参照を保持する名前だけです。そのため、参照する同じオブジェクトへの別の参照にs1 = S1(1, 2, s2)
の 3 番目の項目を作成します。s1
s2
struct
データをシリアル化する方法については、struct
モジュールには埋め込みオブジェクトに直接委任する方法がありません。しかし、 の出力pack
は単なるbytes
(Python 2.x ではstr
) オブジェクトであるため、通常の文字列操作でこれを行うことができます。
# version 1
s2_struct = struct.Struct('!HII')
s1_header = struct.Struct('!HI')
def pack_s2(s2):
return s2_struct.pack(s2.A2, s2.B2, s2.C2)
def unpack_s2(s2):
return S2._make(s2_struct.unpack(s2))
def pack_s1(s1):
return s1_header.pack(s1.A, s1.B) + pack_s2(s1.C)
def unpack_S1(s1):
offset = len(s1_header)
a, b = s1_header.unpack(s1[:offset])
c = unpack_s2(s1[offset:])
return S1._make(a, b, c)
(個人的にはS2(*struct.unpack
ではなくを使用S2._make
しますが、ドキュメントでは後者を繰り返し使用しているため、意図した方法である必要があると思います…)
または、フォーマット文字列を手動でフラット化することもできます:
s2_struct = struct.Struct('!HII')
s1_struct = struct.Struct('!HIHII')
def pack_s2(s2):
return s2_struct.pack(s2.A2, s2.B2, s2.C2)
def pack_s1(s1):
return s1_struct.pack(s1.A, s1.B, s1.C.A2, s1.C.B2, s1.C.C2)
def unpack_s2(s2):
return S2._make(s2_struct.unpack(s2))
def unpack_S1(s1):
a, b, a2, b2, c2 = s1_struct.unpack(s1)
c = S2(a2, b2, c2)
return S1(a, b, c)
2 番目のバージョンの方が読みやすいと思いますが、間違いを犯しやすく、Python レベルではなくバイナリ レベルでオブジェクトを作成することを考える必要があるため、2 つの悪のうち小さい方を選択してください。