面向對象深入
封裝
封裝是將類中的屬性或方法對外部隱藏,對外部提供接口用來輸出想要展示的信息
不封裝的情況下直接將類中的屬性展示出來,可以被隨意修改。但是封裝之後對外界只提供接口來輸出
數據,提高了安全性。
首先可以對屬性進行封裝
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 get_id_card(self,pwd): # 可以在这里添加额外的任何逻辑代码 来限制外部的访问 # 在类的内部 可以访问 if pwd =="123": return self.__id_card raise Exception("密码错误!")
對方法也可以進行封裝
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("记录流水....")
封裝的原理:
python是通过 变形的方式来实现的封装
如何变形 在名称带有双下划线开头的变量名字前添加_类名 如_Person__id_card
当然通过变形后的名字可以直接访问被隐藏的属性 但通过不应该这么做
变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形 就是普通属性
property的另一種使用場景
一個屬性他得值不是固定的,而是通過運算動態產生的
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 不支持自定义.....")
多態
多態指的是不同類型對象可以相應同一種方法而產生不同效果
鴨子類型就是典型的多態,多種不同的類型使用方法一樣
class Cat(): def bark(self): print("喵喵喵") def run(self): print("四条腿跑!") def sleep(self): print("趴着睡!") class Pig(): def bark(self): print("哼哼哼!") def run(self): print("四条腿跑!") def sleep(self): print("侧躺着睡!")
常用的内置函數
__str__
使用:如: class Car: def __init__(self, newWheelNum, newColor): self.wheelNum = newWheelNum self.color = newColor def __str__(self): msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..." return msg def move(self): print('车在跑,目标:夏威夷') BMW = Car(4, "白色") #嘿。。。我的颜色是白色我有4个轮胎...
在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法
当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
__del__
当对象被删除前会自动调用 该方法
声明时候会删除对象?
1.程序运行结束 解释器退出 将自动删除所有数据
2.手动调用del 时也会删除对象
假设要求每一个person对象都要绑定一个文件 class Person: def __init__(self,name,path,mode="rt",encoding="utf-8"): self.name = name self.file = open(path,mode,encoding=encoding) # 读取数据的方法 def read_data(self): return self.file.read() def __del__(self): print("del run!") self.file.close()
反射
反射是通過字符串來操作對象屬性
1.hasattr(object, name):可以查看前面的元素是否拥有后面的元素,后面的元素要用引号包裹,前面不需要。
但是这里必须要实例化,如果是hasattr(Foo,‘name’)报False.
2.getattr(object, name[, default]): 根据括号的元素拿到相应的值,getattr(l1,l2),也就是如果后面的元素属于前面,那么会取出l1.l2的值。如果不是那就报错。
如果getattr(l1,'l2')尾部再加上'加上某些东西',例:gerattr(l1,'l2','l3'),如果是错误了那么会显示最后双引号里面的东西,也就是l3,如果是正确则不会显示,只会显示正确的答案。
class Base(): def __init__(self,name,id): self.id=id self.name=name def show(self): print('id:%s,name:%s'%(self.id,self.name))
b1=Base('aaa',12)
print(getattr(b1,'name'))
==》aaa
3.setattr(object, name, value) :给object对象的name属性赋值value,如果对象原本存在给定的属性name,则setattr会更改属性的值为给定的value;如果对象原本不存在属性name,setattr会在对象中创建属性,并赋值为给定的value;
4.delattr(object, name) : 函数作用用来删除指定对象的指定名称的属性,和setattr函数作用相反。
class MY_CMD: def dir(self): os.system("dir") def ipconfig(self): os.system("ipconfig") cmd = MY_CMD() while True: name = input("请输入要执行的功能:") if hasattr(cmd,name): method = getattr(cmd,name) print(method) method() else: print("sorry this method is not exists....!")
動態導入
直接写import 称之为静态导入 建立在一个基础上:提前已经知道有这个模块
动态导入 指的是 在需要的任何时候 通过指定字符串类型的包名称来导入需要的模块
import importlib
mk = importlib.import_module(m_name)
mk 即导入成功的模块
补充
__getattr__:当对象获取自己没有的属性的时候自动触发
__setattr__:当对象想要给某个属性赋值时,如” user.id=11“