一 、属性隐藏
封装 : 数据和功能组成到一起就是封装
一 隐藏数据属性
class Stu_date():
def __init__(self,x,y,z):
self.name = x
self.age = y
self.__gender = z # 变形stu_obj1._Stu_date__gender
school = 'old'
def __choose(self): # 变形 _Stu_date__choose
print('%s 选课。。。'%self.name)
stu_obj1 = Stu_date('zhangsan',19,'male')
stu_obj1.choose()
在类或者对象的属性前添加 __shuxing ,该属性就是被隐藏了。无法通过对象名和类名访问,
class Stu_date():
def __init__(self,x,y,z):
self.__name = x
self.__age = y
self.__gender = z # 变形stu_obj1._Stu_date__gender
school = 'old'
def __choose(self): # 变形 _Stu_date__choose
print('%s 选课。。。'%self.name)
def get_info(self):
print(self.__name,self.__age,self.__gender) #也变成了stu_obj1._Stu_date__gender
stu_obj1 = Stu_date('zhangsan',19,'male')
stu_obj1.get_info()
通过代码可以看到该隐藏是 对外不对内的,对外隐藏,对内不隐藏
为什么能对外不对内的???其实是在定义阶段,扫描语法 名字发生了变形,把__name ,变成了 obj1.Stu_date_name 了
作用是 在继承中,父类如果不想让子类覆盖自己的方法,可以使用这个方法进行定义为私有方法
隐藏属性的核心意义是什么??
1、把属性隐藏起来的意义,在类内开放接口,让外来使用者通过接口来操作属性值,我们可以在接口上附加任意的判断,来严格控制使用者对对象属性值的操作。
class Stu_Date():
def __init__(self,x,y,z):
self.__name = x
self.__age = y
self.__gender =z
__school = 'old'
def set_school(self,school_name):
if type(school_name) is str:
Stu_Date.__school = school_name
else:
print('必须是str')
def set_info(self,name,age,gender='male'):
if type(name) is str:
self.__name=name
else:
print('必须是str')
if type(age) is int:
self.__age=age
else:
print('必须是int')
if type(gender) is str:
self.__gender=gender
else:
print('必须是str')
def get_info(self):
print(self.__school,self.__name,self.__age,self.__gender)
stu_obj1 = Stu_Date('zhangsan',19,'male')
stu_obj1.set_info(name='lisi',age=20)
stu_obj1.set_school('panggezhuang')
stu_obj1.get_info()
把函数属性隐藏起来,是为了隔离复杂度
实际意义 :在类中,一个功能是有N个函数对象组成,那么诸多的小功能是为了完成大功能而存在,所以小功能函数就不在提供给外来者调用
打个比方,电脑开机,按下开机键,一直到桌面出现,类似于 一个开机键封装了N个小功能,而外来者只需要按下开机键即可。这个就是隔离复杂度的体现。
二 属性值变更控制 装饰器 perperty 类函数转变成类属性的功能
装饰器 property
把类函数转变成类属性的功能,比如
class people():
def __init__(self,name,weight,height):
self.name=name
self.weight = weight
self.heigh=height
@property
def bmi(self): # people1.bmi 看代码是一个对象的属性,但是加()却是一个功能,
# 而这个对象属性为了不让外来人迷惑,所以必须变形成属性的样子
# 加上1
return self.weight /(self.heigh **2)
people1= people('张三',184,90)
# print(people1.bmi())
print(people1.bmi)
把类属性 通常在实例化对象后,生成了对象属性和类属性,通过加下划线 __name __school 的方法,变形隐藏起来,仅提供给类内函数的使用。
问题1 通过perpenty可以把类函数变形成类的属性,如何防止修改和删除,变形后的类属性本质还是函数,是不能够删除的
问题2 类属性和函数属性必须要给外界使用,如何防止被调用者随意赋值、和 删除?
问题1 解答
class StuDate():
def __init__(self,name,age):
self.name = name
self.__age =age
def get_age(self):
return self.__age *12
def set_age(self,x):
print('not set')
def del_age(self):
print('not del')
age = property(get_age,set_age,del_age)
stu_obj1=StuDate('zhangsan',10)
print(stu_obj1.age)
stu_obj1.age =12
del stu_obj1.age
问题2 解答
class StuDate():
def __init__(self,name,age):
self.name = name
self.__age =age
def get_age(self): # 查看对象的属性
return self.__age
def set_age(self,x): # 修改对象的属性,类型已认证,修改成功
if type(x) is not int:
print('不能修改')
return
else:
self.__age=x
def del_age(self): # 删除对象的属性,不允许删除,失败
print('不能删除')
age = property(get_age,set_age,del_age)
stu_obj1 = StuDate('zhangsan',18)
print(stu_obj1.age) # 查看对象的属性
stu_obj1.age =10 # 修改对象的属性,类型已认证,修改成功
stu_obj1.age ='111' # 修改对象的属性,类型认证错误,修改失败
print(stu_obj1.age)
del stu_obj1.age # 删除对象的属性,不允许删除,失败
通过上面的perperty装饰器,可以加强调用者对(类和对象)属性值的操作的控制,相当于对属性值的操作加上了一道筛子,只有经过确认的命令才能执行,
让对象属性和类属性不能够随意变更
升级 perpenty
在 在被装饰的"属性对象"上 添加功能
class StuDate():
def __init__(self,name,age):
self.name = name
self.__age =age
@property
def age(self):
return self.__age
@age.setter
def age(self,x):
if type(x) is not int:
print('不能修改')
return
else:
self.__age=x
@age.deleter
def age(self):
print('不能删除')
stu_obj1 = StuDate('zhangsan',18)
print(stu_obj1.age) # 查看对象的属性
stu_obj1.age =10 # 修改对象的属性,类型已认证,修改成功
stu_obj1.age ='111' # 修改对象的属性,类型认证错误,修改失败
print(stu_obj1.age)
del stu_obj1.age # 删除对象的属性,不允许删除,失败
三 绑定方法 + 装饰器 classmethod staticmethod
绑定方法的总结
1、默认是绑定是给对象,自动传对象名
2、指定绑定给类的,自动传类名 classmethod
3、非绑定方法,不绑定对象和类名 不自动传任何参数, staticmethod
class foo():
def __init__(self,x):
self.f = x
def f1(self):
pass
# <bound method foo.f1 of <__main__.foo object at 0x00000246E5CBA6A0>>
绑定给一个对象的方法,自动传对象名
@classmethod
def f2(cls):
pass
<bound method foo.f2 of <class '__main__.foo'>>
绑定给一个类的的方法 ,自动传类名
@staticmethod
def f3(x,y):
pass
<function foo.f3 at 0x00000267270AF1E0>
<function foo.f3 at 0x00000267270AF1E0>
是一个函数,谁都可以调用,不传任何形参
a1= foo(2)
print(a1.f1)
<bound method foo.f1 of <__main__.foo object at 0x00000246E5CBA6A0>>
绑定给一个对象的方法,
print(foo.f2)
<bound method foo.f2 of <class '__main__.foo'>>
绑定给一个类的的方法
print(foo.f3)
print(a1.f3)
<function foo.f3 at 0x00000267270AF1E0>
<function foo.f3 at 0x00000267270AF1E0>
是一个函数,谁都可以调用
通过上面的方法3种不同的绑定方法,扩大了函数的使用宽度。根据函数体代码的需求来选择的
可以根据业务场景划分不同的使用方法,
比如 在一个登陆mysql数据库实例中,
1、创建每一个调用者使用的事件ID,该场景不需要使用到对象名和类名,就可以使用 非绑定方法
2、创建一个自定义的对象属性,需要传入事件ID,IP,端口号,可以使用 默认绑定方法,因为要使用对象名
3、创建一个默认对象属性,需要从配置文件中读取,创建对象不需要传值,就是可以使用类的绑定方法,在类的内部自定完成对象属性的加载。
import uuid
import setting
class Mysql_Init():
def __init__(self,IP,PORT):
self.mid =self.creat() #2、非绑定方法 都可以调用,那么使用对象产生uuid
self.__ip = IP
self.__port = PORT
def get_info(self):
print('%s:<%s %s>'%(self.mid,self.__ip,self.__port))
# 4、创建一个自定义的对象属性,IP,端口号,可以使用 默认绑定方法,因为要使用对象名
@staticmethod
def creat():
return uuid.uuid4()
# 1、创建每一个调用者使用的事件ID,该场景不需要使用到对象名和类名,就可以使用 非绑定方法
@classmethod
def from_conf(cls):
return cls(setting.IP,setting.PORT) # 6、创建一个默认对象属性,需要从配置文件中读取,创建对象不需要传值,就是可以使用类的绑定方法,在类的内部自定完成对象属性的加载。
obj1 = Mysql_Init('127.0.0.1',3306) # 3、创建一个自定义的对象属性,IP,端口号,可以使用 默认绑定方法,因为要使用对象名
obj2= Mysql_Init.from_conf() # 5、创建一个默认对象属性,需要从配置文件中读取,创建对象不需要传值,就是可以使用类的绑定方法,在类的内部自定完成对象属性的加载。
obj1.get_info()
obj1 = Mysql_Init('127.0.0.1',3306)
# 根据这个代码可以看出 对象实例化需要的是 cls(func1,func2) , 使用classmethod配合函数返回, 默认配置的对象实例化。
总结: 函数体代码需要类名的,绑定给类
总结: 函数体代码需要对象名的,绑定给对象
总结: 函数体代码都不需要的,不绑定
一 定义一个people类,每个人的对象都有 名字 年龄 性别三个属性,分别完成对这3个属性的隐藏,开放接口,property伪装操作
在开放接口里严格控制赋值操作的数据类型问题
二 定义MySQL类
1、对象有ID,host,port 三个属性
3、定义工具creat_id ,在实例化时,为每个对象随机生成ID,保证id唯一
4、为对象定制方法,save和get_obj_by_id,save 能自动将对象序列化到文件中,文件的路径为配置文件中的DB_PATH ,文件名为id号,
保存之前,验证对象对象是否已存在,若存在抛异常; get_obj_by_id 方法用来从文件中反序列化出对象。