سؤال

أنا أتعلم لغة بايثون لفصل دراسي الآن، وقمنا للتو بتغطية الصفوف كأحد أنواع البيانات.لقد قرأت صفحة ويكيبيديا عليها، لكن لم أتمكن من معرفة أين سيكون نوع البيانات هذا مفيدًا في الممارسة العملية.هل يمكنني الحصول على بعض الأمثلة، ربما في بايثون، حيث ستكون هناك حاجة إلى مجموعة غير قابلة للتغيير من الأرقام؟كيف يختلف هذا عن القائمة؟

هل كانت مفيدة؟

المحلول

  • يتم استخدام الصفوف عندما تريد إرجاع نتائج متعددة من دالة.
  • وبما أنها غير قابلة للتغيير، فيمكن استخدامها كمفاتيح للقاموس (لا يمكن استخدام القوائم).

نصائح أخرى

تُنشئ Tuples مفاتيح قاموس جيدة عندما تحتاج إلى دمج أكثر من جزء واحد من البيانات في مفتاحك ولا ترغب في إنشاء فصل دراسي لها.

a = {}
a[(1,2,"bob")] = "hello!"
a[("Hello","en-US")] = "Hi There!"

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

انا يعجبني هذا التفسير.

بشكل أساسي، يجب عليك استخدام الصفوف عندما يكون هناك بنية ثابتة (يحتوي الموضع الأول دائمًا على نوع واحد من القيمة والثاني على نوع آخر، وهكذا دواليك)، ويجب استخدام القوائم لقوائم القيم المتجانسة.

بالطبع هناك دائمًا استثناءات، ولكن هذا دليل عام جيد.

الصفوف والقوائم لها نفس الاستخدامات بشكل عام.تتمتع أنواع البيانات غير القابلة للتغيير بشكل عام بالعديد من الفوائد، معظمها يتعلق بمشكلات التزامن.

لذا، عندما يكون لديك قوائم غير متقلبة بطبيعتها وتحتاج إلى ضمان عدم قيام أي مستهلك بتغييرها، فيمكنك استخدام صف.

الأمثلة النموذجية هي البيانات الثابتة في تطبيق مثل أقسام الشركة وفئاتها وما إلى ذلك.إذا تغيرت هذه البيانات، عادةً ما يقوم منتج واحد بإعادة بناء المجموعة.

أفضل طريقة للتفكير في الأمر هي:

  • الصف هو أ سِجِلّ الحقول التي ليس لها أسماء.
  • يمكنك استخدام صف بدلاً من السجل عندما لا تكون مضطرًا إلى تحديد أسماء الحقول.

فبدلاً من كتابة أشياء مثل:

person = {"name": "Sam", "age": 42}
name, age = person["name"], person["age"]

أو حتى أكثر تفصيلا:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Sam", 42)
name, age = person.name, person.age

يمكنك فقط أن تكتب:

person = ("Sam", 42)
name, age = person

يكون هذا مفيدًا عندما تريد تمرير سجل يحتوي على حقلين فقط، أو سجل يتم استخدامه في أماكن قليلة فقط.في هذه الحالة، قد يكون تحديد نوع سجل جديد بالكامل بأسماء الحقول (في Python، يمكنك استخدام كائن أو قاموس، كما هو مذكور أعلاه) مطولًا للغاية.

تنشأ الصفوف من عالم البرمجة الوظيفية (Haskell، OCaml، Elm، F#، إلخ)، حيث يتم استخدامها بشكل شائع لهذا الغرض.على عكس بايثون، تتم كتابة معظم لغات البرمجة الوظيفية بشكل ثابت (يمكن للمتغير أن يحمل نوع واحد فقط من القيمة، ويتم تحديد هذا النوع في وقت الترجمة).الكتابة الثابتة تجعل دور الصفوف أكثر وضوحًا.على سبيل المثال، في لغة العلم:

type alias Person = (String, Int)

person : Person
person = ("Sam", 42)

وهذا يسلط الضوء على حقيقة أن نوع معين من الصف من المفترض دائمًا أن يحتوي على عدد ثابت من الحقول بترتيب ثابت، ومن المفترض دائمًا أن يكون كل حقل من هذه الحقول من نفس النوع.في هذا المثال، يكون الشخص دائمًا عبارة عن صف من حقلين، أحدهما عبارة عن سلسلة والآخر عدد صحيح.

ما ورد أعلاه يتناقض بشكل صارخ مع القوائم, ، والتي من المفترض أن تكون متغيرة الطول (يختلف عادةً عدد العناصر في كل قائمة، وتكتب وظائف لإضافة العناصر وإزالتها) وعادةً ما يكون كل عنصر في القائمة من نفس النوع.على سبيل المثال، سيكون لديك قائمة واحدة بالأشخاص وقائمة أخرى بالعناوين - ولن تخلط الأشخاص والعناوين في نفس القائمة.في حين أن خلط أنواع مختلفة من البيانات داخل نفس الصف هو الهدف الأساسي من الصف.عادةً ما تكون الحقول الموجودة في الصف من أنواع مختلفة (ولكن ليس دائمًا - على سبيل المثال:يمكن أن يكون لديك (Float, Float, Float) Tuple لتمثيل إحداثيات x،y،z).

غالبًا ما تكون الصفوف والقوائم متداخلة. من الشائع أن يكون لديك قائمة من الصفوف.يمكن أن يكون لديك قائمة بصفوف الأشخاص بالإضافة إلى قائمة بكائنات الأشخاص.يمكنك أيضًا الحصول على حقل صفي تكون قيمته عبارة عن قائمة.على سبيل المثال، إذا كان لديك دفتر عناوين حيث يمكن أن يكون لدى شخص واحد عناوين متعددة، فمن الممكن أن يكون لديك مجموعة من النوع (Person, [String]).ال [String] يُستخدم النوع بشكل شائع في لغات البرمجة الوظيفية للإشارة إلى قائمة السلاسل.في بايثون، لن تقوم بتدوين النوع، ولكن يمكنك استخدام صفوف مثل تلك بنفس الطريقة تمامًا، مع وضع Person الكائن في الحقل الأول من الصف وقائمة السلاسل في الحقل الثاني.

في بايثون هناك ارتباك لأن اللغة لا فرض أي من هذه الممارسات التي يفرضها المترجم في اللغات الوظيفية المكتوبة بشكل ثابت.في تلك اللغات، لا يمكنك مزج أنواع مختلفة من الصفوف.على سبيل المثال، لا يمكنك إرجاع أ (String, String) tuple من دالة يقول نوعها إنها تُرجع a (String, Integer) مترابطة بيانية.لا يمكنك أيضًا إرجاع قائمة عندما يخبرك النوع أنك تخطط لإرجاع صف، والعكس صحيح.يتم استخدام القوائم بشكل صارم للمجموعات المتزايدة من العناصر، ويتم استخدام الصفوف بشكل صارم للسجلات ذات الحجم الثابت.لا تمنعك لغة بايثون من خرق أي من هذه القواعد إذا أردت ذلك.

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

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

في Python (باستخدام تطبيق CPython الافتراضي)، تكون الصفوف أيضًا أسرع من الكائنات أو القواميس لمعظم الأغراض، لذلك يتم استخدامها أحيانًا لهذا السبب، حتى عندما تكون تسمية الحقول باستخدام كائن أو قاموس أكثر وضوحًا.

أخيرًا، لتوضيح أن الصفوف تهدف إلى أن تكون نوعًا آخر من السجلات (وليس نوعًا آخر من القوائم)، قامت بايثون أيضًا تسمى الصفوف:

from collections import namedtuple

Person = namedtuple("Person", "name age")

person = Person("Sam", 42)
name, age = person.name, person.age

غالبًا ما يكون هذا هو الخيار الأفضل - أقصر من تحديد فئة جديدة، ولكن معنى الحقول يكون أكثر وضوحًا من استخدام المجموعات العادية التي لا تحتوي حقولها على أسماء.

تعد القوائم غير القابلة للتغيير مفيدة للغاية للعديد من الأغراض, ، لكن الموضوع معقد للغاية بحيث لا يمكن الإجابة عليه هنا.النقطة الأساسية هي أن الأشياء التي لا يمكن أن تتغير هي أسهل في التفكير من الأشياء التي يمكن أن تتغير.تأتي معظم الأخطاء البرمجية من أشياء تتغير بطرق غير متوقعة، لذا فإن تقييد الطرق التي يمكن أن تتغير بها الأشياء يعد طريقة جيدة للقضاء على الأخطاء.إذا كنت مهتمًا، أنصحك بقراءة برنامج تعليمي للغة برمجة وظيفية مثل Elm أو Haskell أو Clojure (Elm هي الأكثر ودية).لقد اعتبر مصممو تلك اللغات أن الثبات مفيد للغاية الجميع القوائم غير قابلة للتغيير هناك.(بدلاً من تغيير قائمة لإضافة عنصر أو إزالته، يمكنك إنشاء قائمة جديدة بالعنصر المُضاف أو المُزال.تضمن الثبات أن النسخة القديمة من القائمة لا يمكن أن تتغير أبدًا، لذلك يمكن للمترجم ووقت التشغيل جعل الكود يعمل بشكل جيد عن طريق إعادة استخدام أجزاء من القائمة القديمة في القائمة الجديدة وجمع الأجزاء المتبقية عندما تكون أطول ضروري.)

أجدها مفيدة عندما تتعامل دائمًا مع كائنين أو أكثر كمجموعة.

Tuple عبارة عن سلسلة من القيم.يمكن أن تكون القيم من أي نوع، ويتم فهرستها بواسطة عدد صحيح، لذا فإن المجموعات ليست مثل القوائم.الفرق الأكثر أهمية هو أن الصفوف غير قابلة للتغيير.

الصف عبارة عن قائمة قيم مفصولة بفواصل:

t = 'p', 'q', 'r', 's', 't'

من الممارسات الجيدة وضع الصفوف بين قوسين:

t = ('p', 'q', 'r', 's', 't') 

يمكن للقائمة دائمًا أن تحل محل الصف، فيما يتعلق بالوظيفة (باستثناء، على ما يبدو، المفاتيح في الإملاء).ومع ذلك، يمكن للصفوف أن تجعل الأمور تسير بشكل أسرع.وينطبق الشيء نفسه، على سبيل المثال، على السلاسل غير القابلة للتغيير في Java - متى ستحتاج إلى أن تكون غير قادر على تغيير سلاسلك؟أبداً!

لقد قرأت للتو مناقشة جيدة حول تحديد ما يمكنك القيام به من أجل تقديم برامج أفضل؛ لماذا تعتبر البرمجة الوظيفية مهمة؟

Tuple مفيد لتخزين قيم متعددة.كما لاحظت، فإن الصف يشبه القائمة غير القابلة للتغيير - على سبيل المثال.بمجرد الإنشاء، لا يمكنك إضافة/إزالة/تبديل العناصر.

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

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top