وخلق Guido سلاسل في صورة C ، في صورة صفائف من الشخصيات التي أنشأتها. ورأى جيدو أنه كان جيدا. 
أم لا؟تخيل أنك تكتب رمزًا مثاليًا تمامًا لتجاوز بعض البيانات بالتداخل. جميل أفضل من قبيح ، بسيط أفضل من معقد ، لذلك تتوقف عند الإصدار التالي من الكود:
from collections.abc import Iterable def traverse(list_or_value, callback): if isinstance(list_or_value, Iterable): for item in list_or_value: traverse(item, callback) else: callback(list_or_value) 
تكتب اختبار وحدة ، وما رأيك؟ أنها لا تعمل ، وليس فقط لا يعمل ، ولكن
 >>> traverse({"status": "ok"}, print) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in traverse File "<stdin>", line 4, in traverse File "<stdin>", line 4, in traverse [Previous line repeated 989 more times] File "<stdin>", line 2, in traverse File "/usr/local/opt/python/libexec/bin/../../Frameworks/Python.framework/Versions/3.7/lib/python3.7/abc.py", line 139, in __instancecheck__ return _abc_instancecheck(cls, instance) RecursionError: maximum recursion depth exceeded in comparison 
كيف؟ لماذا؟ في البحث عن إجابة ، سوف تغوص في العالم الرائع لمجموعات العمق اللانهائي.
في الواقع ، السلسلة هي 
Iterable المدمجة فقط التي ترجع 
Iterable دائمًا كعنصر! يمكننا بالطبع بناء مثال آخر عن طريق إنشاء قائمة وإضافتها إلى أنفسنا مرة واحدة أو مرتين ، لكن هل ترى هذا غالبًا في شفرتك؟ والخط قابل 
Iterable بعمق لا نهائي ، يتسلل تحت غطاء الليل مباشرة إلى الإنتاج.
مثال آخر في مكان ما من الشفرة ، يلزمك التحقق من وجود عناصر في الحاويات بشكل متكرر. قررت أن تكتب المساعد الذي يسرع بها في نواح كثيرة. تكتب حلاً شاملاً يستخدم فقط طريقة 
__contains__ (الطريقة الوحيدة في الفئة المجردة 
Container ) ، ولكن بعد ذلك تقرر إضافة تحسين فائق لحالة خاصة - مجموعة. بعد كل شيء ، يمكنك فقط المشي على طول ووضع 
set !
 import functools from typing import Collection, Container def faster_container(c: Container) -> Container: if isinstance(c, Collection): return set(c) return CachedContainer(c) class CachedContainer(object): def __init__(self, c: Container): self._contains = functools.lru_cache()(c.__contains__) def __contains__(self, stuff): return self._contains(stuff) 
ثالثا ... الحل الخاص بك لا يعمل! حسنا هنا! مرة أخرى!
 >>> c = faster_container(othello_text) >>> "Have you pray'd to-night, Desdemona?" in c False 
(ولكن تم إصدار إجابة خاطئة بسرعة حقا ...)
لماذا؟ لأن السلسلة في Python عبارة عن مجموعة مدهشة 
لا تتوافق فيها دلالات الأسلوب 
__contains__ مع دلالات 
__iter__ و 
__len__ .
في الواقع ، السلسلة عبارة عن مجموعة:
 >>> from collections.abc import Collection >>> issubclass(str, Collection) True 
لكن المجموعة ... ماذا؟ 
__iter__ و 
__len__ يعتبران هذه مجموعة من الأحرف:
 >>> s = "foo" >>> len(s) 3 >>> list(s) ['f', 'o', 'o'] 
لكن 
__contains__ تعتقد أن هذه مجموعة من 
__contains__ الفرعية!
 >>> "oo" in s True >>> "oo" in list(s) False 
ما الذي يمكن عمله؟
على الرغم من أن سلوك 
str.__contains__ قد يبدو غريباً في سياق 
__contains__ أنواع قياسية أخرى ، إلا أن هذا السلوك هو أحد الأشياء الصغيرة الكثيرة التي تجعل Python مريحة مثل لغة البرمجة النصية ؛ مما يتيح لك كتابة رمز سريع وأدبي على ذلك. لا أقترح تغيير سلوك هذه الطريقة ، خاصةً أننا لا نستخدمها أبدًا للتحقق من وجود حرف واحد في سلسلة.
وبالمناسبة ، هل تعرف لماذا؟ لأننا لا نستخدم أبدًا سلسلة كمجموعة من الشخصيات بلغة البرمجة النصية! التعامل مع شخصيات معينة في سلسلة ، والوصول عن طريق الفهرس - في معظم الأحيان مصير المهام في المقابلات. لذا ، ربما يجب عليك إزالة 
__iter__ من السلسلة ، وإخفائه وراء بعض الطرق مثل 
.chars() ؟ هذا من شأنه أن يحل كل من هذه المشاكل.
وقت لمناقشة يوم الجمعة في التعليقات!