1

だから私は2つの単純なctypes構造体を持っています

class S2 (ctypes.Structure):
    _fields_ = [
    ('A2',     ctypes.c_uint16*10),
    ('B2',     ctypes.c_uint32*10),
    ('C2',     ctypes.c_uint32*10) ]


class S1 (ctypes.Structure):
    _fields_ = [
    ('A',     ctypes.c_uint16),
    ('B',     ctypes.c_uint32),
    ('C',     S2) ]

たとえばnamedtupleでこれと同じことを行うことは可能ですか? リストはnamedtupleでどのように処理されますか?

編集:

struc.pack の使用法

test_data = '0100000002000000' + 10*'01' + 10*'01' + 10*'01'

S2 = collections.namedtuple('S2', ['A2', 'B2', 'C2'])
S1 = collections.namedtuple('S1', ['A', 'B', 'REF_to_S2'])

Data2 = S2._make(struct.unpack('10p10p10p', binascii.unhexlify(test_data[16:])))
##this is not working, because there must be 3 args..
Data1 = S1._make(struct.unpack('ii', binascii.unhexlify(test_data[0:16])))

最後に、データを読み取り可能な形式で印刷したい(キーと値のペアが表示されている)。しかし、今では、2 つの異なる名前付きタプルを使用してそのアンパック操作をどのように処理すればよいかわかりません...?

この unpack.struct 操作は、値の型の問題を処理しますよね?

4

1 に答える 1

4

たとえば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')

また、最初の例でさえ、実際には配列ではなくlist10 個の値の s を作成したことに注意してください。それが必要な場合は、明示的にキャストする必要があります。ctypesctypes


第二に、namedtuples は s の拡張tupleです。つまり、それらは不変であるため、これを行うことはできません。

s1.C = s2

そして最も重要なのは、 aを anamedtupleとして使用できないことctypes.Structureです。これを C 関数に渡すことはできませんstruct.pack。特定のバイナリ形式でシリアル化したい場合は、手動でロジック (たとえば、 の周り)を作成する必要があります。


リストはnamedtupleでどのように処理されますか?

前述のように、 a のメンバーはnamedtuple静的に型指定されておらず、任意の型の値を保持できます。したがって、通常のクラス インスタンス、グローバル変数などと同じように処理tuplelistlistますlist


はい、その stuct.pack が必要です。しかし、s1の最後の値がs2構造への参照であることをどのように指摘すべきかわかりません。

namedtuple横から見ると、上記の例のようにS2、 の値としてインスタンスを使用するだけS1.Cです。繰り返しますが、a の項目/属性は、namedtuple他の属性/変数/その他とまったく同じです。Python では、オブジェクトへの参照を保持する名前だけです。そのため、参照する同じオブジェクトへの別の参照にs1 = S1(1, 2, s2)の 3 番目の項目を作成します。s1s2

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 つの悪のうち小さい方を選択してください。

于 2013-04-26T19:16:39.907 に答える