Python bytearray 是否在 C 表示中使用有符号整数?
Does Python bytearray use signed integers in the C representation?
我在Python中写了a small Cython tool for in-place sorting of structures exposing the buffer protocol。这是一项正在进行的工作;请原谅任何错误。仅供学习。
在我的一组单元测试中,我正在测试跨多种不同类型的缓冲区公开数据结构的就地排序,每种数据结构中都包含多种类型的基础数据。我可以验证它在大多数情况下都按预期工作,但 bytearray
的情况非常特殊。
如果您认为我在下面代码中导入的模块 b
只是在 bytearray
上就地在 Cython 中执行简单的堆排序,那么下面的代码示例显示问题:
In [42]: a #NumPy array
Out[42]: array([ 9, 148, 115, 208, 243, 197], dtype=uint8)
In [43]: byt = bytearray(a)
In [44]: byt
Out[44]: bytearray(b'\t\x94s\xd0\xf3\xc5')
In [45]: list(byt)
Out[45]: [9, 148, 115, 208, 243, 197]
In [46]: byt1 = copy.deepcopy(byt)
In [47]: b.heap_sort(byt1)
In [48]: list(byt1)
Out[48]: [148, 197, 208, 243, 9, 115]
In [49]: list(bytearray(sorted(byt)))
Out[49]: [9, 115, 148, 197, 208, 243]
您可以看到,当使用 sorted
时,为了排序目的,值被迭代并像 Python 整数一样处理,然后放回新的 bytearray
。
但是第 47-48 行的就地排序显示字节被解释为有符号整数,并按其 2 的补码值排序,将数字 >= 128,因为它们是负数,朝向离开了。
我可以通过 运行 在整个 0-255 范围内确认:
In [50]: byt = bytearray(range(0,256))
In [51]: b.heap_sort(byt)
In [52]: list(byt)
Out[52]:
[128,
129,
130,
131,
132,
133,
134,
135,
136,
137,
138,
139,
140,
141,
142,
143,
144,
145,
146,
147,
148,
149,
150,
151,
152,
153,
154,
155,
156,
157,
158,
159,
160,
161,
162,
163,
164,
165,
166,
167,
168,
169,
170,
171,
172,
173,
174,
175,
176,
177,
178,
179,
180,
181,
182,
183,
184,
185,
186,
187,
188,
189,
190,
191,
192,
193,
194,
195,
196,
197,
198,
199,
200,
201,
202,
203,
204,
205,
206,
207,
208,
209,
210,
211,
212,
213,
214,
215,
216,
217,
218,
219,
220,
221,
222,
223,
224,
225,
226,
227,
228,
229,
230,
231,
232,
233,
234,
235,
236,
237,
238,
239,
240,
241,
242,
243,
244,
245,
246,
247,
248,
249,
250,
251,
252,
253,
254,
255,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
91,
92,
93,
94,
95,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
123,
124,
125,
126,
127]
我知道这很难重现。如果需要,您可以使用 Cython 构建链接包,然后 import src.buffersort as b
获得我正在使用的相同排序功能。
我尝试通读 Objects/bytearrayobject.c 中 bytearray
的源代码,但我看到一些对 long
的引用和对 PyInt_FromLong
的一些调用...
这让我怀疑 bytearray
的底层 C 级数据在 C 中表示为带符号的整数,但是从原始字节转换为 Python int
意味着在 Python 中,它在 0 到 255 之间是无符号的。我只能假设这是真的......虽然我不明白为什么 Python 应该将 C long 解释为无符号的,除非这只是 bytearray
的约定,我在代码。但如果是这样,如果字节总是被 Python 视为无符号,为什么 C 端也不会使用无符号整数?
如果为真,就地排序的 "right" 结果应该是什么?因为它们 "just bytes" 两种解释都是有效的,我猜,但本着 Python 的精神,我认为它们应该是一种被认为是标准的方式。
为了匹配 sorted
的输出,在处理 bytearray
时,在 C 端将值转换为 unsigned long
是否足够?
Does Python bytearray use signed integers in the C representation?
它使用 char
s。这些是否被签名取决于编译器。您可以在 Include/bytearrayobject.h
中看到这一点。 Here's the 2.7 version:
/* Object layout */
typedef struct {
PyObject_VAR_HEAD
/* XXX(nnorwitz): should ob_exports be Py_ssize_t? */
int ob_exports; /* how many buffer exports */
Py_ssize_t ob_alloc; /* How many bytes allocated */
char *ob_bytes;
} PyByteArrayObject;
typedef struct {
PyObject_VAR_HEAD
Py_ssize_t ob_alloc; /* How many bytes allocated in ob_bytes */
char *ob_bytes; /* Physical backing buffer */
char *ob_start; /* Logical start inside ob_bytes */
/* XXX(nnorwitz): should ob_exports be Py_ssize_t? */
int ob_exports; /* How many buffer exports */
} PyByteArrayObject;
If true, what should be considered the "right" result of the in-place sort?
A Python bytearray 表示 0 <= elem < 256 范围内的整数序列,无论编译器是否认为 char
是有符号的。您可能应该将其排序为 0 <= elem < 256 范围内的整数序列,而不是作为带符号 char
s.
的序列
To match output of sorted, will it be sufficient on the C side to cast values to unsigned long when dealing with bytearray?
我对 Cython 的了解还不够多,无法说明正确的代码更改是什么。
我在Python中写了a small Cython tool for in-place sorting of structures exposing the buffer protocol。这是一项正在进行的工作;请原谅任何错误。仅供学习。
在我的一组单元测试中,我正在测试跨多种不同类型的缓冲区公开数据结构的就地排序,每种数据结构中都包含多种类型的基础数据。我可以验证它在大多数情况下都按预期工作,但 bytearray
的情况非常特殊。
如果您认为我在下面代码中导入的模块 b
只是在 bytearray
上就地在 Cython 中执行简单的堆排序,那么下面的代码示例显示问题:
In [42]: a #NumPy array
Out[42]: array([ 9, 148, 115, 208, 243, 197], dtype=uint8)
In [43]: byt = bytearray(a)
In [44]: byt
Out[44]: bytearray(b'\t\x94s\xd0\xf3\xc5')
In [45]: list(byt)
Out[45]: [9, 148, 115, 208, 243, 197]
In [46]: byt1 = copy.deepcopy(byt)
In [47]: b.heap_sort(byt1)
In [48]: list(byt1)
Out[48]: [148, 197, 208, 243, 9, 115]
In [49]: list(bytearray(sorted(byt)))
Out[49]: [9, 115, 148, 197, 208, 243]
您可以看到,当使用 sorted
时,为了排序目的,值被迭代并像 Python 整数一样处理,然后放回新的 bytearray
。
但是第 47-48 行的就地排序显示字节被解释为有符号整数,并按其 2 的补码值排序,将数字 >= 128,因为它们是负数,朝向离开了。
我可以通过 运行 在整个 0-255 范围内确认:
In [50]: byt = bytearray(range(0,256))
In [51]: b.heap_sort(byt)
In [52]: list(byt)
Out[52]:
[128,
129,
130,
131,
132,
133,
134,
135,
136,
137,
138,
139,
140,
141,
142,
143,
144,
145,
146,
147,
148,
149,
150,
151,
152,
153,
154,
155,
156,
157,
158,
159,
160,
161,
162,
163,
164,
165,
166,
167,
168,
169,
170,
171,
172,
173,
174,
175,
176,
177,
178,
179,
180,
181,
182,
183,
184,
185,
186,
187,
188,
189,
190,
191,
192,
193,
194,
195,
196,
197,
198,
199,
200,
201,
202,
203,
204,
205,
206,
207,
208,
209,
210,
211,
212,
213,
214,
215,
216,
217,
218,
219,
220,
221,
222,
223,
224,
225,
226,
227,
228,
229,
230,
231,
232,
233,
234,
235,
236,
237,
238,
239,
240,
241,
242,
243,
244,
245,
246,
247,
248,
249,
250,
251,
252,
253,
254,
255,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75,
76,
77,
78,
79,
80,
81,
82,
83,
84,
85,
86,
87,
88,
89,
90,
91,
92,
93,
94,
95,
96,
97,
98,
99,
100,
101,
102,
103,
104,
105,
106,
107,
108,
109,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121,
122,
123,
124,
125,
126,
127]
我知道这很难重现。如果需要,您可以使用 Cython 构建链接包,然后 import src.buffersort as b
获得我正在使用的相同排序功能。
我尝试通读 Objects/bytearrayobject.c 中 bytearray
的源代码,但我看到一些对 long
的引用和对 PyInt_FromLong
的一些调用...
这让我怀疑 bytearray
的底层 C 级数据在 C 中表示为带符号的整数,但是从原始字节转换为 Python int
意味着在 Python 中,它在 0 到 255 之间是无符号的。我只能假设这是真的......虽然我不明白为什么 Python 应该将 C long 解释为无符号的,除非这只是 bytearray
的约定,我在代码。但如果是这样,如果字节总是被 Python 视为无符号,为什么 C 端也不会使用无符号整数?
如果为真,就地排序的 "right" 结果应该是什么?因为它们 "just bytes" 两种解释都是有效的,我猜,但本着 Python 的精神,我认为它们应该是一种被认为是标准的方式。
为了匹配 sorted
的输出,在处理 bytearray
时,在 C 端将值转换为 unsigned long
是否足够?
Does Python bytearray use signed integers in the C representation?
它使用 char
s。这些是否被签名取决于编译器。您可以在 Include/bytearrayobject.h
中看到这一点。 Here's the 2.7 version:
/* Object layout */
typedef struct {
PyObject_VAR_HEAD
/* XXX(nnorwitz): should ob_exports be Py_ssize_t? */
int ob_exports; /* how many buffer exports */
Py_ssize_t ob_alloc; /* How many bytes allocated */
char *ob_bytes;
} PyByteArrayObject;
typedef struct {
PyObject_VAR_HEAD
Py_ssize_t ob_alloc; /* How many bytes allocated in ob_bytes */
char *ob_bytes; /* Physical backing buffer */
char *ob_start; /* Logical start inside ob_bytes */
/* XXX(nnorwitz): should ob_exports be Py_ssize_t? */
int ob_exports; /* How many buffer exports */
} PyByteArrayObject;
If true, what should be considered the "right" result of the in-place sort?
A Python bytearray 表示 0 <= elem < 256 范围内的整数序列,无论编译器是否认为 char
是有符号的。您可能应该将其排序为 0 <= elem < 256 范围内的整数序列,而不是作为带符号 char
s.
To match output of sorted, will it be sufficient on the C side to cast values to unsigned long when dealing with bytearray?
我对 Cython 的了解还不够多,无法说明正确的代码更改是什么。