私有化
1. 对于私有化的理解
_func
: 单前置下划线,私有化属性或方法。类对象和子类可以访问,但是无法通过from somemodule import *
导入。__func
: 双前置下划线,私有属性或方法。不能被外界访问,不会被子类继承。
我们先来看前置双下划线:
以前置双下划线定义的属性和方法,实例对象和子类无法调用和访问。
首先看看实例对象对于私有方法的访问权限:
class GrandFather():
def __init__(self):
self.name = "grandpa"
self.age = 80
# 私有属性
self.__money = 1000
# 私有方法
def __introduce(self):
print("My name is %s and age is %s" % (self.name, self.age))
return
# 通过实例方法调用私有化方法
def introduce(self):
self.__introduce()
return
g = GrandFather()
# 实例对象无法调用私有方法
g.__introduce() # 'GrandFather' object has no attribute '__introduce'
# 实例对象可以通过实例方法来调用私有化方法
g.introduce() # My name is grandpa and age is 80
print(g.name) # grandpa
print(g.age) # 80
# 实例对象无法访问私有属性
print(g.__money) # 'GrandFather' object has no attribute '__money'
因此我们得知,实例对象无法调用私有方法和访问私有属性。
那么接着看看子类对私有方法的权限:
# 定义子类继承GrandFa
class Father(GrandFather):
pass
f = Father()
# 子类可以调用父类的普通实例方法
f.introduce() # My name is grandpa and age is 80
# 子类无法调用父类的私有方法
f.__introduce() # 'Father' object has no attribute '__introduce'
print(f.name) # grandpa
print(f.age) # 80
# 子类无法访问父类的私有属性
print(f.__money) # 'Father' object has no attribute '__money'
因此我们同样可以知道,子类无法调用父类的私有方法和访问父类的私有属性。但是可以通过父类的实例方法来访问父类的私有属性和调用父类的私有方法。
那么私有属性的意义何在?
安全性,有时候我们创建一个类,这个类中我们定义了很多的属性和方法。而且这个类需要被别人导入进行使用,那么就可能有需要类中的一些属性和方法我们要求他是写死的,仅仅允许别人使用但是不允许他人篡改。因此就需要将这些属性和方法定义成为私有属性。这样,当别人调用你所编写的这个类的时候,如果想要使用私有属性或调用私有方法,就只能通过你所定义的普通方法对私有方法进行间接调用,这样就实现了用户只能调用你的私有方法,但是不能进行重写和更改。
就像上面的例子,我们仅仅希望用户得到GrandFather
的一些简介,但是不允许用户更改他的简介格式("My name is %s and age is %s"
)和他的money
。因此用户所拥有的权限仅仅是更改GrandFather
的姓名和年龄。而money
仅仅是能够做到通过间接手段进行访问而无法更改他的值。
但前置下划线:
单前置下划线在类中所定义的属性和方法,可以被实例对象和子类调用、更改、重写。因此看上去和普通的属性和方法没什么区别。
但是如果用但前置下划线去定义一个类,或者定义一个普通函数的时候,那么当别的py文件通过from somemodule import *
导入此文件的时候,以但前置下划线开头的类和方法是不会被导入的。
首先我们以但前置下划线定义一个类和一个方法,然后再本文件下运行它:
class _Person():
def intro(self):
print("hello")
def _intro():
print("hello...")
def test():
print("test")
if __name__ == '__main__':
p = _Person()
p.intro() # hello
_intro() # hello...
test() # test
接着创建另一个文件进行导入使用
# 上一个文件的名称为 “类”
from 类 import *
p = _Person() # name '_Person' is not defined
_intro() # name '_intro' is not defined
test() # test
可以看到,仅仅test()
被导入了。
那么我们指定导入的类和方法,则可以调用。
from 类 import _Person, _intro, test
p = _Person()
_intro() # helo...
test() # test
因此,目前为之,单下划线的作用好像就只是防止被import *
导入。可能还有别的作用,但是我没有了解到。
2. 为何访问不到私有化属性?
上面我们发现当对类中的一个属性或方法加上了前置双下划线则会变成私有属性和方法,实例对象和字类就访问不到了。这是为什么呢?
我们可以看一下:
class GrandFather():
def __init__(self):
self.name = "grandpa"
self.age = 80
self.__money = 1000
self._height = 20
def __introduce(self):
print("My name is %s and age is %s" % (self.name, self.age))
return
def introduce(self):
self.__introduce()
return
print(GrandFather.__dict__)
结果:
{'__module__': '__main__',
'__init__': <function GrandFather.__init__ at 0x03219030>,
'_GrandFather__introduce': <function GrandFather.__introduce at 0x03219108>,
'introduce': <function GrandFather.introduce at 0x03219390>,
'__dict__': <attribute '__dict__' of 'GrandFather' objects>,
'__weakref__': <attribute '__weakref__' of 'GrandFather' objects>,
'__doc__': None}
这里我们就发现,原来被__
定义的属性和方法,python都给他们改名了。
'_GrandFather__introduce'
, 再前面加上了_类名
。
那么我们就用这个方式来访问一下:
g = GrandFather()
g._GrandFather__introduce() # My name is grandpa and age is 80
print(g._GrandFather__money) # 1000
可以看到,私有属性也被成功访问了,而之前不能被访问的原因就是人家改名字了。。。