Skip to main content
 首页 » 编程设计

python之和我一起破解混淆的 MultiplierFactory

2025年05月04日11zfyouxi

本周在 comp.lang.python 上,一段“有趣”的代码是 posted由 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 

从名称 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 是“一个元组,其中包含那些具有默认值的参数的默认参数值,或者如果没有参数具有默认值则为 None”。 我们只是在此处更改 factor argument in __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:不是。只有那些以双下划线开头的属性。它们以这种方式被混淆,以防止从类外意外访问/覆盖。

问题 2:我们只是在此处更改 __init__ 中因子参数的默认值吗?

答:是的。

Q2:对吗?

没错。