面向对象——访问限制


本章概述:python基础——面向对象之访问限制


一、私有属性和私有方法

在很多面向对象编程中,属性可以设置为私有属性,python中也是如此,但是python跟其他编程语言不同在于python并不从语法上严格保证私有属性的私密性,也就是说,虽然在python中设置了私有属性,但是实际上python只是对这个私有属性重新命名,在类的外部通过重命名后的变量名字任可访问到该私有属性。因此在python中针对私有属性的访问问题,程序员们会有一个共识——不要随便访问私有属性,访问对象属性统一通过对象方法去执行。python类中设置私有属性只需要在属性名字前加双下划线即可。

1
2
3
4
5
6
7
8
class Student:
def __init__(self,name,age):
self.__name=name
self.__age=age

s1=Student('z7sz',20)
print(s1.__name) #这一行会报错,__name是私有属性,无法在外部直接访问
print(s1._Student__name) #这一行不会报错并且可以得到属性值,但是最好不要这么做

python中的私有方法跟私有属性是一样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student:
def __init__(self,name,age):
self.__name=name
self.__age=age

def __get(self):
return f'{self.__name}:{self.__age}'

def get(self):
return self.__get()

print(s1.get())
print(s1._Student__get())

上面两行print都能执行成功,但是第二种方式最好不要这么做。

二、property装饰器

前面说了因为私有属性的缘故,使得我们不能够像访问属性的方式来获取值,也不能像直接给私有属性赋值,因此我们通常都会另外写获取和赋值的函数来代替直接通过对象.属性名的方式来操作属性。但是这样毕竟没有直接通过对象.属性名方便,因此property装饰器负责把一个方法变成属性调用,这样就使得我们从对象.方法名()的方式变成对象.属性名的方式来操作属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student:
def __init__(self,name):
self.__name=name
def get_name(self):
return self.__name

def set_name(self,name):
if not isinstance(name,str): #name必须为字符串
raise ValueError('name must be an str!')
self.__name=name

s=Student('z7sz')
s.set_name('z7sz1')
print(s.get_name())

上面这种方式是不通过装饰器,通过方法来访问数据的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

class Student_p:
def __init__(self,name):
self.__name=name

@property
def name(self):
return self.__name

@name.setter
def name(self,name):
if not isinstance(name,str): #name必须为字符串
raise ValueError('name must be an str!')
self.__name=name

s1=Student_p('blog')
print(s1.name) #直接通过'对象.属性'访问数据
s1.name='blog1' #直接赋值
print(s1.name)

@property涉及到两个方面,本身可以将getter方法变成属性,也就是读取的方法,@property本身又创建了另一个装饰器@xxx.setter,负责把一个setter方法变成属性赋值。所以在上面的代码中@property装饰器可以直接读取数据,@name.setter可以赋值。

而且通过该装饰器还可以实现某属性只读不写的功能,只写@property装饰器不写@name.setter则可以实现name属性的只读不写。

装饰器会在后面详细讲,在面向对象内容的装饰器大家可以先记得怎么用。

三、__slots__ 魔法变量

上面的私有属性+装饰器实现了类中私有属性不能随便被读写,但是外部可以随意像类中写入属性。因此__slots__变量,可以用来限制class实例能添加的属性。

1
2
3
4
5
6
7
class A:
__slots__=('name','age') #实例只能添加这两个属性

a=A()
a.name='zsz'
a.age=14
a.sex=1 #这里会报错,因为A不允许实例添加除name和age之外的属性