2.33. الاستبطان (Introspection)¶
تتيح حفنة من الدوال المُدمجة لبرنامج قيد التشغيل أن يفحص نفسه -- القيم التي يعمل بها، والنطاقات الاسمية التي تعيش فيها تلك القيم، والعلاقات بين الأصناف. الجأ إليها عندما تحتاج إلى اتخاذ قرارات بناءً على ما هو عليه الكائن فعلًا، بدلًا مما يدّعيه مستدعيه.
2.33.1. الهوية والتجزئة (hashing)¶
id()-- عدد صحيح فريد يحدّد هوية الكائن طالما بقي حيًا. اسمان يربطان الكائن نفسه يُعيدان المُعرّف نفسه؛ بينما كائنان متساويان ولكن منفصلان لا يفعلان ذلك.
>>> a = [1, 2, 3]
>>> b = a
>>> c = [1, 2, 3]
>>> id(a) == id(b) # same list
True
>>> id(a) == id(c) # equal but distinct
False
المُعرّف غير قابل للنقل عبر عمليات التشغيل المختلفة وليس له معنى يتجاوز "الكائن نفسه أو كائن مختلف".
hash()-- قيمة التجزئة (hash) لكائن، وهي العدد نفسه الذي يستخدمهdictوsetللبحث عنه. كائنان متساويان يُجزَّآن إلى القيمة نفسها؛ ولا تعمل سوى الأنواع القابلة للتجزئة (القيم غير القابلة للتغيير في الغالب).
>>> hash("abc") # some integer, build-dependent
-1600925533
>>> hash([1, 2])
TypeError: unhashable type: 'list'
2.33.2. الاستعلام عن الأنواع وقابلية الاستدعاء¶
type()-- الصنف الدقيق لقيمة ما. تسألtype(x) is int"هل x من النوع int تمامًا" (دون الأصناف الفرعية)؛ وعادةً ما تكونisinstance()هي ما تريده بدلًا من ذلك.isinstance()-- "هل x نسخة من هذا الصنف، أو من صنف فرعي منه؟" الأداة المعيارية للإرسال المبني على النوع داخل الدوال.issubclass()-- النظير على مستوى الصنف. تأخذ صنفين بدلًا من نسخة.callable()-- تُعيدTrueإذا كان بالإمكان استدعاء الوسيط باستخدام(). مفيدة عندما تتلقى وسيطًا قد يكون دالة وقد يكون قيمة عادية.
>>> isinstance(3, int)
True
>>> isinstance(True, int) # bool is a subclass of int
True
>>> issubclass(bool, int)
True
>>> callable(len)
True
>>> callable(10)
False
نمط يستخدم callable:
def call_or_return(x):
return x() if callable(x) else x
2.33.3. النظر إلى النطاقات¶
globals()-- النطاق الاسمي العام للوحدة على هيئةdict. القراءة منه تعمل؛ والكتابة إليه حقيقية، لكن فعل ذلك خارج استكشاف REPL يجعل البرنامج صعب المتابعة.locals()-- النطاق الاسمي المحلي عند موضع الاستدعاء. وداخل دالة يعكس المتغيرات المحلية؛ أما تعديل القاموس المُعاد فليس مضمونًا أن يُكتب مجددًا في المتغيرات المحلية الفعلية (سلوك معرَّف من قبل التنفيذ).
name = "OpenMV"
def f():
x = 10
print(globals()["name"]) # OpenMV
print(locals()) # {'x': 10}
هاتان مفيدتان لتصحيح الأخطاء وللأدوات التي تحتاج إلى اكتشاف ما هو معرَّف. الجأ إليهما باعتدال في الشيفرة العادية -- فالدالة التي تطفر (mutate) globals() هي من أصعب الأشياء التي يمكن التفكير فيها في Python.
2.33.4. انظر أيضًا¶
dir() و help()، المشروحتان في debugging، هما أداتا الاستبطان اليوميتان لاستكشاف سطح كائن غير معروف.