Python中的双下划线
在以下教程中,我们将讨论 双下划线 及其在Python编程语言中的使用。但在此之前,让我们简要讨论下划线的一些方面。
理解Python下划线
下划线(_)字符在Python中并不简单。 有许多编程语言只能在蛇形命名中使用下划线来命名函数和变量;然而,Python对下划线有更重要的用途。我们中的大多数人可能对以下语法比较熟悉:
for _ in range(20)
__init__(self)
- _ = 10
下划线(_)字符在不同的情况下传递不同的含义。
下划线的几个用途如下:
-
在解释器中使用下划线
- 使用下划线来忽略值
- 在循环中使用下划线
- 使用下划线来分隔数字的位数
- 使用下划线进行命名
然而,我们只会涵盖与双下划线一起使用的命名约定。
这些命名约定分为两种类型:
- 双前导下划线:
__var
- 双前导和尾随下划线:
__var__
因此,让我们开始吧。
理解双前导下划线
双前导下划线用于名称的修改。
双前导下划线的语法如下所示:
语法:
__var
双下划线告诉Python解释器,为了避免命名冲突,需要重新编写子类属性的名称。
名称修饰: Python解释器以一种在类继承过程中很难混淆的方式修改变量名称。
让我们来看一个基于这个功能的示例。
示例:1
# defining a class
class mySample():
# using the __init__() function
def __init__(self):
self.first = 10
self._second = 15
self.__third = 20
# instantiating the class
myObj = mySample()
# printing the directory of the object
print(dir(myObj))
输出:
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'_mySample__third',
'_second',
'first']
说明:
在上面的代码片段中,我们定义了一个类作为 mySample() ,并使用初始化函数声明了一些值。然后,我们使用 myObj 对象对该类进行了实例化。最后,我们打印了对象的目录。
因此,上述代码块返回了类对象的每个属性。现在,让我们观察一下属性列表中的变量。
变量 self.first 在列表中以原样出现。
变量 self._second 也以原样出现在列表中。
然而,在变量 self.__third 的情况下,我们可以观察到一些变化。
如果我们观察属性列表,我们会注意到一个名为 _mySample__third 的属性。这是一种名字重整的情况。它发生是为了避免在子类中覆盖该变量。
mySample
示例:
# defining a class
class mySample():
# using the __init__() function
def __init__(self):
self.first = 10
self._second = 15
self.__third = 20
# defining a child class
class AnotherClass(mySample):
def __init__(self):
super().__init__()
self.first = "Variable Overridden"
self._second = "Variable Overridden"
self.__third = "Variable Overridden"
# instantiating the child class
myobj = AnotherClass()
# printing the values of variables
print(myobj.first)
print(myobj._second)
print(myobj.__third)
输出:
Variable Overridden
Variable Overridden
Traceback (most recent call last):
File "D:\Python\ternarypy.py", line 24, in
print(myobj.__third)
AttributeError: 'AnotherClass' object has no attribute '__third'
解释:
在以上代码片段中,我们定义了一个名为 mySample() 的类,并使用初始化函数声明了一些变量。然后,我们定义了一个子类来继承mySample()类,并使用了super()函数来继承父类的变量并进行了覆盖。最后,我们实例化了子类并打印了覆盖变量的值。
结果是,前两个变量的消息成功打印出来;然而,在 “__third” 变量的情况下,程序引发了一个异常。这是由于名称改变导致的名称混淆,将 myObj.__third 改为_AnotherClass__third。
让我们考虑另一个示例,以便借助修改的属性来打印该元素。
示例:2
# defining a class
class mySample():
# using the __init__() function
def __init__(self):
self.first = 10
self._second = 15
self.__third = 20
# defining a child class
class AnotherClass(mySample):
def __init__(self):
super().__init__()
self.first = "Variable Overridden"
self._second = "Variable Overridden"
self.__third = "Variable Overridden"
# instantiating the child class
myobj = AnotherClass()
# printing the value(s) of variable(s)
print(myobj._AnotherClass__third)
输出:
Variable Overridden
解释:
在上面的代码片段中,我们可以观察到我们使用了 “_AnotherClass__third” 变量而不是 “__third” 变量来访问变量的值。
我们可以通过类中的方法访问双下划线变量。让我们考虑一个基于此功能的示例。
示例:3
# defining the class
class myClass:
# initializing function
def __init__(self):
self.__myVar = "Welcome"
# defining another method to return the variable
def get_Var(self):
return self.__myVar
# instantiating the class
myObj = myClass()
# it returns the "Welcome" which is a __var
print(myObj.get_Var())
# here, an error is raised as stated before. It alters the variable's name
print(myObj.__myVar)
输出:
Welcome
Traceback (most recent call last):
File "D:\Python\ternarypy.py", line 15, in
print(myObj.__myVar)
AttributeError: 'myClass' object has no attribute '__myVar'
解释:
在上面的代码片段中,我们定义了一个类并使用初始化函数声明了一个变量。然后,我们定义了一个方法来返回变量的值。最后,我们实例化了该类并使用两种方式打印了变量的值。结果是,程序在打印方法时返回了 “Welcome” 语句。然而,对于另一个方法,它修改了变量的名称,因此引发了异常。
我们也可以利用双下划线作为方法名前缀。让我们以这个功能为基础考虑一个示例。
示例:4
# defining a class
class myClass:
# defining a double-leading underscore function
def __myfunction(self):
return "Welcome"
# defining a function to call the above function
def call_function(self):
return self.__myfunction()
# instantiating the class
myObj = myClass()
# printing the value within the function
print(myObj.call_function())
# raised an error
print(myObj.__myfunction())
输出:
Welcome
Traceback (most recent call last):
File "D:\Python\ternarypy.py", line 14, in
print(myObj.__myfunction())
AttributeError: 'myClass' object has no attribute '__myfunction'
说明:
在上面的代码片段中,我们定义了一个在类中的双下划线后的函数。然后我们定义了另一个函数来调用该函数,并将结果打印给用户。
现在,我们来了解另一种名称改编的方式。 首先,我们将声明一个名为 _myClass__myVar 的变量,并尝试使用双下划线名称访问该变量。
让我们考虑以下示例:
示例: 5
# declaring a variable
_myClass__myVar = "Welcome"
# defining a class
class myClass:
# defining a function to return the declared variable
def call_function(self):
return __myVar
# instantiating the class
myObj = myClass()
# printing the value of the variable
print(myObj.call_function())
输出:
Welcome
解释:
在上面的代码片段中,我们声明了一个变量并定义了一个类。然后我们定义了一个函数来返回声明变量的值。最后,我们实例化了该类并调用该函数来打印该变量的值。
了解双下划线开头和结尾的含义
在像Python这样的编程语言中,我们会发现很多以双下划线开头和结尾的命名。这些命名约定被称为 魔术方法 或 双下划线方法 。
双下划线开头和结尾的语法如下所示:
语法:
__var__
让我们考虑一个基于魔术方法的示例。
示例:
# defining a class
class myClass:
# using a magic method
def __init__(self):
# using a magic method as variable name
self.__myNum__ = 10
# instantiating the class
myObj = myClass()
# printing the value of the variable
print(myObj.__myNum__)
输出:
10
解释:
在上述代码片段中,我们定义了一个类。我们在类中定义了一个魔法方法作为 __init__()
函数,也被称为初始化函数。然后我们声明了变量 __num__
。最后,我们实例化了这个类并打印出变量的值。结果,这个程序运行并输出了所需的结果。然而,将魔法方法作为变量名是不好的实践,因为这将导致命名冲突。因此最好避免使用它们。