GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing python.github.io — struct --- تفسیر بایتها بهعنوان دادههای دودویی بستهبندیشده
|
نویسه |
ترتیب بایت |
اندازه |
تراز |
|---|---|---|---|
|
بومی |
بومی |
بومی |
|
بومی |
استاندارد |
هیچ |
|
کوچکاندیان (little-endian) |
استاندارد |
هیچ |
|
بزرگاندیان |
استاندارد |
هیچ |
|
شبکه (= بزرگاندیان) |
استاندارد |
هیچ |
اگر اولین نویسه یکی از اینها نباشد، '@' فرض میشود.
نکته
عدد ۱۰۲۳ (0x3ff در مبنای شانزده) بازنماییهای بایتی زیر را دارد:
03 ff در بزرگاندیان (>)
ff 03 بهصورت کوچکاندیان (little-endian) (<)
مثال پایتون:
>>> import struct >>> struct.pack('>h', 1023) b'\x03\xff' >>> struct.pack('<h', 1023) b'\xff\x03'
ترتیب بایت بومی، بسته به سیستم میزبان، بزرگاندیان (big-endian) یا کوچکاندیان (little-endian) است. برای مثال، Intel x86، AMD64 (x86-64) و Apple M1 کوچکاندیان هستند؛ IBM z و بسیاری از معماریهای قدیمی بزرگاندیان هستند. برای بررسی ترتیب بایت (endianness) سیستم خود از sys.byteorder استفاده کنید.
اندازه و همترازی بومی با استفاده از عبارت sizeof کامپایلر C تعیین میشود. این همیشه با ترتیب بایت بومی ترکیب میشود.
اندازهی استاندارد فقط به نویسهی قالب بستگی دارد؛ جدول موجود در بخش Type Codes را ببینید.
به تفاوت بین '@' و '=' توجه کنید: هر دو از ترتیب بایتهای بومی استفاده میکنند، اما اندازه و همترازی مورد دوم استاندارد شده است.
قالب '!' نمایانگر ترتیب بایتهای شبکه است که مطابق تعریف IETF RFC 1700، همیشه بهصورت بزرگاندیان (big-endian) است.
راهی برای مشخص کردن ترتیب بایت غیربومی (اجبار به جابجایی بایتها) وجود ندارد؛ از انتخاب مناسب '<' یا '>' استفاده کنید.
یادداشتها:
فضای پرکننده (padding) فقط بهصورت خودکار بین اعضای متوالی ساختار اضافه میشود. هیچ فضای پرکنندهای در ابتدا یا انتهای ساختار کدگذاریشده اضافه نمیشود.
هنگام استفاده از اندازه و ترازبندی غیربومی، هیچ پرکنندهای (padding) اضافه نمیشود، برای مثال با '<'، '>'، '=' و '!'.
برای همتراز کردن انتهای یک ساختار با الزام همترازی یک نوع خاص، قالب را با کد آن نوع و تعداد تکرار صفر به پایان ببرید. مثالها را ببینید.
نویسههای قالب معنای زیر را دارند؛ با توجه به نوع آنها، تبدیل بین مقادیر C و پایتون باید بدیهی باشد. ستون «اندازه استاندارد» به اندازهی مقدار بستهبندیشده بر حسب بایت هنگام استفاده از اندازه استاندارد اشاره دارد؛ یعنی زمانی که رشتهی قالب با یکی از '<'، '>'، '!' یا '=' شروع شود. هنگام استفاده از اندازه بومی، اندازهی مقدار بستهبندیشده وابسته به سکو است.
قالب |
نوع C |
نوع پایتون |
اندازه استاندارد |
یادداشتها |
|---|---|---|---|---|
|
بایت پرکننده |
بدون مقدار |
(7) |
|
|
char |
بایتهایی با طول ۱ |
1 |
|
|
signed char |
int |
1 |
(2) |
|
unsigned char |
int |
1 |
(2) |
|
_Bool |
bool |
1 |
(1) |
|
short |
int |
2 |
(2) |
|
unsigned short |
int |
2 |
(2) |
|
int |
int |
4 |
(2) |
|
unsigned int |
int |
4 |
(2) |
|
long |
int |
4 |
(2) |
|
unsigned long |
int |
4 |
(2) |
|
long long |
int |
۸ |
(2) |
|
unsigned long long |
int |
۸ |
(2) |
|
|
int |
(2), (3) |
|
|
|
int |
(2), (3) |
|
|
_Float16 |
float |
2 |
(4), (6) |
|
float |
float |
4 |
(4) |
|
double |
float |
۸ |
(4) |
|
float complex |
complex |
۸ |
(10) |
|
double complex |
complex |
16 |
(10) |
|
char[] |
bytes |
(9) |
|
|
char[] |
bytes |
(8) |
|
|
void* |
int |
(2), (5) |
تغییر یافته در نسخهی 3.3: پشتیبانی از قالبهای 'n' و 'N' اضافه شد.
تغییر یافته در نسخهی 3.6: پشتیبانی از قالب 'e' اضافه شد.
تغییر یافته در نسخهی 3.14: پشتیبانی از قالبهای 'F' و 'D' اضافه شد.
تغییر یافته در نسخهی 3.15: پشتیبانی از قالبهای 'Zf' و 'Zd' اضافه شد. قالبهای 'F' و 'D' منسوخ نرم هستند.
همچنین ببینید
ماژولهای array و ctypes، و همچنین ماژولهای شخص ثالث مانند numpy، از کدهای نوع مشابه، اما کمی متفاوت، استفاده میکنند.
یادداشتها:
کد تبدیل '?' متناظر با نوع _Bool است که از C99 در استانداردهای C تعریف شده است. در حالت استاندارد، این نوع با یک بایت بازنمایی میشود.
هنگام تلاش برای بستهبندی مقداری که عدد صحیح نیست با استفاده از هر یک از کدهای تبدیل مربوط به عدد صحیح، اگر آن مقدار دارای متد __index__() باشد، آن متد برای تبدیل آرگومان به عدد صحیح پیش از بستهبندی فراخوانی میشود.
تغییر یافته در نسخهی 3.2: استفاده از متد __index__() برای غیرصحیحها افزوده شد.
کدهای تبدیل 'n' و 'N' فقط برای اندازه بومی (انتخابشده بهعنوان پیشفرض یا با نویسه ترتیب بایت '@') در دسترس هستند. برای اندازه استاندارد، میتوانید از هر یک از قالبهای دیگر عدد صحیح که مناسب برنامه شماست استفاده کنید.
برای کدهای تبدیل 'f'، 'd' و 'e'، بازنمایی فشرده از قالب binary32، binary64 یا binary16 IEEE 754 (بهترتیب برای 'f'، 'd' یا 'e') استفاده میکند، صرفنظر از قالب ممیز شناور استفادهشده توسط سکو.
نویسهی قالب 'P' فقط برای ترتیب بایت بومی در دسترس است (که بهعنوان پیشفرض یا با نویسهی ترتیب بایت '@' انتخاب میشود). نویسهی ترتیب بایت '=' استفاده از ترتیب کوچکاندیان (little-endian) یا بزرگاندیان (big-endian) را بر اساس سیستم میزبان انتخاب میکند. ماژول struct این را بهعنوان ترتیب بومی تفسیر نمیکند، بنابراین قالب 'P' در دسترس نیست.
نوع binary16 «دقت نصفه» (half precision) در IEEE 754، در بازنگری سال ۲۰۰۸ استاندارد IEEE 754 معرفی شد. این نوع دارای یک بیت علامت، توان ۵ بیتی و دقت ۱۱ بیتی است (با ۱۰ بیت که بهصورت صریح ذخیره میشوند) و میتواند اعدادی بین تقریباً 6.1e-05 و 6.5e+04 را با دقت کامل نمایش دهد. این نوع بهطور گسترده توسط کامپایلرهای C پشتیبانی نمیشود: اگر کامپایلر از پیوست H استاندارد C23 پشتیبانی کند، بهعنوان نوع _Float16 در دسترس است. در یک ماشین معمول، میتوان از unsigned short برای ذخیرهسازی استفاده کرد، اما نه برای عملیات ریاضی. برای اطلاعات بیشتر، صفحهی ویکیپدیا دربارهی قالب ممیز شناور با دقت نصفه را ببینید.
هنگام بستهبندی، 'x' یک بایت NUL درج میکند.
نویسه قالب 'p' یک «رشته پاسکالی» را کدگذاری میکند، یعنی رشتهای کوتاه با طول متغیر که در تعداد ثابتی از بایتها ذخیره میشود و با تعداد (count) مشخص میگردد. نخستین بایت ذخیرهشده، طول رشته یا ۲۵۵ است، هرکدام که کوچکتر باشد. بایتهای رشته در ادامه میآیند. اگر رشته بایت دادهشده به pack() بیش از حد طولانی باشد (طولانیتر از count منهای ۱)، تنها count-1 بایت ابتدایی رشته ذخیره میشود. اگر رشته بایت کوتاهتر از count-1 باشد، با بایتهای null پر میشود تا دقیقاً در مجموع count بایت استفاده شود. توجه داشته باشید که برای unpack()، نویسه قالب 'p' count بایت مصرف میکند، اما شیء bytes برگشتی هرگز نمیتواند بیش از ۲۵۵ بایت داشته باشد. هنگام pack کردن، آرگومانهایی از انواع bytes و bytearray پذیرفته میشوند.
برای نویسهی قالب 's'، تعداد بهعنوان طول رشتهی بایتی تفسیر میشود، نه بهعنوان تعداد تکرار مانند دیگر نویسههای قالب؛ برای مثال، '10s' بهمعنای یک رشتهی ۱۰ بایتی واحد است که به یک رشتهی بایتی پایتون یا از آن نگاشت میشود، در حالی که '10c' بهمعنای ۱۰ المان نویسهای یکبایتی جداگانه (مانند cccccccccc) است که به ۱۰ شیء بایتی متفاوت پایتون یا از آنها نگاشت میشوند. (برای نمایش ملموس این تفاوت، مثالها را ببینید.) اگر تعدادی داده نشود، مقدار پیشفرض ۱ است. در بستهبندی، رشتهی بایتی در صورت لزوم بریده میشود یا با بایتهای تهی پر میشود تا در قالب جای گیرد. در واگشایی، شیء bytes حاصل همیشه دقیقاً دارای تعداد بایت مشخصشده است. بهعنوان یک حالت خاص، '0s' بهمعنای یک رشتهی بایتی خالی واحد است (در حالی که '0c' بهمعنای ۰ نویسه است). هنگام بستهبندی، آرگومانهایی از انواع bytes و bytearray پذیرفته میشوند.
برای کدهای نوع 'Zf' و 'Zd'، بازنمایی بستهبندیشده از قالبهای باینری ۳۲ و باینری ۶۴ استاندارد IEEE 754 برای اجزای عدد مختلط استفاده میکند، صرفنظر از قالب ممیز شناوری که پلتفرم به کار میبرد. توجه داشته باشید که انواع مختلط بهطور پیشفرض و بدون قید و شرط در دسترس هستند، با وجود اینکه انواع مختلط در زبان C یک ویژگی اختیاری محسوب میشوند. همانطور که در استاندارد C11 مشخص شده است، هر نوع مختلط با یک آرایهی دو عنصری C نمایش داده میشود که بهترتیب حاوی قسمتهای حقیقی و موهمی است. نویسههای قالب 'F' و 'D' (بهترتیب برای 'Zf' و 'Zd') برای سازگاری پشتیبانی میشوند.
میتوان پیش از یک نویسه قالب، یک تعداد تکرار صحیح قرار داد. برای مثال، رشته قالب '4h' دقیقاً همان معنای 'hhhh' را دارد.
نویسههای فضای سفید بین قالبها نادیده گرفته میشوند؛ هرچند یک تعداد و قالب آن نباید شامل فضای سفید باشند.
هنگام بستهبندی (packing) یک مقدار x با استفاده از یکی از قالبهای عدد صحیح ('b'، 'B'، 'h'، 'H'، 'i'، 'I'، 'l'، 'L'، 'q'، 'Q')، اگر x خارج از محدوده معتبر برای آن قالب باشد، struct.error پرتاب میشود.
تغییر یافته در نسخهی 3.1: پیشتر، برخی از قالبهای عدد صحیح مقادیر خارج از محدوده را دور میزدند و بهجای struct.error، DeprecationWarning ایجاد میکردند.
برای نویسهی قالب '?'، مقدار بازگشتی یا True است یا False. هنگام بستهبندی، از مقدار درستی شیء آرگومان استفاده میشود. یکی از مقادیر ۰ یا ۱ در نمایش بولی بومی یا استاندارد بستهبندی میشود، و هر مقدار غیرصفر هنگام واگشایی True خواهد بود.
نکته
مثالهای ترتیب بایتهای بومی (native byte order) (که با پیشوند قالب '@' یا فقدان هر نویسهی پیشوند مشخص میشوند) ممکن است با آنچه دستگاه خواننده تولید میکند مطابقت نداشته باشند، زیرا این امر به سکو و کامپایلر بستگی دارد.
بستهبندی و واگشایی اعداد صحیح در سه اندازهی مختلف، با استفاده از ترتیب بایتبزرگ (big endian):
>>> from struct import * >>> pack(">bhl", 1, 2, 3) b'\x01\x00\x02\x00\x00\x00\x03' >>> unpack('>bhl', b'\x01\x00\x02\x00\x00\x00\x03') (1, 2, 3) >>> calcsize('>bhl') 7
تلاش برای بستهبندی یک عدد صحیح که برای فیلد تعریفشده بیش از حد بزرگ است:
>>> pack(">h", 99999) Traceback (most recent call last): File "<stdin>", line 1, in <module> struct.error: 'h' format requires -32768 <= number <= 32767
نمایش تفاوت بین نویسههای قالببندی 's' و 'c':
>>> pack("@ccc", b'1', b'2', b'3') b'123' >>> pack("@3s", b'123') b'123'
میتوان فیلدهای واگشاییشده را با انتساب آنها به متغیرها یا با قرار دادن نتیجه در یک تاپل نامدار (named tuple) نامگذاری کرد:
>>> record = b'raymond \x32\x12\x08\x01\x08' >>> name, serialnum, school, gradelevel = unpack('<10sHHb', record) >>> from collections import namedtuple >>> Student = namedtuple('Student', 'name serialnum school gradelevel') >>> Student._make(unpack('<10sHHb', record)) Student(name=b'raymond ', serialnum=4658, school=264, gradelevel=8)
ترتیب نویسههای قالب ممکن است در حالت بومی بر اندازه تأثیر بگذارد، زیرا پرکننده (padding) ضمنی است. در حالت استاندارد، کاربر مسئول درج هرگونه پرکننده دلخواه است. توجه داشته باشید که در اولین فراخوانی pack در زیر، ۳ بایت NUL پس از '#' بستهبندیشده اضافه شدند تا عدد صحیح بعدی روی مرز ۴ بایتی تراز شود. در این مثال، خروجی روی یک ماشین با ترتیب بایت کمارزش در ابتدا (little endian) تولید شده است:
>>> pack('@ci', b'#', 0x12131415) b'#\x00\x00\x00\x15\x14\x13\x12' >>> pack('@ic', 0x12131415, b'#') b'\x15\x14\x13\x12#' >>> calcsize('@ci') 8 >>> calcsize('@ic') 5
قالب زیر 'llh0l' منجر به افزوده شدن دو بایت پرکننده (pad bytes) در انتها میشود، با فرض تراز بودن نوع long پلتفرم روی مرزهای ۴ بایتی:
>>> pack('@llh0l', 1, 2, 3) b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
دو کاربرد اصلی برای ماژول struct وجود دارند: تبادل داده بین کد پایتون و C در یک برنامه یا برنامهای دیگر که با همان کامپایلر کامپایل شده است (قالبهای بومی)، و تبادل داده بین برنامههایی که از چیدمان دادهی مورد توافق استفاده میکنند (قالبهای استاندارد). بهطور کلی، رشتههای قالب ساختهشده برای این دو حوزه با یکدیگر تفاوت دارند.
هنگام ساخت رشتههای قالب که چیدمانهای بومی را تقلید میکنند، کامپایلر و معماری ماشین ترتیب بایتها و پرکنندهگذاری را تعیین میکنند. در چنین مواردی، باید از نویسهی قالب @ برای مشخص کردن ترتیب بایت بومی و اندازههای داده استفاده شود. بایتهای پرکننده داخلی معمولاً بهطور خودکار درج میشوند. ممکن است در انتهای یک رشته قالب به یک کد پیشساخته با تکرار صفر نیاز باشد تا به مرز بایت صحیح گرد شود و تراز مناسب تکههای متوالی داده فراهم گردد.
این دو مثال ساده را در نظر بگیرید (روی یک ماشین ۶۴بیتی، کوچکاندیان):
>>> calcsize('@lhl') 24 >>> calcsize('@llh') 18
بدون استفاده از پد (padding) اضافی، دادهها در انتهای دومین رشتهی قالب تا یک مرز ۸ بایتی پد نمیشوند. یک کد قالب با تکرار صفر این مشکل را حل میکند:
>>> calcsize('@llh0l') 24
میتوانید از کد قالب 'x' برای مشخص کردن تعداد تکرار استفاده کنید، اما برای قالبهای بومی بهتر است از یک قالب با تکرار صفر مانند '0l' استفاده کنید.
بهطور پیشفرض، از ترتیب بایتها و ترازبندی بومی استفاده میشود، اما بهتر است صریح باشید و از نویسهی پیشوند '@' استفاده کنید.
هنگام تبادل داده فراتر از فرایند خود، مانند شبکه یا ذخیرهسازی، دقیق باشید. ترتیب بایت، اندازه و ترازبندی را دقیقاً مشخص کنید. فرض نکنید که آنها با ترتیب بومی یک ماشین خاص مطابقت دارند. برای مثال، ترتیب بایت شبکه بزرگاندیان (big-endian) است، در حالی که بسیاری از پردازندههای رایج کوچکاندیان (little-endian) هستند. با تعریف صریح این موارد، نیازی نیست کاربر به جزئیات سکویی که کدش روی آن اجرا میشود توجه کند. اولین نویسه معمولاً باید < یا > (یا !) باشد. مسئولیت پر کردن (padding) بر عهدهی برنامهنویس است. نویسهی قالب با تکرار صفر کار نمیکند. در عوض، کاربر باید بهصراحت بایتهای پرکنندهی 'x' را در صورت نیاز اضافه کند. با مرور مثالهای بخش پیشین، داریم:
>>> calcsize('<qh6xq') 24 >>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3) True >>> calcsize('@llh') 18 >>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3) True >>> calcsize('<qqh6x') 24 >>> calcsize('@llh0l') 24 >>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3) True
تضمین نمیشود که نتایج بالا (اجراشده روی یک ماشین ۶۴ بیتی) هنگام اجرا روی ماشینهای مختلف مطابقت داشته باشند. برای مثال، مثالهای زیر روی یک ماشین ۳۲ بیتی اجرا شدهاند:
>>> calcsize('<qqh6x') 24 >>> calcsize('@llh0l') 12 >>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3) False
ماژول struct همچنین نوع زیر را تعریف میکند:
یک شیء Struct جدید برمیگرداند که دادههای دودویی را بر اساس رشته قالب format مینویسد و میخواند. ایجاد یک شیء Struct بهصورت یکبار و فراخوانی متدهای آن کارآمدتر از فراخوانی توابع سطح ماژول با همان قالب است، زیرا رشته قالب تنها یکبار کامپایل میشود.
نکته
نسخههای کامپایلشدهی آخرین رشتههای قالب ارسالشده به توابع سطح ماژول در نهانگاه ذخیره میشوند، بنابراین برنامههایی که تنها از چند رشتهی قالب استفاده میکنند، نیازی نیست نگران استفادهی مجدد از یک نمونه از Struct باشند.
اشیای Struct کامپایلشده از متدها و ویژگیهای زیر پشتیبانی میکنند:
یکسان با تابع pack()، با استفاده از قالب کامپایلشده. (len(result) برابر با size خواهد بود.)
کاملاً مشابه تابع pack_into()، با استفاده از قالب کامپایلشده.
دقیقاً مانند تابع unpack()، با استفاده از قالب کامپایلشده. اندازهی بافر بر حسب بایت باید برابر با size باشد.
کاملاً مشابه تابع unpack_from() است و از قالب کامپایلشده استفاده میکند. اندازه بافر بر حسب بایت، از موقعیت offset به بعد، باید حداقل size باشد.
یکسان با تابع iter_unpack()، با استفاده از قالب کامپایلشده. اندازهی بافر بر حسب بایت باید مضربی از size باشد.
اضافه شده در نسخهی 3.4.
رشته قالب استفادهشده برای ساخت این شیء Struct.
اندازهی محاسبهشدهی ساختار (و بنابراین اندازهی شیء bytes تولیدشده بهوسیلهی متد pack()) متناظر با format.
تغییر یافته در نسخهی 3.13: نمایش repr() ساختارها تغییر کرده است. اکنون به این صورت است:
>>> Struct('i') Struct('i')