2

今週の comp.lang.python では、Steven 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

名前からMultiplierMultiplierFactoryコードが何をしているのかはわかりますが、正確な内部構造についてはわかりません。まず単純化しましょう。

論理

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

今までは簡単でした:)

属性アクセス

もう 1 つの興味深い点は、好奇心旺盛なfactorアクセサーです。

def factor(self):
    return getattr(self, '_%s__factor' % self.__class__.__name__)

の初期化中にMultiplierFactoryself.__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デフォルトを持つ引数のデフォルトの引数値を含むタプル、または引数にデフォルト値がない場合は None 」であることがわかりました。ここで引数のデフォルト値を変更しているだけ ですか? 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)

正しい?

そして、「これは本当の質問ではない」と急いでいる人のために...もう一度読んでください、私の質問は太字+斜体で表示されています

4

1 に答える 1

1

Q1. この方法で常に属性にアクセスできますか?

A: いいえ。2 つのアンダースコアで始まる属性のみです。クラス外からの偶発的なアクセス/オーバーライドを防ぐために、そのように難読化されます。

Q2:__init__ここで factor 引数のデフォルト値を変更しているだけですか?

A: はい。

Q2: そうですか?

右。

于 2009-09-27T08:49:53.890 に答える