在python中有时候会发现别人写的代码中会有一些函数或者变量是以下划线开头的,这些情况又主要出现在类中,其中既有单下划线,也有双下划线,这种以下划线开头的函数或者变量实际上就是代表“私有”的意思,在python中私有变量不需要额外的像其它某些语言中还需要使用private关键词,在python中使用下划线开始命名类中的函数或者变量即可表示私有。那么单下划线和双下划线开头的具体意义以及区别分别是什么呢?若有兴趣请看本文细细为您分析!
附上类使用专栏的其它文章的链接:
- python 类的使用(1) 之类使用的基本框架
- python 类的使用(2) 之类变量
- python 类的使用(3)之类中常用的三个装饰器@classmethod、@staticmethod、@property
- python 类的使用(4)之类常用的魔法方法
- python 类的使用(5)之类装饰器(类的装饰器和类作为装饰器)
- python 类的使用(6)之类的继承
- python 类的使用(7)之类的私有属性和方法 (类中以单下划线或双下划线开头的变量名或函数名)
以单下划线开头的函数或变量(类中)
以单下划线开头的函数或者变量实际上是伪私有,在类中定义的加单下划线的函数或者属性都是可以被类外部所访问到的。以单下划线开头的函数或变量的意义对我们来说就是虽说其能够被访问,但是最好不要访问(这种伪私有属性或方法的含义就是告诉我们使用这个类的人最好不要直接调用它)。
举个简单的例子:
class Animal:
_type = 'cute'
# 定义了一个以单下划线开头的类属性
def __init__(self):
self._age = 3
# 这里也有一个以单下划线开头的类属性
self.name = 'xiaobai'
def _show_info(self):
# 定义了一个以单下划线开头的函数
return self.name, self._age
a = Animal()
print(a._show_info(),a._type, a._age)
# 这里直接调用函数和直接调用两个属性
# 结果:('xiaobai', 3) cute 3
# 可以看到是像普通的属性或方法一样调用就行了
除了上面正常调用外,类的继承时父类的以单下划线开头的属性以及方法也都会被继承。在某些博客中看到说这种命名的方式在使用from module import 类名时会出错,但是我试了没什么问题,但也不知道是不是我有什么误解。
以双下划线开头的函数或变量(类中)
在一个类中,不乏有以双下划线包围的函数,这些函数之前我已经介绍过了,它们就是类的魔法方法,而单纯以双下划线开头的函数或变量代表的是python类中真正的私有方法或属性,这些方法或者属性在类的外部是不能被访问到的。也就是不能被以这种类名.__变量名
或类名__函数名
的形式被访问到,同时类的继承中,这些私有属性及私有方法也不能被继承,但在类的内部这些私有属性和方法是可以被访问到的,因此可以通过间接的方法来设置、访问这些私有变量或函数。
先看一个简单的例子:
class City:
def __init__(self):
self.__name = 'Beijing'
# 这里设置一个私有变量
self.area = 16410.54
def show_area(self):
print(self.area)
def __show_area(self):
print(self.area)
a = City()
a.show_area() # 结果:16410.54
a.__show_area() # 报错:'City' object has no attribute '__show_area'
print(a.__name) # 报错:'City' object has no attribute '__name'
# 根据上面的结果,确实是能看出以双下划线开头的属性和方法确实是真正的私有变量
# ok,接下来举个在类内部使用这些私有属性或方法的例子:
class City:
def __init__(self):
self.__name = 'Beijing'
# 这里设置一个私有变量
self.area = 16410.54
def __show_area(self):
return self.area
def show_name_and_area(self):
print(self.__name, self.__show_area)
def change_name(self, new_name):
self.__name = new_name
a = City()
a.show_name_and_area()
# 运行结果:Beijing 16410.54
a.change_name('BJ')
# 这里修改内部的私有变量
a.show_name_and_area()
# 运行结果:BJ 16410.54
# 私有变量被成功修改,可以看到在类的内部调用还是很有用的
# 接下来看一下在类继承时的情况:
class City:
def __init__(self):
self.__name = 'Beijing'
# 这里设置一个私有变量
self.area = 16410.54
def __show_area(self):
print(self.area)
class A:
pass
a = A()
a.__show_area() # 报错:'A' object has no attribute '__show_area'
print(a.area) # 结果:16410.54
print(a.__name) # 报错:'A' object has no attribute '__name'
# 可以根据上述结果证明类的继承时私有方法和属性是不会被继承的,
# 这也使继承时不易发生变量名或函数名的冲突
当然并不是说一定不能访问到私有变量,python中是使用name mangling技术处理类中函数或变量名的,即__name替换成 _class__name,在类外部这样调用就行了,如下:
# 接上个例子
a = City()
a._City__show_area()
当然这种使用方式是不推荐的,毕竟被设置为私有的变量或函数肯定是有原因的,因此正常情况下不要使用这种方式去调用。
不在类中的下划线在函数名或变量名两侧的情况
这种情况实际上较少出现,但是也简单说一下吧,其实它们就是普通的全局变量或者函数,可以在任意地方被调用,我尝试了一下在函数名或变量名的两侧加好几个下划线都没问题,都可以正常调用的,当然平常我们不会这样用(没什么意义,看起来也很乱)。但是有时候为了与python中的保留字不冲突,可能会加下划线来区分,如class_可以与class关键字区分开。