Decypher со мной, что запутанный множительфакторный

StackOverflow https://stackoverflow.com/questions/1483085

Вопрос

На этой неделе на 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: верно?

Верно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top