封装(三大特性)
# 简介
简单的理解封装(Encapsulation),即在设计类时,刻意地将一些属性和方法隐藏在类的内部,这样在使用此类时,将无法直接以“类对象.属性名”(或者“类对象.方法名(参数)”)的形式调用这些属性(或方法),而只能用未隐藏的类方法间接操作这些隐藏的属性和方法。
类封装好处:
- 首先,封装机制保证了类内部数据结构 (opens new window)的完整性,因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。
- 对类实现良好的封装,用户只能借助暴露出来的类方法来访问数据,我们只需要在这些暴露的方法中加入适当的控制逻辑,即可轻松实现用户对类中属性或方法的不合理操作。
- 对类进行良好的封装,还可以提高代码的复用性。
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:
- 将内容封装到某处
- 从某处调用被封装的内容
# 如何进行封装
和其它面向对象的编程语言(如 C++、Java)不同,Python 类中的变量和函数,不是公有的(类似 public 属性),就是私有的(类似 private),这 2 种属性的区别如下:
- public:公有属性的类变量和类函数,在类的外部、类内部以及子类(后续讲继承特性时会做详细介绍)中,都可以正常访问;
- private:私有属性的类变量和类函数,只能在本类内部使用,类的外部以及子类都无法使用。
但是,Python 并没有提供 public、private 这些修饰符。为了实现类的封装,Python 采取了下面的方法:
- 默认情况下,Python 类中的变量和方法都是公有(public)的,它们的名称前都没有下划线(_);
- 如果类中的变量和函数,其名称以双下划线“__”开头,则该变量(函数)为私有变量(私有函数),其属性等同于 private。
封装:
- 私有化属性、私有化方法
- 定义公有set和get方法
"""
封装实例 就是将属性私有化
"""
class CLanguage:
def setname(self, name):
if len(name) < 3:
raise ValueError('名称长度必须大于3!')
self.__name = name
def getname(self):
return self.__name
# 为 name 配置 setter 和 getter 方法
name = property(getname, setname)
def setadd(self, add):
if add.startswith("http://"):
self.__add = add
else:
raise ValueError('地址必须以 http:// 开头')
def getadd(self):
return self.__add
# 为 add 配置 setter 和 getter 方法
add = property(getadd, setadd)
# 定义个私有方法
def __display(self):
print(self.__name, self.__add)
def all(self):
# 访问私有方法
self.__display()
# 将name ,add 属性私有化
clang = CLanguage()
clang.name = "xxx"
clang.add = "http://c.biancheng.net"
print(clang.name)
print(clang.add)
print(clang.all)
xxx
http://c.biancheng.net
<bound method CLanguage.all of <__main__.CLanguage object at 0x0000017AA19FD280>>
CLanguage 将 name 和 add 属性都隐藏了起来,但同时也提供了可操作它们的“窗口”,也就是各自的 setter 和 getter 方法,这些方法都是公有(public)的。
不仅如此,以 add 属性的 setadd() 方法为例,通过在该方法内部添加控制逻辑,即通过调用 startswith() 方法,控制用户输入的地址必须以“http://”开头,否则程序将会执行 raise 语句抛出 ValueError 异常。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
封装实例 就是将属性私有化
__xxx = 1 # 私有属性
def setXXX(self,name): #set是加判断
if name是否符合条件
赋值
else:
不赋值
def getXXX(self): #通过get获取值
return self.__xxx
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 访问私有属性方法
- set 和 get 方法
- 使用装饰器的方式 @property: get @函数名.setter: set
- 通过_类__私有属性名
set 和 get 方法
class Student:
def __init__(self, name, age):
self.__name = name # 私有属性
self.__age = age
self.__scort = 99
# set 和 get方法
def setName(self, name): # 用set来设置,name的长度,小于等于6位的话就可以赋值
if len(name) <= 6:
self.__name = name
else:
print("名字输入有误")
def getName(self):
return self.__name
def __str__(self): #
return "姓名:{},年龄:{},成绩:{}".format(self.__name, self.__age, self.__scort)
p = Student("李小", 20)
p.setName("ffff") # set是用来修改
print(p.getName()) # get是用来获取
print(p)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
使用装饰器的方式
@property #其实就是get
def a():
pass
@a.setter #就是set
def b():
pass
class Student:
def __init__(self, name, age):
self.name = name
self.__age = age
# 先有get的,在用set的
@property
def age(self): # 其实就是get
return self.__age
@age.setter
def age(self, age): # 其实就是set
if age > 0 and age < 100:
self.__age = age
else:
print("输入有误")
def __str__(self):
return "姓名:{},年龄:{}".format(self.name, self.__age)
s = Student("李小小", 20)
print(s.age) # 获取私有属性
print(s)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
通过_类__私有属性名
class Stu(object):
def __init__(self):
self.__age = 99
s = Stu()
print(s._Stu__age) # 通过_类名__私有属性名 访问
# 查看创建对象里面的属性
print(dir(s)) # 查看里面的属性
print(s.__dir__()) # 查看里面的属性 和dir(p)一样
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
编辑 (opens new window)
上次更新: 2023/05/17, 23:08:21