Reputation: 1673
I want to create ctypes.Structure
-like object from bytes
with Object(bytes_buffer)
-like pattern.
According to https://stackoverflow.com/a/11486058 I use __new__
factory
from ctypes import Structure, c_char, c_uint8
ARRAY_LENGTH = 5
class Person(Structure):
_fields_ = [("name", c_char * ARRAY_LENGTH),
("age", c_uint8)]
def __new__(cls, buf):
return cls.from_buffer_copy(buf)
When calling Structure.from_buffer_copy
it looks like the method doesn't check the \0
character (and it looks like Python-style)
>>> p = Person.from_buffer_copy(b"Piter\x10")
>>> print(p.name, p.age)
... b'Piter' 16
But when calling from_buffer_copy
from Structure.__new__
the method checks \0
character when interpreting c_char * 5
(and it looks like C-style)
>>> p = Person(b"Piter\x10")
Traceback (most recent call last):
File "/home/denis/person.py", line 69, in <module>
p = Person(b"Piter\x10")
ValueError: bytes too long (6, maximum length 5)
But using C-style string works well in both cases:
ARRAY_LENGTH = 6
class Person(Structure):
_fields_ = [("name", c_char * ARRAY_LENGTH),
("age", c_uint8)]
def __new__(cls, buf):
return cls.from_buffer_copy(buf)
>>> p = Person.from_buffer_copy(b"Piter\0\x10")
>>> print(p.name, p.age)
... b'Piter' 16
>>> p = Person(b"Piter\0\x10")
>>> print(p.name, p.age)
... b'Piter' 16
So
Person.from_buffer_copy(b"Piter\x10")
interprets full array length when \0
is not presented.Person(b"Piter\x10")
requires the \0
.I have no idea why it's so. Is it Python feature?
I run code with both Python 2 and Python 3
Python 3.8.5 (default, Sep 4 2020, 07:30:14)
[GCC 7.3.0] on linux
and
Python 2.7.18 (default, Aug 4 2020, 11:16:42)
[GCC 9.3.0] on linux2
(used "Piter\x10"
instead of b"Piter\x10"
)
Upvotes: 2
Views: 383
Reputation: 4279
you've missed the empty __init__
from ctypes import Structure, c_char, c_uint8
ARRAY_LENGTH = 5
class Person(Structure):
_fields_ = [("name", c_char * ARRAY_LENGTH),
("age", c_uint8)]
def __new__(cls, buf):
return cls.from_buffer_copy(buf)
def __init__(*args):
pass
p = Person(b"Piter\x10")
print(p.name)
works just fine
you can read more about __new__ here
Briefly explained, __new__
gets called before __init__
and does what you want it to do, but then __init__
gets called anyway and it doesnt know how to use your input
Upvotes: 1