封装
什么是封装
对外部隐藏内部的属性,以及实现细节,给外部提供使用的接口。 注意:封装有隐藏的意思,但不是单纯的隐藏
为什么封装
1,提高安全性。2,隔离复杂度
学习封装的目的,就是为了能够限制外界对内部的数据的访问。python中属性的权限有两种:
1》公开的:没有 任何限制,谁都能访问
2》私有的:只有当前类本身可以用
# 案例:怎样进行封装
class Student:
def __init__(self,name,age,gender,id_card):
self.name = name
self.age = age
self.gender = gender
self.__id_car = id_card
def show_id_card(self): #进行封装,访问一个私有被封装的方法
# 可以在这里添加额外的任何逻辑代码,来限制外部的访问
print(self.__id_card) #完成封装 封装的方法
stu1 = Student("rose",20,",man","1111111111111111111")
print(stu1.name) #结果为 rose
# print(stu1.__id_card) #这样访问不了id_card ,报错
print(Student.__id_card) #这样可以访问,结果为rose,即只有当前类本身能够访问
stu1.show_id_card() #结果为 rose
# ##########
# 封装属性:提现了安全性
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): #进行封装,访问一个私有被封装的方法
# 可以在这里添加额外的任何逻辑代码,来限制外部的访问
print(self.__id_card)
return self.__id_card
#修改被封装的属性 称之为设置器
def set_id_card(self,new_id): #从外界传入一个新的值
#案例:身份证号码必须是字符串类型,长度必须是18位
if isinstance(new_id, str) and len(new_id) ==18:
self.__id_card = new_id
else:
print("身份证号码错误,必须是字符串,且长度必须为18")
self.__id_car = new_id
stu1 = Student("rose", 20, ",man", "1111111111111111111")
stu1.show_id_card()
# stu1.set_id_card("22222222222222")
# stu1.show_id_card()
id = stu1.get_id_card()
print(id)
stu1.set_id_card(123) #结果为:身份证号码错误,必须是字符串,且长度必须为18
stu1.set_id_card("123456789987654321")
print(stu1.get_id_card()) #结果为123456789987654321
# 总结:在set_id_card中可以增加限制,和满足你所需求的功能,对其封装的进行修改
# 同理。在get_id_card中也可以怎加限制,例如判断满足的条件,判断合法就访问,对其用户进行了限制
# 目的:是为了保证安全性。除了可以封装属性,还可以封装方法
# 封装方法:体现了隔离复杂度
class ATM:
def withdraw(self):
self.__user_auth()
self.__input_money()
self.__save_record()
def __user_auth(self):
print("请输入账号密码...")
def __input_money(self):
print('请输入取款金额,余额为10000元')
def __save_record(self):
print("记录流水")
atm = ATM()
atm.withdraw()
# 总结:1,什么样的方法应该被封装起来:
# 一个为内部提供支持方法,不应该让外界直接访问,就把它藏起来,如上例中的__user_auth
#如何封装的:封装原理
# 就是把名字做了修改,通过修改名字的方法,即变形
# 如何变形,就是在名称带有双下划线开头的变量名字前加了_类名 如_Person_id_card
# 注意:变形这个操作是在定义类的时候发生的,只发生一次,
# 后续再添加的带有双下划线的任何属性,都将不会变形
#什么时候应该封装属性:
# 如银行卡密码,这种属性就不能直接被外界使用,要封装起来
class Teacher:
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.__salary = salary
@property
def get_salary(self):
return self.__salary
def set_salary(self, new_salary):
self.__salary = new_salary
t =Teacher("fee",23,16000)
print(t.get_salary())
t.set_salary(20000)
print(t.get_salary())
print(t.name)
# 出现的问题:被封装的属性在访问时,需要调用方法,而普通属性直接点就ok
# 这样一来对于使用者而言,必须要知道访问的属性,是私有还是公开,
# 然后调用对象的方法比较麻烦的。此时,我们的目标是,让访问的私有属性
# 和访问普通属性的方式一致,这时候就需要property装饰器,就是将一个私有的伪装成共有的
class Student:
def __init__(self,name,age,gender,id_card):
self.name = name
self.age = age
self.gender = gender
self.__id_car = id_card
def show_id_card(self): #进行封装,访问一个私有被封装的方法
# 可以在这里添加额外的任何逻辑代码,来限制外部的访问
print(self.__id_card) #完成封装 封装的方法
stu1 = Student("rose",20,",man","1111111111111111111")
print(stu1.name) #结果为 rose
# print(stu1.__id_card) #这样访问不了id_card ,报错
print(Student.__id_card) #这样可以访问,结果为rose,即只有当前类本身能够访问
stu1.show_id_card() #结果为 rose
# ##########
# 封装属性:提现了安全性
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): #进行封装,访问一个私有被封装的方法
# 可以在这里添加额外的任何逻辑代码,来限制外部的访问
print(self.__id_card)
return self.__id_card
#修改被封装的属性 称之为设置器
def set_id_card(self,new_id): #从外界传入一个新的值
#案例:身份证号码必须是字符串类型,长度必须是18位
if isinstance(new_id, str) and len(new_id) ==18:
self.__id_card = new_id
else:
print("身份证号码错误,必须是字符串,且长度必须为18")
self.__id_car = new_id
stu1 = Student("rose", 20, ",man", "1111111111111111111")
stu1.show_id_card()
# stu1.set_id_card("22222222222222")
# stu1.show_id_card()
id = stu1.get_id_card()
print(id)
stu1.set_id_card(123) #结果为:身份证号码错误,必须是字符串,且长度必须为18
stu1.set_id_card("123456789987654321")
print(stu1.get_id_card()) #结果为123456789987654321
# 总结:在set_id_card中可以增加限制,和满足你所需求的功能,对其封装的进行修改
# 同理。在get_id_card中也可以怎加限制,例如判断满足的条件,判断合法就访问,对其用户进行了限制
# 目的:是为了保证安全性。除了可以封装属性,还可以封装方法
# 封装方法:体现了隔离复杂度
class ATM:
def withdraw(self):
self.__user_auth()
self.__input_money()
self.__save_record()
def __user_auth(self):
print("请输入账号密码...")
def __input_money(self):
print('请输入取款金额,余额为10000元')
def __save_record(self):
print("记录流水")
atm = ATM()
atm.withdraw()
# 总结:1,什么样的方法应该被封装起来:
# 一个为内部提供支持方法,不应该让外界直接访问,就把它藏起来,如上例中的__user_auth
#如何封装的:封装原理
# 就是把名字做了修改,通过修改名字的方法,即变形
# 如何变形,就是在名称带有双下划线开头的变量名字前加了_类名 如_Person_id_card
# 注意:变形这个操作是在定义类的时候发生的,只发生一次,
# 后续再添加的带有双下划线的任何属性,都将不会变形
#什么时候应该封装属性:
# 如银行卡密码,这种属性就不能直接被外界使用,要封装起来
class Teacher:
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.__salary = salary
@property
def get_salary(self):
return self.__salary
def set_salary(self, new_salary):
self.__salary = new_salary
t =Teacher("fee",23,16000)
print(t.get_salary())
t.set_salary(20000)
print(t.get_salary())
print(t.name)
# 出现的问题:被封装的属性在访问时,需要调用方法,而普通属性直接点就ok
# 这样一来对于使用者而言,必须要知道访问的属性,是私有还是公开,
# 然后调用对象的方法比较麻烦的。此时,我们的目标是,让访问的私有属性
# 和访问普通属性的方式一致,这时候就需要property装饰器,就是将一个私有的伪装成共有的
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, a):
print(a)
t = Teacher("WWW",22,11111)
t.salary = 500
print(t.salary)
print(t.__dict__)
#通常使用 @property来访问私有的,希望将私有属性变为普通属性访问
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, a):
print(a)
t = Teacher("WWW",22,11111)
t.salary = 500
print(t.salary)
print(t.__dict__)
#通常使用 @property来访问私有的,希望将私有属性变为普通属性访问
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
import abcclass Animal(metaclass=abc.ABCMeta): #同一类事物:动物 @abc.abstractmethod def talk(self): pass
class People(Animal): #动物的形态之一:人 def talk(self): print('say hello')
class Dog(Animal): #动物的形态之二:狗 def talk(self): print('say wangwang')
class Pig(Animal): #动物的形态之三:猪 def talk(self): print('say aoao')
hasattr 判断是否存在某个属性
getattr 获取某个属性的值
setattr 新增或修改某个属性
delattr 删除某个属性
class MY_CMD:
def dir(self):
os.system("dir")
os.system("dir")
def ipconfig(self):
os.system("ipconfig")
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....!")
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 即导入成功的模块
"""
该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类
直接写import 称之为静态导入 建立在一个基础上:提前已经知道有这个模块
动态导入 指的是 在需要的任何时候 通过指定字符串类型的包名称来导入需要的模块
import importlib
mk = importlib.import_module(m_name)
mk 即导入成功的模块
"""
该方式常用在框架中 因为框架设计者不可能提前预知后续需要的模块和类