Python面向对象之封装
【一】什么是封装,为什么要封装
-
封装就是指,把数据与功能都整合到一起
-
就是将某些地方隐藏起来,在程序外部看不到,其他程序无法调用
-
-
封装最主要的原因就是为了保护隐私,将不想让用户看到的功能隐藏起来
-
封装的方法就是在变量名前面加 __
【二】封装隐藏属性
class Person:__NAME = "knight" def __init__(self):# 变形为self._Person__ageself.__age = 22 # 定义函数时,会检测函数语法,所以__开头的属性也会变形# 变形为_Foo__rundef __run(self):print('__f1 run') # 定义函数时,会检测函数语法,所以__开头的属性也会变形def walk(self):# 变形为self._Person__runself.__run() print(Person.N) #AttributeError: type object 'Person' has no attribute 'N' obj = Person() # print(obj.__x) # AttributeError: 'Person' object has no attribute '__x' # 数据属性 person = Person() print(person._Person__NAME) # 添加上person._Person 才能找到 # kinght # 函数属性 class Person:# 在变量名前面加 __ : 在类初始化对象的时候会对当前变量名进行变形 变形成 _Person__变量名__SCHOOL_NAME = '清华' def __init__(self, name):self.name = name # 函数属性 : 在类初始化对象的时候会对当前变量名进行变形 变形成 _Person__变量名def __change_name(self):self.name = 'nb_' + self.name student = Person(name='dream') print(student.name) # 查看类的民称空间 # {'_Person__SCHOOL_NAME': '清华','_Person__change_name': <function Person.__change_name at 0x000001D09384C0D0>,} print(Person.__dict__) print(student.__change_name()) # 当我们在对象中调用相关属性的时候会发现,找不到
-
补充
# 变形只发生在类初始化得到对象的时候 # 并且变形只会发生一次 print(student.name) # dream print(Person.__dict__) # {'__module__': '__main__', '_Person__SCHOOL_NAME': '清华', student.__SCHOOL_NAME = '北大' print(student._Person__SCHOOL_NAME) # 清华 print(Person.__dict__) # {'__module__': '__main__', '_Person__SCHOOL_NAME': '清华', print(student.__dict__) # {'name': 'dream', '__SCHOOL_NAME': '北大'} print(student.__SCHOOL_NAME) # 北大
【三】什么是开放接口
-
定义属性,并且隐藏属性或者方法是为了不然以后看到对应的功能和逻辑
-
但是要给用户提供修改的接口
class Teacher:def __init__(self,name,age):self.__name = nameself.__age = age def set_info(self,name,age):# 修改名字和修改年龄之前要校验当前格式是否正确# 名字前面必须 + lj_if not name.startswith('lj_'):raise ValueError('垃圾呢?')# 年龄必须是数字且大于0if not age.isdigit():raise ValueError('年龄是数字')if int(age) < 0 :raise ValueError('还没出生?')self.__name = nameself.__age = age # 做一个接口查看当前讲师的个人信息def tell_info(self):print(f"当前讲师是:{self.__name},年龄是:{self.__age}") teacher = Teacher(name='knight',age=20) # 修改当前姓名和年龄 teacher.set_info(name='lj_gdy',age='21') teacher.tell_info()
【四】小结
-
隐藏属性和开发接口本质上都是为了明确的区分内外,在类内部可以随意修改代码,但是在类外部不允许使用者修改代码
-
类外部只需要拿到一个接口,只要接口名不变,里面的逻辑可以随意实现
-
只要接口基础不变,代码可以任意修改
【五】什么是property
-
是一种特殊的属性,将函数的返回值作为数据属性返回
class Student:def __init__(self,name):self.name = name @property def vip_name(self):return self.name student = Student(name='knight') print(student.name) # knight print(student.vip_name) # knight # 没有property 的话函数就会输出 <bound method Student.vip_name of <__main__.Student object at 0x000001962556BA60>>
例:
class BMI:def __init__(self,name,weight,height): # __init__就等于是BMIself.name = nameself.weight = weightself.height = height @propertydef bmi(self):return self.weight / (self.height ** 2) knight = BMI(name='knight',weight=63,height=165) print(knight.bmi) # 0.0023140495867768596
-
为什么要使用property
(1)在所有编程语言中都有三种封装方式
public: 公开
protected:对外不公开但是对内公开
private:对谁都不公开
(2)上面三种封装方式就用到了我们的类中
class PersonOne(object):def __init__(self,name):self.name = name person_one = PersonOne(name='knight') print(person_one.name) # 查看 person_one.name = '666' # 修改 print(person_one.name) del person_one.name # 删除 print(person_one.name)
-
使用装饰器property
class Person(object):def __init__(self,name):self.__name = name# 给当前函数名添加装饰器 property# 将当前 函数名作为一个数据属性返回@propertydef vip_name(self):# 返回值可以是字符串也可以是其他内容return self.__name#修改,函数名一致,后面加.setter@vip_name.setterdef vip_name(self,value):# print(value)self.__name = value # 删除,函数名不变,后面加.deleter# 删除当前变量名的时候会触发@vip_name.deleterdef vip_name(self):del self.__name # 查看 person =Person(name='knight') print(person.vip_name) # 修改 person.vip_name = 'hyt' print(person.vip_name) # 删除 del person.vip_name print(person.vip_name)