decypher معي أن يبعث مضاعفة
-
18-09-2019 - |
سؤال
هذا الأسبوع على comp.lang.python، كان قطعة من الكود "مثيرة للاهتمام" نشر بواسطة ستيفن d'Aprano كإجابة نكتة لسؤال الواجبات المنزلية. ها هو:
class MultiplierFactory(object):
def __init__(self, factor=1):
self.__factor = factor
@property
def factor(self):
return getattr(self, '_%s__factor' % self.__class__.__name__)
def __call__(self, factor=None):
if not factor is not None is True:
factor = self.factor
class Multiplier(object):
def __init__(self, factor=None):
self.__factor = factor
@property
def factor(self):
return getattr(self,
'_%s__factor' % self.__class__.__name__)
def __call__(self, n):
return self.factor*n
Multiplier.__init__.im_func.func_defaults = (factor,)
return Multiplier(factor)
twice = MultiplierFactory(2)()
نحن نعلم ذلك twice
هو ما يعادل الجواب:
def twice(x):
return 2*x
من الأسماء Multiplier
و MultiplierFactory
نحصل على فكرة ما تفعله الرمز، لكننا لسنا متأكدين من المخادين الدقيقين. دعونا تبسيط ذلك أولا.
منطق
if not factor is not None is True:
factor = self.factor
not factor is not None is True
أي ما يعادل not factor is not None
, ، وهو ايضا factor is None
. وبعد نتيجة:
if factor is None:
factor = self.factor
حتى الآن، كان ذلك سهلا :)
الوصول إلى السمة
نقطة أخرى مثيرة للاهتمام هي الغريب factor
الملحق.
def factor(self):
return getattr(self, '_%s__factor' % self.__class__.__name__)
أثناء تهيئة MultiplierFactory
, self.__factor
تم تعيين. ولكن في وقت لاحق، الوصول إلى التعليمات البرمجية self.factor
.
ثم يبدو أن:
getattr(self, '_%s__factor' % self.__class__.__name__)
يفعل بالضبط "self.__factor
".
هل يمكننا دائما الوصول إلى السمات في هذه الأزياء؟
def mygetattr(self, attr):
return getattr(self, '_%s%s' % (self.__class__.__name__, attr))
تغيير ديناميكيا تواقيع وظيفة
على أي حال، في هذه المرحلة، هنا هو التعليمات البرمجية المبسطة:
class MultiplierFactory(object):
def __init__(self, factor=1):
self.factor = factor
def __call__(self, factor=None):
if factor is None:
factor = self.factor
class Multiplier(object):
def __init__(self, factor=None):
self.factor = factor
def __call__(self, n):
return self.factor*n
Multiplier.__init__.im_func.func_defaults = (factor,)
return Multiplier(factor)
twice = MultiplierFactory(2)()
الكود هو تنظيف تقريبا الآن. الخط الوحيد المحير، ربما، سيكون:
Multiplier.__init__.im_func.func_defaults = (factor,)
ما في هناك؟ نظرت إلى Datamodel Doc., ، ووجدت ذلك func_defaults
كنت "Tuple يحتوي على قيم الوسيطة الافتراضية لهذه الوسائط التي لها إعدادات افتراضية، أو لا شيء في حالة عدم وجود قيمة افتراضية". هل نحن فقط تغيير القيمة الافتراضية factor
حجة في __init__
هنا؟ سيكون رمز الناتج بعد ذلك:
class MultiplierFactory(object):
def __init__(self, factor=1):
self.factor = factor
def __call__(self, factor=None):
if factor is None:
factor = self.factor
class Multiplier(object):
def __init__(self, innerfactor=factor):
self.factor = innerfactor
def __call__(self, n):
return self.factor*n
return Multiplier(factor)
twice = MultiplierFactory(2)()
مما يعني أن تحديد القيمة الافتراضية ديناميكيا كانت مجرد ضوضاء عديمة الفائدة Multiplier
لا يطلق عليه أبدا بدون معلمة افتراضية، الصحيح?
وربما يمكننا تبسيطها إلى:
class MultiplierFactory(object):
def __init__(self, factor=1):
self.factor = factor
def __call__(self, factor=None):
if factor is None:
factor = self.factor
def my_multiplier(n):
return factor*n
return my_multiplier
twice = MultiplierFactory(2)() # similar to MultiplierFactory()(2)
صيح؟
ولأولئك الذين يروجون "هذا ليس سؤالا حقيقيا" ... اقرأ مرة أخرى، أسئلتي في غامق + مائل
المحلول
q1. هل يمكننا دائما الوصول إلى السمات في هذه الأزياء؟
ج: لا. إنها فقط تلك السمات التي تبدأ بتشكيل السفلات المزدوجة. يتم تبديدهم بهذه الطريقة، لمنع الوصول العرضي / الغالق من خارج الفصل.
q2: هل نحن فقط تغيير القيمة الافتراضية لوسيطة عامل في __init__
هنا؟
ج: نعم.
q2: أليس كذلك؟
حق.