هذه هي المجموعة السادسة من النصائح والبرمجة من Python من خلاصتيpythonetc.
الاختيارات السابقة:
الديكور غير نمطية
لا يشترط على أدوات الديكور إرجاع وظائف جديدة فقط ، بل يمكنها إرجاع أي قيمة أخرى:
def call(*args, **kwargs): def decorator(func): return func(*args, **kwargs) return decorator @call(15) def sqr_15(x): return x * x assert sqr_15 == 225 
قد يكون ذلك مفيدًا لإنشاء فئات بسيطة باستخدام طريقة واحدة يمكن إعادة تعريفها:
 from abc import ABCMeta, abstractmethod class BinaryOperation(metaclass=ABCMeta): def __init__(self, left, right): self._left = left self._right = right def __repr__(self): klass = type(self).__name__ left = self._left right = self._right return f'{klass}({left}, {right})' @abstractmethod def do(self): pass @classmethod def make(cls, do_function): return type( do_function.__name__, (BinaryOperation,), dict(do=do_function), ) class Addition(BinaryOperation): def do(self): return self._left + self._right @BinaryOperation.make def Subtraction(self): return self._left - self._right 
__length_hint__
يسمح 
PEP 424 للمولدات والمواد التكرارية الأخرى التي ليس لها حجم محدد مسبقًا بإرجاع طولها التقريبي. على سبيل المثال ، من المحتمل أن يعرض هذا المولد حوالي 50 عنصرًا:
 (x for x in range(100) if random() > 0.5) 
إذا كتبت شيئًا ما قابلًا للتكرار وترغب في إرجاع طول تقريبي ، 
__length_hint__ طريقة 
__length_hint__ . وإذا كنت تعرف الطول الدقيق ، فاستخدم 
__len__ . إذا كنت تستخدم كائنًا قابلاً للتكرار وترغب في معرفة المدة التي يمكن أن تكون عليها ، فاستخدم 
operator.length_hint .
في مع مولد
يمكن استخدام عامل التشغيل 
in المولدات: 
x in g . في هذه الحالة ، ستعمل Python على التكرار أكثر من 
g حتى 
x أو حتى ينتهي 
g .
 >>> def g(): ... print(1) ... yield 1 ... print(2) ... yield 2 ... print(3) ... yield 3 ... >>> 2 in g() 1 2 True 
range() ، ومع ذلك ، يعمل بشكل أفضل قليلا. إنه يحتوي على طريقة سحرية متجاوزة 
__contains__ ، وبفضل ذلك يصبح التعقيد الحسابي لـ 
in يساوي O (1):
 In [1]: %timeit 10**20 in range(10**30) 375 ns ± 10.7 ns per loop 
لاحظ أن هذا لن يعمل مع الدالة 
xrange() من Python 2.
عوامل التشغيل + = و +
لدى Python عاملان مختلفان: 
+= و 
+ . تعتبر أساليب 
__add__ و 
__add__ مسؤولة عن سلوكهم ، على التوالي.
 class A: def __init__(self, x): self.x = x def __iadd__(self, another): self.x += another.x return self def __add__(self, another): return type(self)(self.x + another.x) 
إذا لم 
__iadd__ تعريف 
__iadd__ a += b كـ 
a = a + b .
الفرق الدلالي بين 
+= و 
+ هو أن أول واحد يغير الكائن ، والثاني ينشئ واحدًا جديدًا:
 >>> a = [1, 2, 3] >>> b = a >>> a += [4] >>> a [1, 2, 3, 4] >>> b [1, 2, 3, 4] >>> a = a + [5] >>> a [1, 2, 3, 4, 5] >>> b [1, 2, 3, 4] 
تعمل كسمة لفئة
لا يمكنك تخزين إحدى الوظائف كخاصية صفية ، لأنه سيتم تحويلها تلقائيًا إلى طريقة إذا تم الوصول إليها من خلال مثيل:
 >>> class A: ... CALLBACK = lambda x: x ** x ... >>> A.CALLBACK <function A.<lambda> at 0x7f68b01ab6a8> >>> A().CALLBACK <bound method A.<lambda> of <__main__.A object at 0x7f68b01aea20>> >>> A().CALLBACK(4) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: <lambda>() takes 1 positional argument but 2 were given 
يمكنك الغش ولف الوظيفة في واصف تافه:
 >>> class FunctionHolder: ... def __init__(self, f): ... self._f = f ... def __get__(self, obj, objtype): ... return self._f ... >>> class A: ... CALLBACK = FunctionHolder(lambda x: x ** x) ... >>> A().CALLBACK <function A.<lambda> at 0x7f68b01ab950> 
يمكنك أيضًا الخروج من الموقف باستخدام طريقة الفصل بدلاً من السمة.
 class A: @classmethod def _get_callback(cls): return lambda x: x ** x