Decypher со мной, что запутанный множительфакторный
-
18-09-2019 - |
Вопрос
На этой неделе на comp.lang.python, «интересный» кусок кода был Опубликовано Стивен Д'Апрано в качестве шутки отвечает на домашнее задание. Вот:
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
был "Кортеж, содержащий значения аргумента по умолчанию для тех аргументов, которые имеют по умолчанию, или нет, если нет аргументов". Мы просто меняем значение по умолчанию для 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 Можем ли мы всегда получить доступ к атрибутам таким образом?
A: Нет. Это только те атрибуты, которые начинаются с двойных подчеркиваний. Таким образом, они запутываются, чтобы предотвратить случайный доступ/переопределение извне класса.
Q2: Мы просто меняем значение по умолчанию для фактора аргумента в __init__
здесь?
A: Да.
Q2: верно?
Верно.