封装
封装的介绍 1.什么是封装 ***** 装:往容器/名称空间里存入名字 封:代表将存放于名称空间中的名字给藏起来,这种隐藏对外不对内 2.为何要封装 封数据属性:??? 封函数属性:??? 3.如何封装 在类内定义的属性前加__开头
封装属性的意义 1.封装数据属性:将数据属性隐藏起来,类的外面就无法直接操作属性,怎么间接使用? 2.需要类内开辟一个接口来外部的使用可以间接地操作属性,可以在 3.从而严格控制使用对属性的操作
class People:
def __init__(self,name,age):
self.__name = name
self.__age = age
def tell_info(self):
print('name:%s age:%s'%(self.__name,self.__age))
def set_info(self,name,age):
if type(name) is not str:
print('名字必须为字符串')
return
if type(age) is not int:
print('年龄必须为数字')
return
self.__name = name
self.__age = age
obj=People('大海',18)
#严格的控制查看属性
#obj.__name
obj.tell_info() # 可以通过接口间接的访问到属性
# 严格的控制修改属性
# obj.__name = '夏洛'是修改不了的
#_People__name
# print(obj.__dict__)
obj.set_info('夏洛',16) #通过接口间接访问属性
# print(obj.__dict__)
obj.tell_info()
封装函数的意义 封装函数属性:隔离复杂度 # 间接的访问一些不需要使用者知道的方法
class ATM:
# 这些功能使用者没必要知道
# 也就是说把类的内部没必要让使用者知道的功能封装起来
def __card(self):
print('插卡')
def __auth(self):
print('用户认证')
def __input(self):
print('输入取款金额')
def __print_bill(self):
print('打印账单')
def __take_money(self):
print('取钱')
# 使用者只需要知道取款功能
# 在类内部开一个统一的接口按步骤依次调用就可以了
def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
a = ATM()
a.withdraw()
@property的使用
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值 例:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 成人的BMI数值: 过轻:低于18.5 正常:18.5-23.9 过重:24-27 肥胖:28-32 非常肥胖, 高于32 体质指数(BMI)=体重(kg)÷身高^2(m)
class People:
def __init__(self,name,weight,height):
self.name = name
self.weight = weight
self.height = height
@property
def bmi(self):
return self.weight / (self.height**2)
obj=People('大海',70,1.75)
bmi=obj.bmi
print(bmi)
反射
反射:通过字符串来反射/映射到对象/类的属性上 创建类
class People:
def __init__(self,name,age):
self.name = name
self.age = age
def run(self):
print('%s is running'%self.name)
obj=People('dahai',18)
name = '大海'
print(obj.__dict__)
所以用户输入的是一个字符串的形式,我们怎样把它变成属性名,就用到了反射 判断对象是否有属性,有就返回True,没有就算False
print(hasattr(obj,'name'))
print(hasattr(obj,'aaa'))
获取对象属性
print(getattr(obj,'name'))
# 第三个参数找不到返回None
print(getattr(obj,'xxx',None))
修改属性
setattr(obj,'name','dahai2')
不存在就增加
setattr(obj,'yyy','www')
print(getattr(obj,'yyy',None))
删除对象属性值
delattr(obj,'name')
print(obj.__dict__)
单列模式
单列模式的介绍 1.什么是单例模式 ***** 单:同一个 例: 实例/对象 模式:一个模板或者一个方法 单例模式:基于某种方法实例化多次得到实例/对象是同一个 2.为何用单例模式 当实例化多次得到的对象中(存放的属性)都(一样)的情况,应该将多个对象指向同一个内存,即同一个实例 3.如何用
绑定类方法的单例模式
class Mysql:
# 封装一下 对内不对外
__instance = None
def __init__(self,ip,port):
self.ip =ip
self.port = port
@classmethod
def from_conf(cls):
# print('类方法绑定')
if cls.__instance is None:
# 完成Mysql对象的初始化 Mysql('127.0.0.1',1234)
# cls.__instance 就是Mysql的对象
cls.__instance = cls('127.0.0.1',1234)
# 拿到的是Mysql('127.0.0.1',1234)实例化
return cls.__instance
obj1=Mysql.from_conf()
obj2=Mysql.from_conf()
obj3=Mysql.from_conf()
print(id(obj1))
print(id(obj2))
print(id(obj3))
print(obj1.ip)
print(obj2.ip)
print(obj3.ip)
print(obj1.port)
print(obj2.port)
print(obj3.port)
# 不单例
obj4 = Mysql('127.0.0.1',5678)
print(id(obj4))
print(obj4.port)
元类
在python中统一了类与类型的概念 什么是元类: 源自一句话:在python中,一切皆对象,而对象都是由类实例化得到的 关系: 1.调用元类---->自定义的类 2.调用自定义的类---->自定义的对象
type元类创建自定义类 class关键字创建自定义类的底层的工作原理,分为四步 1.先拿到类名:‘Teacher’ 2.再拿到类的基类们:(object,) 3.然后拿到类的名称空间???(执行类体代码,将产生的名字放到类的名称空间也就是一个字典里,补充exec) 4.调用元类实例化得到自定义的类:Teacher=type(‘Teacher’,(object,),{…})
# 不依赖class关键字创建一个自定义类
# 1. 拿到类名
class_name = 'Teacher'
#2. 拿到类的基类/父类们:(object,)
class_bases = (object,)
#3. 拿到类的名称空间 类的属性 ,方法 也就是类的体代码
class_body = '''
HP = 100
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def run(self):
print('%s在跑步'%self.name)
'''
class_dic = {}
# 介绍 exec 函数 可以执行字符串里面的代码
# exec('print(1)')
# exec函数的使用,第一个参数代码放到字符串里面,第二个参数是全局的字典,第三个参数的局部的字典
# exec('x=1',{},{})
# exec函数的使用,我要用第一个参数代码放到字符串里面,不用第二个参数是全局的字典因为类体代码没有这样的需求
# ,用第三个参数的局部的字典
exec(class_body,{},class_dic)
Teacher = type(class_name,class_bases,class_dic)
print(Teacher)
print(Teacher.HP)
print(Teacher.run)
a=Teacher('大海',18,'man')
a.run()
自定义元类Mymeta
class Mymeta(type):
# 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
# type(class_name,class_bases,class_dic)
# __init__
def __init__(self,class_name,class_bases,class_dic):
print(self)
print(class_name)
print(class_bases)
print(class_dic)
# 这里必须写object ,默认的type元类会做,自定义元类的要自己写
class Teacher(object,metaclass=Mymeta):
# Teacher=type('Teacher',(object,),{...})
# Teacher=Mymeta('Teacher',(object,),{...})
school = '图灵'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def run(self):
print('%s在跑步'%self.name)
自定义元类控制类的产生 现在可以控制类的产生 1.类名必须用驼峰体 2.类体必须有文档注释,且文档注释不能为空
class Mymeta(type):
# 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
# type(class_name,class_bases,class_dic)
# __init__
def __init__(self,class_name,class_bases,class_dic):
if class_name.islower():
raise TypeError('类名必须使用驼峰体')
# print(class_dic.get('__doc__'))
doc = class_dic.get('__doc__')
if doc is None or len(doc) == 0 or len(doc.strip('\n '))==0:
raise TypeError('类的体代码必须有文档注释,且不能为空')
# 这里必须写object ,默认的type元类会做,自定义元类的要自己写
class Teacher(object,metaclass=Mymeta):
'''
dasdas
'''
# Teacher=type('Teacher',(object,),{...})
# Teacher=Mymeta('Teacher',(object,),{...})
school = '图灵'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def run(self):
print('%s在跑步'%self.name)
自定义元类来控制类的调用产生自定义对象 现在可以控制类的产生 1.类名必须用驼峰体 2.类体必须有文档注释,且文档注释不能为空
class Mymeta(type):
# 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
# type(class_name,class_bases,class_dic)
# __init__
# def __init__(self,class_name,class_bases,class_dic):
# if class_name.islower():
# raise TypeError('类名必须使用驼峰体')
# # print(class_dic.get('__doc__'))
# doc = class_dic.get('__doc__')
# if doc is None or len(doc) == 0 or len(doc.strip('\n '))==0:
# raise TypeError('类的体代码必须有文档注释,且不能为空')
def __call__(self, *args, **kwargs):
# print(self)
# print(args)
# print(kwargs)
# 1. 先产生一个空对象__new__可以给Teacher这个类创建一个空对象
tea_obj = self.__new__(self)
# 2. 执行__init__方法,完成对象的初始属性操作
self.__init__(tea_obj,*args, **kwargs)
# 3. 返回初始化好的那个对象
return tea_obj
# 这里必须写object ,默认的type元类会做,自定义元类的要自己写
class Teacher(object,metaclass=Mymeta):
'''
dasdas
'''
# Teacher=type('Teacher',(object,),{...})
# Teacher=Mymeta('Teacher',(object,),{...})
school = '图灵'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def run(self):
print('%s在跑步'%self.name)
# def __call__(self, *args, **kwargs):
# print('aaa')
tea1 = Teacher('大海',18,'man')
print(tea1.__dict__)
# tea1()
推理:如果一切皆对象,那么Teacher也是一个对象,该对象之所可以调用,肯定是这个对象的类Mymeta中也定义了一个函数__call__
自定义元类来控制类的调用过程产生对象 元类Mymeta实例化Teacher,调用Teacher实际上是调用元类Mymeta的__call__方法会 1.先产生一个Teacher的空对象tea_obj 2.Teacher执行__init__方法,完成对象的初始属性操作 3.返回初始化好的那个对象 推理:调用Teacher(…)就是在调用Teacher的元类Mymeta中的__call__,那么在该__call__中就需要做上述三件事
自定义元类来控制类的调用(即类的实例化过程)
#1 我们把对象实例化的属性全部变成隐藏属性
class Mymeta(type):
def __call__(self, *args, **kwargs):
# print(self)
# print(args)
# print(kwargs)
# 1. 先产生一个空对象__new__可以给Teacher这个类创建一个空对象
tea_obj = self.__new__(self)
# 2. 执行__init__方法,完成对象的初始属性操作
self.__init__(tea_obj,*args, **kwargs)
# 在这里改
# _类名__属性
# _Teacher__name
# print(tea_obj.__dict__)
# k1 = []
# v1 = []
# # print(self.__name__)
# # print(tea_obj.__dict__.items())
# for k,v in tea_obj.__dict__.items():
# # print(k,v)
# # print('_%s__%s'%(self.__name__,k))
# k1.append('_%s__%s'%(self.__name__,k))
# v1.append(v)
# # print(k1)
# # print(v1)
# tea_obj.__dict__ = dict(zip(k1,v1))
# 字典生成式
tea_obj.__dict__ = {'_%s__%s'%(self.__name__,k):v for k,v in tea_obj.__dict__.items()}
# 加条件
# tea_obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in tea_obj.__dict__.items() if v == '大海'}
print(tea_obj.__dict__)
# 列表生成式
print([i * 3 for i in range(1,10)])
# 只拿到偶数
print([i * 3 for i in range(1, 10) if i % 2 == 0])
# print(tea_obj.__dict__)
# 3. 返回初始化好的那个对象
return tea_obj
# 这里必须写object ,默认的type元类会做,自定义元类的要自己写
class Teacher(object,metaclass=Mymeta):
'''
dasdas
'''
# Teacher=type('Teacher',(object,),{...})
# Teacher=Mymeta('Teacher',(object,),{...})
school = '图灵'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def run(self):
print('%s在跑步'%self.name)
# def __call__(self, *args, **kwargs):
# print('aaa')
tea1 = Teacher('大海',18,'man')
print(tea1.__dict__)
# print(tea1._Teacher__name)
# tea1()
推理:如果一切皆对象,那么Teacher也是一个对象,该对象之所可以调用,肯定是这个对象的类Mymeta中也定义了一个函数__call__
列表生成式和字典生成式
列表生成式
print([i * 3 for i in range(1,10)])
# 只拿到偶数
print([i * 3 for i in range(1, 10) if i % 2 == 0])
#原始写法
i1 = []
for i in range(1, 10):
if i % 2 == 0:
i1.append(i*3)
print(i1)
字典生成式
dict1 = {k+'aaa':v for k,v in {'name':'大海','age':18}.items() if k == 'name'}
print(dict1)
|