Python 类封装 property相关装饰器 接口抽象类abc模块 鸭子类型
1.公开的:
没有任何限制 谁都能访问
2.私有的:
只有当前类本身能够访问
默认为公共的
4.封装使用:
封装语法:
__属性名或方法名
封装属性 class Student: def __init__(self,name,age,gender,id_card): self.name = name self.age = age self.gender = gender self.__id_card = id_card def show_id_card(self): # 可以在这里添加额外的任何逻辑代码 来限制外部的访问 #注意:在类的内部 可以访问 print(self.__id_card) s = Student('jack',18,'man',32132111) # print(s.id_card) # 报错没有这个属性 # print(s.__id_card) # 报错内部封装了无法访问 s.show_id_card() # 32132111 通过函数在类内部访问拿到结果 s.__id_card = 1233 print(s.__id_card) # 1233 访问的不是原来被封装的属性,而是在对象中添加了__id_card print(s.__dict__) # 'name': 'jack', 'age': 18, 'gender': 'man', '_Student__id_card': 32132111, '__id_card': 1233}
class ATM: def withdraw(self): self.__user_auth() self.__input_money() self.__save_record() # 输入账号和密码 # 显示余额 # 输入取款金额 # 保存记录 def __user_auth(self): print("请输入账号密码....") def __input_money(self): print("余额为100000000,请输入取款金额!") def __save_record(self): print("记录流水....") a = ATM() # a.__user_auth() # 报错__user_auth()被封装了无法访问 # 通过内部直接访问 a.withdraw() # 请输入账号密码.... 余额为100000000,请输入取款金额! 记录流水....
5.封装的原理(不建议使用这种方式访问被封装的属性和方法)
python是通过 变形的方式来实现的封装 如何变形 在名称带有双下划线开头的变量名字前添加_类名 如_Person__id_card 当然通过变形后的名字可以直接访问被隐藏的属性 但通过不应该这么做 变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形 就是普通属性 class Student: def __init__(self, name, age, gender, id_card): self.name = name self.age = age self.gender = gender self.__id_card = id_card # 封装方法 def __say(self): print('hello') def show_id_card(self): # 可以在这里添加额外的任何逻辑代码 来限制外部的访问 # 在类的内部 可以访问 print(self.__id_card) s = Student('jack',18,'man',32132111) # print(s.__id_card) # 报错内部封装了无法访问 # print(s._Student__id_card) # 通过变形拿到结果32132111 (被封装的属性名其实变成了'_Student__id_card') s.show_id_card() # 32132111 通过函数在类内部访问拿到结果 # s.__id_card = 1233 # print(s.__id_card) # 1233 访问的不是原属性,而是在对象中添加了__id_card print(s.__dict__) # 'name': 'jack', 'age': 18, 'gender': 'man', '_Student__id_card': 32132111, '__id_card': 1233}
class Teacher: def __init__(self,name,age,salary): self.name = name self.age = age self.__salary = salary @property # getter # 用于访问私有属性的值 也可以访问普通属性 def salary(self): return self.__salary @salary.setter # 用来设置私有属性的值 也可以设置普通属性 def salary(self,new_salary): self.__salary = new_salary @salary.deleter # 用来设置私有属性的值 也可以删除普通属性 def salary(self): # print("can not delete salary!") del self.__dict__["_Teacher__salary"] t = Teacher('jack',18,1000) print(t.salary) # 1000 此处的salary是一个函数相当于t.salary()主要是用于访问被封装的属性和方法 与property相关的 两个装饰器 property 对象点被装饰的方法触发(一般用于获取封装属性的值) setter 用点语法 给属性赋值时触发 (一般用于设置,给对象设置属性) deleter 用点语法删除属性时触发 (一般用于删除属性的值)
class Person: def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight # self.BMI = weight / (height ** 2) @property def BMI(self): return self.weight / (self.height ** 2) @BMI.setter def BMI(self,new_BMI): print("BMI 不支持自定义.....") p = Person("egon",1.7,80) print(p.BMI) p.BMI = 10
接口是一组功能的集合,但是接口中仅包含功能的名字,不包含具体的实现代码
接口本质是一套协议标准,遵循这个标准的对象就能被调用
2.
class USB: def open(self): pass def close(self): pass def read(self): pass def write(self): pass class Mouse(USB): def open(self): print("鼠标开机.....") def close(self): print("鼠标关机了...") def read(self): print("获取了光标位置....") def write(self): print("鼠标不支持写入....") def pc(usb_device): usb_device.open() usb_device.read() usb_device.write() usb_device.close() m = Mouse() # 将鼠标传给电脑 pc(m)
3.
在上述案例中,PC的代码一旦完成,后期无论什么样的设备 只要遵循了USB接口协议,都能够被电脑所调用
接口主要是方便了对象的使用者,降低使用者的 学习难度,只要学习一套使用方法,就可以以不变应万变
问题:
如果子类没有按照你的协议来设计,也没办法限制他,将导致代码无法运行
指的是包含抽象方法(没有函数体的方法)的类, 用@abc.abstractmethod 装饰器
抽象类的特点:
不能直接实例化 必须有子类覆盖了所有抽象方法后才能实例化子类
接口是指只有方法声明而没有实现体 , 接口中所有方法都是抽象的
import abc class Test(metaclass=abc.ABCMeta): @abc.abstractmethod def say_hi(self): pass class TT(Test): def say_hi(self): print("i am TT obj") t = TT() t.say_hi()
class PC(): def conntent_device(self, usb_device): usb_device.open() usb_device.work() usb_device.close() class Mouse: # 实现接口规定的所有功能 def open(self): print("mouse opened") def work(self): print("mouse working...") def close(self): print("mouse closed") mouse = Mouse() pc = PC() pc.conntent_device(mouse) class KeyBoard: def open(self): print("KeyBoard opened") def work(self): print("KeyBoard working...") def close(self): print("KeyBoard closed") key1 = KeyBoard() # 如果key1的特征和行为都像USB设备 那就把它当做USB设备来使用 # 对于使用者而言可以不用关心这个对象是什么类,是如如何是实现, pc.conntent_device(key1)