本周在 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:对吗?
没错。
关于python - 和我一起破解混淆的 MultiplierFactory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1483085/