📜  Python中的私有变量

📅  最后修改于: 2022-05-13 01:55:35.697000             🧑  作者: Mango

Python中的私有变量

先决条件: Python中的下划线
在Python中,不存在只能在对象内部访问的“私有”实例变量。然而,大多数Python代码和编码器都遵循一个约定,即,一个带有下划线前缀的名称,例如_geek应该被视为 API 或任何Python代码的非公共部分,无论它是函数还是方法,或数据成员。在经历这个过程时,我们还将尝试理解各种形式的尾随下划线的概念,例如,for _ in range(10), __init__(self)。

重整及其工作原理

在Python中,有一种叫做名称修饰的东西,这意味着对类私有成员的有效用例的支持有限,基本上是为了避免名称与子类定义的名称发生名称冲突。 __geek 形式的任何标识符(至少两个前导下划线或最多一个尾随下划线)都将替换为 _classname__geek,其中 classname 是当前类名,前导下划线被去除。只要它出现在类的定义中,这种修饰就完成了。这有助于让子类覆盖方法而不破坏类内方法调用。
让我们看一下这个例子,并尝试找出这个下划线是如何工作的:

Python
# Python code to illustrate how mangling works
class Map:
    def __init__(self, iterate):
        self.list = []
        self.__geek(iterate)
    def geek(self, iterate):
        for item in iterate:
            self.list.append(item)
 
    # private copy of original geek() method
    __geek = geek  
 
class MapSubclass(Map):
     
    # provides new signature for geek() but
    # does not break __init__()
    def geek(self, key, value):       
        for i in zip(keys, value):
            self.list.append(i)


Python
# Python code to illustrate
# how single underscore works
def _get_errors(self):
    if self._errors is None:
        self.full_clean()
    return self._errors
 
errors = property(_get_errors)


Python
# Python code to illustrate how double
# underscore at the beginning works
class Geek:
    def _single_method(self):
        pass
    def __double_method(self): # for mangling
        pass
class Pyth(Geek):
    def __double_method(self): # for mangling
        pass


Python
# Python code to illustrate double leading and
# double trailing underscore works
class Geek:
 
    # '__init__' for initializing, this is a
    # special method 
    def __init__(self, ab):
        self.ab = ab
 
    # custom special method. try not to use it
    def __custom__(self):
        pass


修改规则的设计主要是为了避免事故,但仍然可以访问或修改被认为是私有的变量。这甚至在特殊情况下很有用,例如在调试器中。

_单前导下划线

因此,基本上方法、函数或数据成员开头的下划线意味着您不应该访问此方法,因为它不是 API 的一部分。让我们看一下这段代码:

Python

# Python code to illustrate
# how single underscore works
def _get_errors(self):
    if self._errors is None:
        self.full_clean()
    return self._errors
 
errors = property(_get_errors)

该片段取自 Django 源代码 (django/forms/forms.py)。这表明错误是属性,也是 API 的一部分,但方法 _get_errors 是“私有的”,因此不应访问它。

__双前导下划线

一开始,两条下划线引起了很多混乱。这是关于语法而不是约定。双下划线将破坏类的属性名称,以避免类之间的属性名称冲突。例如:

Python

# Python code to illustrate how double
# underscore at the beginning works
class Geek:
    def _single_method(self):
        pass
    def __double_method(self): # for mangling
        pass
class Pyth(Geek):
    def __double_method(self): # for mangling
        pass

__双前导和双尾下划线__

还有另一种双前导和尾随下划线的情况。我们在使用特殊变量或方法(称为“魔术方法”)时遵循这一点,例如 __len__、__init__。这些方法为名称提供了特殊的句法特征。例如,__file__ 表示Python文件的位置,__eq__ 在执行 a == b 表达式时执行。

例子:

Python

# Python code to illustrate double leading and
# double trailing underscore works
class Geek:
 
    # '__init__' for initializing, this is a
    # special method 
    def __init__(self, ab):
        self.ab = ab
 
    # custom special method. try not to use it
    def __custom__(self):
        pass