我不确定如何说出我要问的问题,所以随时可以更改标题。
目前,我正在开发一个现有的python代码库,并遇到了这种" style"并希望了解使用它的好处。
例如,
Class Pokemon(object):
def __init__(self, name):
self.name = name
def _catch(self, pokeball):
''' actual implementation here'''
def catch(self, pokeball):
_catch(pokeball)
您可能会注意到对catch()函数的调用将被重新路由到_catch()函数。我理解在函数之前使用下划线可以防止意外覆盖函数。
编辑:我认为标题应该再次修改,我理解下划线意味着什么然而我不确定为什么我们使用catch()和_catch(),因为我们显然想用catch()公开函数但是决定将实现粘贴在_catch()中。答案 0 :(得分:3)
通常,这种设计用于两种相关(但几乎相反)的模式,我不知道“设计模式”的名称。 (我认为它们都包含“引擎”,如果有帮助,则包含“模板”。)
首先,我们的想法是允许子类覆盖公共catch
方法,比如在核心实现之前或之后添加一些额外的工作,但仍然调用_catch
做大部分工作的方法。例如:
Class Pokemon(object):
def __init__(self, name):
self.name = name
def _catch(self, pokeball):
''' actual implementation here'''
# hundreds of lines of complex code
print(pokeball)
return pokeball
def catch(self, pokeball):
print('Gotta catch em all')
return self._catch(pokeball)
class Pikachu(Pokemon):
def catch(self, pokeball):
print('Pikachu')
return self._catch(pokeball)
这允许Pikachu
覆盖实现的“非核心”部分,这只是几行,而不会覆盖“核心”部分,即数百行。
这种模式在Python中并不像在Java中那样常见,但它确实有意义。
另一方面,我们的想法是让基类将实现分解为单独的部分,每个部分都可以被子类覆盖,而不必替换其他所有部分。例如:
class Pokemen(object):
def catch(self, pokeball):
self._wake_up()
if not self._check_ready() return False
try:
return self._catch(pokeball)
except SillyError:
return False
finally:
self.consider_sleeping()
那么,为什么要使用领先的下划线?
领先的单一下划线意味着“按惯例私有”。对于方法名称,特别是 * ,它是人类读者的提示某些东西不是API的一部分。任何想要使用Pokemon
对象的人都不应该在其上调用_catch
,因为该方法是一个实现细节 - 它可能会在未来的版本中发生变化甚至消失,它可能会对对象的状态做出假设不保证总是如此,等等。但是catch
应始终可以安全地打电话。
这通常适合您在Java或C ++中使用protected
方法的东西,这正是您在这些语言中使用这两种设计模式的原因,即使它没有这真的意味着同样的事情。
领先的双下划线(没有尾随的双下划线)意味着不同的东西。在方法名称或其他属性中,这意味着名称应该被“修改”,以便当子类或超类意图定义和使用自己的私有名称时,它更难以意外地调用它或覆盖它。
通常情况下,这与您在Java或C ++中创建private
方法或成员的内容非常匹配,但它比protected
中的单个下划线更远。 / p>
*在其他一些地方,它实际上确实有更多的含义。例如,如果您未在from mod import *
中指定__all__
,则会mod
跳过带有前导下划线的模块全局。