質問

今週の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

名前から 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__)

の初期化中 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