Python 函数前带有 single/double 下划线的命名约定是什么意思?
What does the Python naming convention with single/double underscore before a function mean?
我不确定如何表达我要问的问题,所以请随时更改标题。
目前,我正在处理现有的 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() 中。
通常,这种设计用于两个相关(但几乎相反)的模式,我不知道 "design patterns" 名称。 (我认为它们都包含 "engine",其中一个包含 "template",如果有帮助的话。)
首先,想法是允许子class 覆盖public 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
覆盖实现的 "non-core" 部分,它只有几行,而不覆盖 "core" 部分,它有数百行。
这种模式在 Python 中并不像在 Java 中那样常见,但它有时确实有意义。
另一方面,想法是让基础 class 将实现分解成单独的部分,每个部分都可以被子 class 覆盖,而无需替换其他所有部分。例如:
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()
那么,为什么要使用前导下划线?
前导单下划线表示"private by convention"。对于方法名称,特别是,* 它是一个提示 给人类 reader 某些东西不属于 API.任何想要使用 Pokemon
对象的人都不应该对其调用 _catch
,因为该方法是一个实现细节——它可能会在未来的版本中改变甚至消失,它可能会对对象的状态做出假设不能保证总是正确的,等等。但是 catch
应该总是可以安全调用。
通常这与您在 Java 或 C++ 中创建 protected
方法的东西非常匹配,这正是您在这些设计模式中使用的东西语言,即使它实际上并不意味着同一件事。
前导双下划线(没有尾随双下划线)意味着不同的东西。在方法名称或其他属性中,这意味着名称应该是 "mangled",这样 subclass 或 superclass 就更难意外地调用它,或者在需要时覆盖它改为定义和使用自己的私有名称。
通常,这非常适合您在 Java 或 C++ 中创建 private
方法或成员的内容,但它与 protected
.
* 在其他一些地方,它确实有更多的意义。例如,如果您未在 mod
.
中指定 __all__
,则 from mod import *
将跳过具有前导下划线的全局模块
我不确定如何表达我要问的问题,所以请随时更改标题。
目前,我正在处理现有的 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() 中。
通常,这种设计用于两个相关(但几乎相反)的模式,我不知道 "design patterns" 名称。 (我认为它们都包含 "engine",其中一个包含 "template",如果有帮助的话。)
首先,想法是允许子class 覆盖public 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
覆盖实现的 "non-core" 部分,它只有几行,而不覆盖 "core" 部分,它有数百行。
这种模式在 Python 中并不像在 Java 中那样常见,但它有时确实有意义。
另一方面,想法是让基础 class 将实现分解成单独的部分,每个部分都可以被子 class 覆盖,而无需替换其他所有部分。例如:
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()
那么,为什么要使用前导下划线?
前导单下划线表示"private by convention"。对于方法名称,特别是,* 它是一个提示 给人类 reader 某些东西不属于 API.任何想要使用 Pokemon
对象的人都不应该对其调用 _catch
,因为该方法是一个实现细节——它可能会在未来的版本中改变甚至消失,它可能会对对象的状态做出假设不能保证总是正确的,等等。但是 catch
应该总是可以安全调用。
通常这与您在 Java 或 C++ 中创建 protected
方法的东西非常匹配,这正是您在这些设计模式中使用的东西语言,即使它实际上并不意味着同一件事。
前导双下划线(没有尾随双下划线)意味着不同的东西。在方法名称或其他属性中,这意味着名称应该是 "mangled",这样 subclass 或 superclass 就更难意外地调用它,或者在需要时覆盖它改为定义和使用自己的私有名称。
通常,这非常适合您在 Java 或 C++ 中创建 private
方法或成员的内容,但它与 protected
.
* 在其他一些地方,它确实有更多的意义。例如,如果您未在 mod
.
__all__
,则 from mod import *
将跳过具有前导下划线的全局模块