هذا هو الاختيار الحادي عشر لنصائح Python والبرمجة من خلاصتيpythonetc.
←
المجموعات السابقةتحظر
break
استثناءً إذا طُبقت في كتلة أخيرة ، حتى إذا لم يكن هناك أي كتلة:
for i in range(10): try: 1 / i finally: print('finally') break print('after try') print('after while')
النتيجة:
finally after while
ينطبق الأمر نفسه على
continue
، ولكن لا يمكن استخدام هذا التعبير إلا في
finally
حتى إصدار Python 3.8:
SyntaxError: 'continue' not supported inside 'finally' clause
يمكنك إضافة أحرف Unicode إلى سلسلة حرفية ليس فقط عن طريق فهارسها ، ولكن أيضًا حسب الاسم.
>>> '\N{EM DASH}' '—' >>> '\u2014' '—'
هذه الطريقة متوافقة أيضًا مع الخطوط f:
>>> width = 800 >>> f'Width \N{EM DASH} {width}' 'Width — 800'
هناك ستة طرق "سحرية" لكائنات Python التي تحدد قواعد المقارنة:
__lt__
لـ <
__gt__
لـ >
__le__
لـ <=
__ge__
لـ >=
__eq__
لـ ==
__ne__
!=
إذا لم يتم تعريف أي من هذه الطرق أو إرجاع
NotImplemented
،
NotImplemented
القواعد التالية:
a.__lt__(b)
مثل b.__gt__(a)
a.__le__(b)
مثل b.__ge__(a)
a.__eq__(b)
نفسه not a.__ne__(b)
(لاحظ أنه في هذه الحالة a
و b
لم يغير الأماكن)
ومع ذلك ، فإن الشروط
a >= b
و
a != b
لا تعني تلقائيًا
a > b
. يقوم
functools.total_ordering
decorator بإنشاء جميع الطرق الست بناءً على
__eq__
وإحدى هذه
__lt__
:
__le__
أو
__ge__
أو
__ge__
أو
__ge__
.
from functools import total_ordering @total_ordering class User: def __init__(self, pk, name): self.pk = pk self.name = name def __le__(self, other): return self.pk <= other.pk def __eq__(self, other): return self.pk == other.pk assert User(2, 'Vadim') < User(13, 'Catherine')
في بعض الأحيان تحتاج إلى استخدام كل من الإصدارات المزين وغير المزين للوظيفة. تتمثل أسهل طريقة لتحقيق ذلك في حالة عدم استخدام صيغة تزيين خاصة (مع الرمز
@
) وإنشاء وظيفة تزيين يدويًا:
import json def ensure_list(f): def decorated(*args, **kwargs): result = f(*args, **kwargs) if isinstance(result, list): return result else: return [result] return decorated def load_data_orig(string): return json.loads(string) load_data = ensure_list(load_data_orig) print(load_data('3'))
أو يمكنك كتابة ديكور يزين الوظيفة ، مع الحفاظ على الإصدار الأصلي في السمة الأصلية الخاصة به:
import json def saving_orig(another_decorator): def decorator(f): decorated = another_decorator(f) decorated.orig = f return decorated return decorator def ensure_list(f): ... @saving_orig(ensure_list) def load_data(string): return json.loads(string) print(load_data('3'))
إذا تم إنشاء جميع أدوات الديكور الخاصة بك من خلال
functools.wraps
، فيمكنك استخدام سمة
__wrapped__
للوصول إلى وظيفة غير
__wrapped__
:
import json from functools import wraps def ensure_list(f): @wraps(f) def decorated(*args, **kwargs): result = f(*args, **kwargs) if isinstance(result, list): return result else: return [result] return decorated @ensure_list def load_data(string): return json.loads(string) print(load_data('3'))
لكن تذكر أن هذه
__wrapped__
لا تعمل مع الوظائف التي تم تزيينها بأكثر من
__wrapped__
تزيين واحدة: يجب عليك الرجوع إلى
__wrapped__
كل من الديكورات المطبقة:
def ensure_list(f): ... def ensure_ints(f): @wraps(f) def decorated(*args, **kwargs): result = f(*args, **kwargs) return [int(x) for x in result] return decorated @ensure_ints @ensure_list def load_data(string): return json.loads(string) for f in ( load_data, load_data.__wrapped__, load_data.__wrapped__.__wrapped__, ): print(repr(f('"4"')))
النتيجة:
[4] ['4'] '4'
@saving_orig
decorator المذكور أعلاه
@saving_orig
آخر كوسيطة. وإذا كان سيتم المعلمة؟ نظرًا لأن الديكور ذي المعلمات هو وظيفة تقوم بإرجاع ديكور حقيقي ، تتم معالجة هذا الموقف تلقائيًا:
import json from functools import wraps def saving_orig(another_decorator): def decorator(f): decorated = another_decorator(f) decorated.orig = f return decorated return decorator def ensure_ints(*, default=None): def decorator(f): @wraps(f) def decorated(*args, **kwargs): result = f(*args, **kwargs) ints = [] for x in result: try: x_int = int(x) except ValueError: if default is None: raise else: x_int = default ints.append(x_int) return ints return decorated return decorator @saving_orig(ensure_ints(default=0)) def load_data(string): return json.loads(string) print(repr(load_data('["2", "3", "A"]'))) print(repr(load_data.orig('["2", "3", "A"]')))
@saving_orig
مصمم الديكور
@saving_orig
بما نريد إذا تم تطبيق
@saving_orig
متعددة على الوظيفة. ثم لكل منهم عليك الاتصال
orig
:
import json from functools import wraps def saving_orig(another_decorator): def decorator(f): decorated = another_decorator(f) decorated.orig = f return decorated return decorator def ensure_list(f): ... def ensure_ints(*, default=None): ... @saving_orig(ensure_ints(default=42)) @saving_orig(ensure_list) def load_data(string): return json.loads(string) for f in ( load_data, load_data.orig, load_data.orig.orig, ): print(repr(f('"X"')))
النتيجة:
[42] ['X'] 'X'
يمكن
saving_orig
عن طريق دعم عدد تعسفي من الديكورات
saving_orig
:
def saving_orig(*decorators): def decorator(f): decorated = f for d in reversed(decorators): decorated = d(decorated) decorated.orig = f return decorated return decorator ... @saving_orig( ensure_ints(default=42), ensure_list, ) def load_data(string): return json.loads(string) for f in ( load_data, load_data.orig, ): print(repr(f('"X"')))
النتيجة:
[42] 'X'
يوجد حل آخر: اجعل
saving_orig
pass
orig
من دالة مزخرفة إلى أخرى:
def saving_orig(another_decorator): def decorator(f): decorated = another_decorator(f) if hasattr(f, 'orig'): decorated.orig = f.orig else: decorated.orig = f return decorated return decorator @saving_orig(ensure_ints(default=42)) @saving_orig(ensure_list) def load_data(string): return json.loads(string)
عندما يصبح الديكور أكثر تعقيدًا ، فمن الأفضل تحويله من وظيفة إلى فئة باستخدام طريقة
__call__
:
class SavingOrig: def __init__(self, another_decorator): self._another = another_decorator def __call__(self, f): decorated = self._another(f) if hasattr(f, 'orig'): decorated.orig = f.orig else: decorated.orig = f return decorated saving_orig = SavingOrig
يسمح لك السطر الأخير بتسمية الفصل في حقيبة الهجن وحفظ اسم الديكور في حقيبة الأفعى.
بدلاً من تحويل الوظيفة المزخرفة ، يمكنك إنشاء فئة أخرى تسمى ، وإرجاع مثيلات الوظيفة بدلاً من الوظيفة:
class CallableWithOrig: def __init__(self, to_call, orig): self._to_call = to_call self._orig = orig def __call__(self, *args, **kwargs): return self._to_call(*args, **kwargs) @property def orig(self): if isinstance(self._orig, type(self)): return self._orig.orig else: return self._orig class SavingOrig: def __init__(self, another_decorator): self._another = another_decorator def __call__(self, f): return CallableWithOrig(self._another(f), f) saving_orig = SavingOrig
كل رمز متاح
هنا.