我想将一个 freezeset 放入其自身中并将一个元组放入其自身中。
看起来很容易。通过编写一个简单的 C++ 扩展,我能够输出以下内容:
frozenset({frozenset(...)})
((...),)
Run Code Online (Sandbox Code Playgroud)
...意味着该对象在其自身内部
是否可以仅使用 python 及其标准库来执行相同的操作?
小智 5
我找到了另一种相对简单的方法来做到这一点,至少对于 a 来说tuple,使用marshal对象序列化模块。
如果您并不真正关心“如何”,那么这里有一个 TL;DR 单行代码(在 Python 3.11.3 上),它返回一个包含自身的元组:
\n__import__(\'marshal\').loads(b\'\\xa9\\x01\\x72\\x00\\x00\\x00\\x00\')\nRun Code Online (Sandbox Code Playgroud)\n如果您确实关心“如何”,那么该方法的总体主旨是:
\ntuple的序列化方式与其他容器类型(例如list.marshal序列化一个自包含列表,例如[[...]]。[[...]]使其引用 a tuple,然后反序列化。无需再费周折...
\n我运行了这段代码,看看如何marshal序列化一些基本的内置容器类型:
import marshal\n\nL = [1, 2, 3] # a list\nS = {1, 2, 3} # a set\nT = (1, 2, 3) # a tuple\n\ndef show_serial(x): print(x, \'=>\', marshal.dumps(x).hex(\' \'))\nfor x in (L, S, T): show_serial(x)\nRun Code Online (Sandbox Code Playgroud)\n输出:
\n[1, 2, 3] => db 03 00 00 00 e9 01 00 00 00 e9 02 00 00 00 e9 03 00 00 00\n{1, 2, 3} => bc 03 00 00 00 e9 01 00 00 00 e9 02 00 00 00 e9 03 00 00 00\n(1, 2, 3) => a9 03 e9 01 00 00 00 e9 02 00 00 00 e9 03 00 00 00\nRun Code Online (Sandbox Code Playgroud)\n输出的间隔稍有不同,以便排列整齐:
\n[1, 2, 3] => db 03 00 00 00 e9 01 00 00 00 e9 02 00 00 00 e9 03 00 00 00\n{1, 2, 3} => bc 03 00 00 00 e9 01 00 00 00 e9 02 00 00 00 e9 03 00 00 00\n(1, 2, 3) => a9 03 e9 01 00 00 00 e9 02 00 00 00 e9 03 00 00 00\nRun Code Online (Sandbox Code Playgroud)\nlist和 the的字节set均相同。这告诉我第一个字节表示序列化对象的类型。list和 the sethave 03 00 00 00/ the tuplehas just 03。这些字节表示容器对象的长度。至于为什么tuple它的长度只需要 1 个字节......我猜这是因为短元组(例如 )(x,y)非常(r,g,b)常见并且这节省了空间。int(1),即、int(2)和int(3)。e9表示一个(小)整数,每个 5 字节块的剩余 4 个字节是该整数的小端值。制作一个独立的列表,并将其序列化!
\nL = []; L.append(L); show_serial(L) # a self-containing list\nRun Code Online (Sandbox Code Playgroud)\n输出:
\n[[...]] => db 01 00 00 00 72 00 00 00 00\nRun Code Online (Sandbox Code Playgroud)\n我能理解这个字节字符串吗?
\ntype(L) is list,所以第一个字节是db- \xe2\x9c\x93len(L) == 1,所以接下来的 4 个字节是小尾数 1,01 00 00 00- \xe2\x9c\x9372 00 00 00 00必须是自引用容器的特殊“this object”指示符。您还可以通过其他几种方式检查这一点:L = [1]; L.append(L); show_serial(L) # a list containing `1` and itself\n# output: [1, [...]] => db 02 00 00 00 e9 01 00 00 00 72 00 00 00 00\n\nL = 2*[None]; L[0] = L[1] = L; show_serial(L) # a list containing itself twice\n# output: [[...], [...]] => db 02 00 00 00 72 00 00 00 00 72 00 00 00 00\nRun Code Online (Sandbox Code Playgroud)\n现在我有了构建字节字符串所需的信息,它将反序列化为自包含的tuple:
类型:我想要一个tuple,所以第一个字节是a9。
length:它应该包含 1 个元素(即它本身)。与 a 不同list,smalltuple只需要一个字节来序列化其长度。所以下一个字节是01。
content:唯一的元素是容器本身。所以接下来的 5 个字节是72 00 00 00 00.
b = bytes.fromhex(\'a9 01 72 00 00 00 00\')\nT = marshal.loads(b)\nprint(T)
\n瞧\xc3\xa0!T是一个tuple包含自身的现在!
((...),)\nRun Code Online (Sandbox Code Playgroud)\npickleto 序列化而不是 吗marshal?看起来不像——pickle可以处理list包含自身的 a,但它不知道如何处理tuple具有相同功能的 a。RecursionError当我尝试腌制之前创建的元组时,我得到了:
import pickle\npickle.dumps(T)\n\nTraceback (most recent call last):\n File "selfref.py", line 49, in <module>\n pickle.dumps(T)\nRecursionError: maximum recursion depth exceeded while pickling an object\nRun Code Online (Sandbox Code Playgroud)\n我也看不到任何可以使用pickle操作码手动组合字节字符串然后反序列化的方法。当它创建 a 时list,pickle有一个APPEND操作码可以使用...但是当它创建 a 时tuple,它首先将 a 的所有内容推tuple入堆栈,然后是TUPLE操作码。那么那些内容怎么可能是tuple还不存在的呢?也许有一种我没有看到的解决方法 - 如果您知道,请发表评论并让我知道!
frozenset吗?不幸的是,这似乎也不起作用。A序列化与 a或 afrozenset相同,只是第一个字节代替/ of 。但是当我尝试反序列化看起来应该是正确的字节码时,会引发一个问题......listsetbedbbcmarshal.loadsValueError
b = bytes.fromhex(\'be 01 00 00 00 72 00 00 00 00\')\nF = marshal.loads(b)\n\nTraceback (most recent call last):\n File "C:/Users/ryant/OneDrive/py/self-referencing-tuple.py", line 43, in <module>\n F = marshal.loads(b)\nValueError: bad marshal data (invalid reference)\nRun Code Online (Sandbox Code Playgroud)\n可能有一些我不知道为什么这似乎不起作用的原因,而对于它来说tuple它工作得很好 - 如果您知道的话请发表评论!同样,我有兴趣知道是否可以使用ctypes@SuperStormer 的答案中的方法来创建一个frozenset包含自身的方法。
tuple那么其他包含自身的对象又如何呢?您可以采用此技术来创建tuple包含更复杂模式的对象 - 但还有一些细微差别需要处理。具体来说,看起来db/a9并不总是/marshal的字节码...当 a / a包含在另一个(不同的)/中时,例如,字节码通常是/ 。listtuplelisttuplelisttuple5b29
我不完全确定它们出现的不同代码和环境是什么,根据文档,“格式的详细信息是故意未记录的;它可能会在 Python 版本之间发生变化(尽管很少这样做)。 ”
\n不管它的价值如何——这里有一些我想出的一些黑客函数,它们似乎在将list<->转换tuple为嵌套序列类型(包括包含自身的序列类型)方面效果很好marshal:
def tupleify(iterable=(), /):\n \'\'\' Converts nested lists to nested tuples \'\'\'\n Lb, Tb = iter(marshal.dumps(iterable)), list()\n for byte in Lb:\n if byte in (0xdb, 0x5b):\n length = list(map(next, 4*[Lb]))\n if any(length[1:]):\n Tb += [byte - 0x33] + length\n else:\n Tb += [byte - 0x32] + length[:1]\n else:\n Tb.append(byte)\n return marshal.loads(bytes(Tb))\n\ndef listify(iterable=(), /):\n \'\'\' Converts nested tuples to nested lists \'\'\'\n Tb, Lb = iter(marshal.dumps(iterable)), list()\n for byte in Tb:\n if byte in (0xa9, 0x29):\n Lb += [byte + 0x32, next(Tb), 0, 0, 0]\n elif byte in (0xa8, 0x28):\n Lb.append(byte + 0x33)\n else:\n Lb.append(byte)\n return marshal.loads(bytes(Lb))\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
191 次 |
| 最近记录: |