Coding for KidsCoding for Kids
المستويات الإبداعيةالتحدياتدليل المعلم
صوت للميزات
دورة تطوير بايثون المتقدمة
الفصل
>
المستوى

وحدات التسلسل
وحدة البنية

الهدف

إعداد تحليل البيانات النهائي للمزرعة الجديدة باستخدام وحدة struct.

في نهاية الطريق توجد محطة خدمة تدير المزرعة الجديدة التي تم بناؤها بالفعل والمحاصيل المزروعة. هنا سنقوم بفحص ومعالجة بيانات المحاصيل المزروعة والناتج المتوقع للمزرعة. مثل باقي المستويات في هذا الفصل، سنعمل على تسلسل وفك تسلسل البيانات، معرفين وحدة أخيرة تسمى وحدة struct.

تقدم وحدة struct سلسلة من دوال التسلسل التي تُعبأ البيانات بصيغة ثنائية، وعلى عكس الوحدات الأخرى التي عملنا معها، فإن لديك تحكمًا أكبر في كيفية تنظيم البيانات سواء أثناء تسلسلها أو عند فك تسلسلها لاحقًا، مما يجعلها أكثر مرونة من الوحدات الأخرى. استخدم import struct للوصول إلى الدوال التالية التي سنستخدمها لمعالجة البيانات:

  • struct.calcsize(): تحدد عدد البايتات التي تُعبأ بواسطة سلسلة تنسيق معينة، وتقبل معاملًا واحدًا (1) وهو التنسيق الذي ترغب في التحقق من حجمه بالبايت. التنسيقات التي سنستخدمها هي:
    • integer: يُمثل بـ 'i' وهو تنسيق للبيانات الممثلة بأعداد صحيحة
    • float: يُمثل بـ 'f' وهو تنسيق للبيانات الممثلة بأعداد عشرية
    • double: يُمثل بـ 'd' وهو تنسيق للبيانات الممثلة بأعداد عشرية أكثر تعقيدًا عندما يكون تنسيق الـ float غير كافٍ.
  • struct.pack(): يقوم بتسلسل البيانات إلى صيغة ثنائية، معبأة بتنسيق تختاره. يمكنك تمرير معاملين (2) أو أكثر، الأول هو التنسيق الذي ترغب في استخدامه والثاني هو القيم التي تريد تسلسلها. التنسيقات هي نفس تلك المذكورة سابقًا ويجب إضافتها بما يتوافق مع عدد المعاملات التي تمررها.
  • struct.unpack(): يقوم بفك تسلسل البيانات الثنائية المعبأة، يأخذ معاملين (2): الأول هو التنسيق الذي يجب أن يتطابق مع التنسيق الذي تم تسلسل البيانات به، والمعامل الثاني هو البيانات التي تم تسلسلها.
  • struct.iter_unpack(): يقوم بفك تسلسل البيانات الثنائية المعبأة، ويعمل بنفس طريقة struct.unpack() ولكن يقوم بالتكرار عبر كل كتلة بيانات بشكل فردي باستخدام حلقة.
  • struct.pack_into(): نسخة متقدمة من struct.pack()، يأخذ أربعة (4) معاملات وهي: التنسيق الذي ترغب في استخدامه، مخزن البيانات الذي تريد وضع البيانات فيه، الموضع في المخزن الذي تريد أن تشغل البيانات فيه، وأخيرًا البيانات التي تقوم بتعبئتها.
  • struct.unpack_from(): نسخة متقدمة من struct.unpack()، يأخذ ثلاثة (3) معاملات وهي: التنسيق الذي ترغب في استخدامه، مخزن البيانات الذي تريد فك تسلسله، وأخيرًا الموضع في المخزن الذي تريد فك البيانات منه. هذا يسمح بفك أجزاء محددة من البيانات.

انتقل إلى علامة X المضيئة في محطة الخدمة وواجه المكتب، وأنشئ ثلاث (3) متغيرات بأسماء: integer، float وdouble. سنستخدم هذه المتغيرات للتحقق من حجم كل تنسيق بالبايت باستخدام دالة struct.calcsize(). بالنسبة لمتغير integer استخدم الدالة مع 'i' كمعامل، بالنسبة لمتغير float استخدم الدالة مع 'f' كمعامل، وأخيرًا بالنسبة لمتغير double استخدم الدالة مع 'd' كمعامل. على سبيل المثال: integer = struct.calcsize('i'). أضف المتغيرات الثلاثة (3) إلى دالة write() المكتوبة مسبقًا.

انتقل إلى علامة X الذهبية واستخدم الدالة read() لجمع البيانات عن المزرعة الجديدة، دون ملاحظة نقاط البيانات والتنسيق للاستخدام المستقبلي، وهي: الموارد، الحجم والتقدير. بعد تدوين هذه الملاحظات، انتقل إلى علامة X المضيئة فوق السجادة الزرقاء وأنشئ متغيرًا باسم blue_data.

مع المتغير blue_data، خزن القيمة الناتجة عن دالة struct.pack()، مع تمرير التنسيق والقيم التي دونتها سابقًا كمعاملات. عند كتابة التنسيق، يجب عليك "تعبئة" أنواع التنسيقات في وحدة واحدة. على سبيل المثال، تنسيق العدد الصحيح يُمثّل بـ 'i' كما تم التفصيل سابقًا، فإذا كنت تضيف ثلاث قيم صحيحة، تضيفها هكذا: 'iii'. وبالمثل، إذا كنت تضيف عددًا صحيحًا وعددًا عشريًا وعددًا مزدوجًا، فسيكون التنسيق هكذا: 'ifd'. عند تمرير البيانات، تضعها بشكل منفصل كمعاملات. فيما يلي مثال عام:

data_1 = 8 # is an integer data_2 = 2.25 # is a float data_3 = 900.702938103 # is a double blue_data = struct.pack('ifd', data_1, data_2, data_3)

تسمح دالة struct.pack() بقدر كبير من المرونة، مما يمكنك من تحديد كيفية تنسيق البيانات ويسمح لك بتسلسل عدة نقاط بيانات دفعة واحدة حسب تقديرك. أضف البيانات التي تمت قراءتها مسبقًا باستخدام المثال أعلاه كقاعدة. استخدم الدالة display() مع blue_data كمعامل لعرض البيانات المعبأة.

انتقل إلى علامة X الداكنة فوق السجادة الزرقاء وواجه الطرفية، وأنشئ متغيرًا باسم blue_unpack وخزن القيمة الناتجة عن دالة struct.unpack()، مع تمرير نفس التنسيق المستخدم لتعبئة البيانات ومتغير blue_data كمعاملات. يُكتب التنسيق بنفس طريقة دالة struct.pack()، بحيث يمكنك فك تسلسل البيانات بنفس الطريقة التي تم بها تسلسلها. استخدم الدالة write() مع blue_unpack كمعامل للتحقق من البيانات التي سبق تعبئتها.

في نفس الموقع سنستخدم أيضًا دالة struct.iter_unpack()، التي تأخذ نفس المعاملات تمامًا كما في struct.unpack()، إلا أنها مُهيأة الآن كحلقة for، مما يسمح لنا بالتكرار عبر البيانات بدلاً من كتابتها جميعها مرة واحدة. تُكتب الدالة كما يلي:

for values in struct.iter_unpack(-insert value-, -insert value-): player.speak(values)

سنستخدم دالة speak() لعرض القيم، وبالنسبة للمعاملات المفقودة في دالة struct.iter_unpack()، أضف نفس تلك المستخدمة سابقًا مع struct.unpack() حيث أنها نسخ من نفس الدالة من حيث الاستخدام.

انتقل إلى علامة X الذهبية فوق السجادة الحمراء وواجه المكتب، استخدم الدالة read() لمراجعة كميات المحاصيل. دون ملاحظة كل الكميات والتنسيق الخاص بكل محصول. انتقل إلى علامة X المضيئة فوق السجادة الحمراء وأنشئ كائنًا باسم buffer، وأضف إليه القيمة bytearray(16). هذه مجموعة من البايتات التي يمكنك التعامل معها قبل تعبئتها، ولأغراضنا تعمل مثل بنك بيانات حيث يمكنك تخزين البيانات يدويًا. الرقم 16 كمعامل هو عدد البايتات التي يمكنك تخزينها في كائن buffer.

استخدم دالة struct.pack_into() لتعبئة كائن buffer الذي أنشأته. لا حاجة لإنشاء متغير لتخزين قيمة الدالة حيث إن الدالة نفسها ستدرج القيم مباشرة في كائن buffer. سنستخدم الدالة لكل من القيم التي دونتها مسبقًا ونمرر معاملات التعبئة الخاصة بها.

على سبيل المثال، بالنسبة لأول قيمة محصول مقدمة، سيتم تزويدك بتنسيقها، موقع البايت ومقدارها. أضف التنسيق كالمعامل الأول، والموقع الذي ترغب في تسلسل البايتات فيه وهو في هذه الحالة buffer. بالنسبة للمعامل الثالث، حدد الموضع الذي ترغب في إضافة القيمة فيه داخل buffer، حيث يحدد التنسيق عدد البايتات المستخدمة، لذا احرص على تعبئة بيانات لم تُشغل من قبل. وأخيرًا أضف القيمة التي ترغب في تسلسلها وتعبئتها في كائن buffer.

struct.pack_into('i', buffer, 0, 82)

يحتوي كائن buffer على 16 بايت كما ذُكر سابقًا، ففي الكود أعلاه، تنسيق العدد الصحيح يحتوي على 4 بايت ويتم إدراجه عند الموضع 0. هذا يعني أنه بمجرد إدخال البيانات في buffer، يتبقى فقط 12 بايت غير مشغولة في buffer، حيث إن المواضع من 0 إلى 3 مشغولة بالقيمة المقدمة، وهي في هذه الحالة 82. قم بذلك لكل نقاط بيانات المحاصيل التي تمت قراءتها وتدوينها مسبقًا، إذ يوجد إجمالي ثلاث (3) نقاط. استخدم الدالة display() وأضف buffer لعرض البيانات المعبأة.

انتقل إلى علامة X الداكنة فوق السجادة الحمراء وواجه الطرفية، هنا سنفك تسلسل البيانات للتحقق من المحتويات وضمان التخزين الصحيح. أنشئ ثلاث متغيرات باسم: lettuce، carrots وmelons، وسنقوم بفك تسلسل بيانات كل نقطة على حدة. لكل متغير، خزن القيمة الناتجة عن دالة struct.unpack_from() مع تمرير معاملات البيانات التي دونتها لتعبئة البيانات. بالنسبة للمعامل الأول، استخدم التنسيق، والمعامل الثاني أضف كائن buffer وهو موقع فك التسلسل، وأخيرًا المعامل الثالث هو الموضع في buffer الذي ترغب في فك البيانات منه. على سبيل المثال:

lettuce = struct.unpack_from('i', buffer, 0)

تشير هذه البيانات إلى المثال السابق لتعبئة البيانات الذي يتم الآن فك تسلسله، قم بنفس العملية للمتغيرين الآخرين وأدرج lettuce، carrots وmelons في الدالة write() المكتوبة مسبقًا لإكمال المستوى.

كتاب الكود