هذه هي المجموعة الثانية من نصائح وبرمجة Python من
موجزpythonetc الخاص بي. التحديدات السابقة:
لغات عادية
اللغة العادية هي لغة رسمية يمكن تمثيلها
كآلة حالة محدودة . بمعنى آخر ، لمعالجة النص حرفًا تلو الآخر تحتاج فقط إلى تذكر الحالة الحالية ، وعدد هذه الحالات محدود.
مثال مثالي: آلة تتحقق مما إذا كان الإدخال أوليًا مثل -3 أو 2.2 أو 001. في بداية المقالة ، يتم عرض آلة حالة محدودة. تشير الدوائر المزدوجة إلى الحالة النهائية ، حيث يمكن للآلة التوقف.
تبدأ الآلة من موضع . ربما يجد ناقصًا ، ثم رقمًا ، ثم في الموضع ③ يعالج العدد المطلوب من الأرقام. بعد ذلك ، يمكن التحقق من الفاصل العشري (③ → ④) ، متبوعًا برقم واحد (④ → ⑤) أو أكثر (⑤ → ⑤).
المثال الكلاسيكي للغة غير النظامية هو مجموعة من تعبيرات السلسلة للنموذج:
ab
aaa-bbb
aaaaa-bbbbb
من الناحية الرسمية ، نحتاج إلى سلسلة تحتوي على مثيلات N لـ
a
، ثم
–
ثم - N مثيلات
b
، حيث يكون N عددًا صحيحًا أكبر من 0. لا يمكنك تنفيذ ذلك باستخدام جهاز الحالة ، حيث سيتعين عليك تذكر عدد الأحرف التي اعتقدت أنه يمكنك يتم ذلك فقط باستخدام عدد لا نهائي من الحالات.
يمكن للتعبيرات العادية تحديد اللغات العادية فقط. قبل استخدامها ، تأكد من أنه يمكن معالجة السلسلة الخاصة بك باستخدام جهاز الحالة. على سبيل المثال ، لا تصلح لمعالجة JSON أو XML أو حتى التعبيرات الحسابية مع الأقواس.
من المضحك أن العديد من محركات regex الحديثة ليست منتظمة. على سبيل المثال ، تدعم وحدة regex في Python التكرار (مما
سيساعد في حل المشكلة باستخدام
aaa-bbb
).
جدولة ديناميكية
عندما تقوم Python باستدعاء أسلوب ، على سبيل المثال
af(b, c, d)
، يجب عليها أولاً تحديد الوظيفة الصحيحة
f
. بحكم تعدد الأشكال ، يحدد
a
ما سيتم اختياره في نهاية المطاف. عادةً ما تسمى عملية تحديد طريقة الإرسال الديناميكي.
يدعم Python تعدد الأشكال أحادي الإرسال فقط. هذا يعني أن الكائن نفسه فقط يؤثر على اختيار الكائن (في مثالنا ،
a
). في اللغات الأخرى ، يمكن أخذ الأنواع
b
و
c
و
d
في الاعتبار - تسمى هذه الآلية الإرسال المتعدد. ومن الأمثلة اللافتة على ذلك لغة C #.
ومع ذلك ، يمكن محاكاة جدولة متعددة باستخدام واحد. هذا هو السبب في إنشاء قالب تصميم الزائر: يستخدم مرتين إرسال واحد لمحاكاة مزدوجة.
تذكر أن طرق التحميل الزائد (كما هو الحال في Java و C ++) ليست تناظرية للإرسال المتعدد. يعمل الإرسال الديناميكي في وقت التشغيل ، ويتم التحميل الزائد فقط أثناء التجميع.
ستساعدك هذه الأمثلة على فهم الموضوع بشكل أفضل:
أسماء مضمنة
في Python ، يمكنك بسهولة تعديل جميع المتغيرات القياسية المتوفرة في النطاق العالمي:
>>> print = 42 >>> print(42) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'int' object is not callable
يفيد ذلك إذا كانت الوحدة النمطية الخاصة بك تحدد الوظائف التي تتطابق أسماؤها مع أسماء الوظائف المضمنة. يحدث هذا أيضًا في المواقف التي تمارس فيها البرمجة التخطيطية وتأخذ قيمة سلسلة عشوائية كمعرف.
ولكن حتى إذا قمت بتكرار أسماء بعض الوظائف المضمنة ، فقد تحتاج إلى الوصول إلى ما أشاروا إليه في الأصل. هذا هو السبب في وجود الوحدة النمطية المضمنة:
>>> import builtins >>> print = 42 >>> builtins.print(1) 1
يتوفر أيضًا في معظم الوحدات المتغير
__builtins__
. ولكن هناك خدعة واحدة. أولاً ، هذه ميزة في تنفيذ cpython ، وعادة لا يجب استخدامها على الإطلاق. ثانيًا ، يمكن أن يشير
__builtins__
إلى كل من
builtins
و
builtins.__dict__
.
عنيد
في بعض الأحيان يبدأ التطبيق في التصرف بشكل غريب في المعركة. بدلاً من إعادة تشغيله ، قد ترغب في فهم سبب المشاكل عندما يكون ذلك ممكنًا.
الحل الواضح هو تحليل إجراءات البرنامج ومحاولة فهم الجزء الذي يتم تنفيذه من التعليمات البرمجية. يجعل التسجيل الصحيح هذه المهمة أسهل ، ولكن قد لا تكون سجلاتك مفصلة بما فيه الكفاية بسبب البنية أو مستوى التسجيل المحدد في الإعدادات.
في مثل هذه الحالات ، قد يكون من المفيد. هذه أداة Unix التي تتعقب مكالمات النظام. يمكنك تشغيله سابقًا -
strace python script.py
- ولكنه عادةً ما يكون أكثر ملاءمة للاتصال بتطبيق قيد التشغيل بالفعل:
strace -p PID
.
$ cat test.py with open('/tmp/test', 'w') as f: f.write('test') $ strace python test.py 2>&1 | grep open | tail -n 1 open("/tmp/test", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3
يحتوي كل سطر في التتبع على اسم استدعاء النظام والوسيطات الموجودة بين قوسين وقيمة الإرجاع. نظرًا لاستخدام بعض الوسيطات لإرجاع نتيجة استدعاء النظام ، وليس لتمرير البيانات إليها ، يمكن إيقاف إخراج الخط مؤقتًا حتى انتهاء استدعاء النظام.
في هذا المثال ، يتم إيقاف الإخراج حتى اكتمال الكتابة إلى STDIN:
$ strace python -c 'input()' read(0,
Tuple الحرفي
أحد الأجزاء الأكثر تناقضًا في بنية Python هو المجموعة الحرفية.
لإنشاء مجموعة ، يكفي إدراج القيم المفصولة بفواصل:
1, 2, 3
. ماذا عن صف العنصر الواحد؟ ما عليك سوى إضافة فاصلة معلقة:
1,
،. يبدو قبيحًا وغالبًا ما يؤدي إلى أخطاء ، ولكنه منطقي تمامًا.
ماذا عن صف فارغ؟ هذه فاصلة واحدة -؟ لا ، هذا
()
. وماذا ، الأقواس تخلق مجموعة ، مثل الفواصل؟ لا ،
(4)
ليس مجموعة ، بل
4
فقط.
In : a = [ ...: (1, 2, 3), ...: (1, 2), ...: (1), ...: (), ...: ] In : [type(x) for x in a] Out: [tuple, tuple, int, tuple]
لإرباك الأشياء أكثر صعوبة ، غالبًا ما تتطلب الأحرف الحرفية في الصفوف قوسين إضافيين. إذا كنت بحاجة إلى أن يكون tuple هو الوسيط الوحيد للدالة ، فمن الواضح أن
f(1, 2, 3)
لن تعمل - سيكون عليك كتابة
f((1, 2, 3))
.