类的封装--访问限制
概念
面向对象语言的三大特征:封装, 继承, 多态 (鸭子模型)
python中不存在真正的多态
广义的封装: 类和函数定义本身就是封装的体现狭义的封装:一个类的某些属性,不希望外界直接访问,而是把这个属性私有化[只有当前类持有],然后暴露给外界一个访问的方法即可.
封装的本质:就是属性私有化的过程
封装的好处:提供了数据的复用性,保证了数据的安全性
举例:插排
在class内部可以有属性和方法,而外部的代码可以通过直接调用实例变量的方法来操作数据,这样就隐藏了内部的复杂逻辑。
但是从我们之前定义的class来看,外部代码还是可以自由的修改一个实例的name等属性。
使用
如果要让内部的属性不被外部访问,可以把属性名前加两个下划线,在python中以双下划线开头的变量就变成了一个私有的变量,只有内部可以访问,而外部不能访问。
class Person(object):
def __init__(self, name, age, height, money):
self.name = name
self.__age__=age
self.__money = money
修改完毕之后,对于外部的代码几乎没有变动,但是已经无法从外部访问money变量了
>>>per = Person("hanmeimei", 20, 170, 10000)
>>>per.__money
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__money'
这样就确保了外部的代码不能随意的修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。
但是,如果外部的代码需要获取money的属性的时候该怎么办呢?
我们可以通过getMoney与setMoney的方法来操作数据
class Person(object):
def run(self):
print(self.__money)
def eat(self):
print("eat",food)
def __init__(self, name, age, height, weight, money):
self.name = name
self.__age__=age
self.weight = weight
self.__money = money
#通过内部方法,去修改私有属性
#通过自定义的方法实现对私有属性的赋值与取值
#set方法:setxxx
def setMoney(self, money):
#数据的过滤
if money < 0:
money = 0
self.__money = money
#get方法:getXXX
def getMoney(self):
return self.__money
per = Person("hanmeimei", 20, 170, 55, 10000)
#1.属性被私有化之后的访问
#如果要让内部属性不被外部直接访问,在属性前加两个下划线(__),
#在python中如果在属性前面加两个下划线,name这个属性就变成了私有属性[private]
#私有属性的含义:在外界不能像以前那么直接访问
#print(per.__money) #无法在外界直接访问
per.run() #内部可以访问
#2.解决办法: 如何对私有属性取值和赋值
#但是,需要注意的是,在python找那个私有不是绝对的
#属性被私有化之后,可以通过get/set的方法进行访问
per.setMoney(10)
print(per.getMoney())
#4.特殊情况
#在Python中 __xxx__ 属于特殊变量,将不再属于私有变量,可以直接访问
print(per.__age__)
#在python中 _xxx变量,这样的实例变量外部是可以访问的,但是,按照约定的规则
#当我们看到这样的变量时,意思虽然是"虽然我可以被访问,但是请把我视为私有变量,不要直接访问我"
print(per._height)
双下划线开头的变量是不是一定不能够从外部访问呢?其实也不是。
# 不能直接访问per.__money是因为python解释器把__money变成了_Person__money
# 仍然可以使用_Person__money去访问,但是强烈不建议这么干,不同的解释器可能存在解释的变量名不一致
per = Person("hanmeimei", 20, 170, 55, 10000)
per._Person__money = 1
print(per.getMoney())
总的来说,python本身没有任何机制能够阻止你干坏事,一切靠自觉
注意:这种错误的写法
per = Person("hanmeimei", 20, 170, 55, 10000)
per.__money = 1
print(per.__money)
# 从表面上看,外部代码“成功的设置了__money”变量,
# 但是实际上这个__money变量和内部的__money变量不是同一个变量,而是外部的代码给per新增了一个变量
# 测试一下
print(per.getMoney())
单下划线,双下划线,头尾下划线的说明
'''
头尾下划线__foo__():定义特殊的方法,一般是系统定义名字,类似于__init__()
单下划线:_foo:以单下划线开头的表示是protected类型的变量,即保护类型的变量只允许本身与子类访问,
不能用于from module import *
双下划线:__foo:双下划线的表示的是私有类型(private)的变量,只能允许这个类的本身进行访问。
'''
练习
'''
需求:富二代开着骚红色玛莎拉蒂,很自豪的跟朋友炫耀...
分析:
汽车类:
特征:品牌,颜色
行为:在马路上奔驰
富二代类:
特征:姓名
行为:开车,炫耀
'''
form car import Car
from richman import RichMan
#1.创建富二代对象
man = RichMan("王思聪")
#2.创建汽车对象
car = Car("玛莎拉蒂","骚红色")
#富二代的行为
man.dirveCar(car)
man.showCar(car)
class Car(object):
#构造函数
def __init__(self,brand, color):
self.__brand = brand
self.__color = color
#get/set函数
def setBrand(self, brand):
self.__brand = brand
def getBrand(self,brand):
return self.__brand
def setColor(self, color):
self.__color = color
def getColor(self):
return self.__color
#成员函数
def run(self):
print("%s在马路上奔驰"%self.__brand)
class RichMan(object):
#构造函数
def __init__(self, name):
self.__name = name
#get/set函数
def setName(self, name):
self.__name = name
def getName(self):
return self.__name
#成员函数
def driverCar(self,car)
print("福二代%s开着他新车%s"%(self.__name, self.getBrand()))
def showCar(self,car)
print("很自豪的炫耀起来,你看这辆%s,你看这%s成色...."%(car.getBrand(), car.getColor()))