day 26 元类
一.isinstance issubclass
class Person:
pass
class Student(Person):
pass
stu1=Student()
#判断是不是实例
print(isinstance(stu1,Student))
#判断是不是子类
print(issubclass(Student,Person))
二.反射
反射 实际上就是反省
简单来说就是 对象具有一种修正错误的能力
hasatter 是否存在某个属性
getatter 获取某个属性
setatter 设置某个属性
delatter 删除某个属性
这几个方法有个共同点都是通过字符串来操作属性
通过字符串来操作属性 ,这就是反省
class Student:
def __init__(self,name,sex,age):
self.name=name
self.sex=sex
self.age=age
def study(self):
print('该学生正在学习')
stu1=Student('henry','man',29)
def test(obj):
if hasattr(obj, 'name'):
print(getattr(obj, 'name'))
else:
print('没有name这个属性')
test(stu1)
这个test方法可以直接由print(getattr(stu1,"name","没有name属性")) 替换
setattr(stu1,'school','shandong')
print(getattr(stu1,'school')) #结果:shandong
delattr(stu1,'school')
print(getattr(stu1,'school','没有school这个属性')) #结果:没有school这个属性
什么时候用反射?
如果在编写代码期间 就能明确知道我要访问的属性 没有必要使用反射
如果在编写代码期间 无法明确知道我要访问的属性 这时就应该使用反射
class Student:
def study(self):
print('正在学习中')
stu=Student()
res=getattr(stu,'study',None)
print(res) #绑定的方法 bound method
def eat():
print('正在吃东西')
setattr(stu,'eat',eat)
print(getattr(stu,'eat',None)) #function
可以通过反射的方式为对象增加一个方法 但是注意 这样增加的方法就是一个普通函数 不会自动传值
需要编写一个CMD工具 这个工具可以支持两个命令 dir ,tasklist
class CMD:
def dir(self):
print('查看当前文件夹目录')
def tasklist(self):
print('查看任务列表')
cmd=CMD()
res=input('请输入指令:').strip()
if hasattr(cmd,res):
func=getattr(cmd,res)
func()
else:
print('输入指令有误')
三.__str__ __del__
前后带__的都是特殊的内置函数,会在某些时机自动执行,一般情况我们不应该直接调用它们
当我们需要自定义打印现实内容时 就需要__str__方法
该方法必须返回一个字符串
class Test:
def __init__(self,name):
self.name=name
def __str__(self):
print('str run..')
return self.name
t=Test('henry')
print(t)
结果:str run..
henry
# 在讲一个对象转换字符串时 本质就是在调用这个对象 __str__方法
print(str(t))
__del__
当对象被从内存中删除时会自动执行
另一种情况时 程序员手动删除了这个对象 也会自动执行
什么时候使用__del__
在python中 有自动内存管理机制 所以 python自己创建的数据 不需要我们做任何操作
但是有一种情况 我们使用python打开了一个不属于python管理的数据
比如打开了一个文件 这个文件一定是操作系统在打开 会占用系统内存 而python解释器无法操作系统内存的
所以 当你的python解释器运行结束后 文件依然处于打开状态 这时候就需要使用__del__来关闭系统资源
简单地说 当程序运行结束时 需要做一些清理操作 就使用__del__
__del__也称之为 析构函数
分析构造 并拆除这个对象
class Testfile:
def __init__(self,filename,mode,encoding='utf-8'):
self.file=open(filename,mode,encoding=encoding)
def read(self):
return self.file.read()
def wtite(self,text):
self.wtite(text)
def __del__(self):#该方法其实就是一个通知性质,仅仅告诉程序员对象将被删除
self.file.close() #在这里关闭文件
tf=Testfile('E:\python-li\课堂\day26\测试文件','rt')
print(tf.read())
四.exec
exec
execute的缩写
表示执行的意思
作用:帮助解析执行的代码,并且将得到的名称存储到指定的名称空间 解释器的内部也是调用它来执行代码的
三个参数:
参数一:需要一个字符串对象,表示需要被执行的python语句
参数二:是一个字典 表示全局名称空间
参数三:也是一个字典 表示局部名称空间
#如果同时制定了 全局和局部 则 会将字符串中包含名称 解析后存到局部中
globalsdic={}
localsdic={}
exec('''
aaaaaa=1
bbbbb=1
def func1():
print('我是func1')
''',globalsdic,localsdic)
print(localsdic)
#结果:{'aaaaaa': 1, 'bbbbb': 1, 'func1': <function func1 at 0x000001FBA4AF1E18>}
#如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中
dic={}
exec('''
aaaaa=1
bbbbb=1''',dic)
print(dic)#输出的就是全局的
exec中,放到第二个参数位置的字典不论名字是什么都表示全局名称空间,放到第三个位置的字典不论名字是什么都表示局部名称空间.
五.元类
1.什么是元类?
一切皆对象
class关键字自定义的类其实也是一个对象
元类是指产生类的类 type就是元类
所有的自定义的类都是通过type实例化得来的
2.为何要用元类?
为了控制类的产生过程,还可以控制对象的产生过程
3.怎么用?
创建元类方法有两种?
方式一:用class关键字去创建,用的默认的元类type
class Student:
school='beijing'
def __init__(self,name,age):
self.name=name
self.age=age
def study(self):
print('正在学习!')
s1=Student('henry','23')
print(type(s1))#结果:<class '__main__.Student'> s1的类是Student
print(type(Student)) #结果:<class 'type'> Student的类是type,类其实是type类型的实例(对象)
print(Student) #结果:<class '__main__.Student'>
方式二:用自定义元类
首先要明白创建类的三要素 类名,类的父类,类的名称空间
类名:
class_name='Student'
类的父类也叫基类:
class_bases=(object,) #其实是一个元组
类的名称空间字典的形式:
class_dic={}
class_body='''
school='beijing'
def __init__(self,name,age):
self.name=name
self.age=age
def study(self):
print('正在学习!')
'''
exec(class_body,{},class_dic) #利用exec传入名称空间
#准备好创建类的三要素
print(class_name)
print(class_bases)
print(class_dic)
#Student=type(类名,基类,类的名称空间)
Student=type(class_name,class_bases,class_dic)
print(Student) #<class '__main__.Student'>
class Test(object): #Test = type("Test",(object,),{})
pass
自定义元类的目的
目的一.自定义元类通过__call__方法控制类的调用过程及控制对象实例化过程
__call__ :调用的意思,在对象被调用时执行
class Mymeta(type):
def __call__(self, *args, **kwargs):
print('Mymeta中的call run')
print(self) #<class '__main__.Student'>
print(args) #('henry', 29)
print(kwargs) #{}
class Student(object,metaclass=Mymeta):
def __init__(self,name,age):
self.name=name
self.age=age
def study(self):
print('正在学习!')
obj=Student('henry',29)
调用Student的目的:
先创建一个Student的空对象
为该空对象初始化所有的属性
#自定义一个元类,需要继承type
class Mymeta(type):
#self 要创建对象的那个类(Student) *调用Student类时传入的参数
def __call__(self, *args, **kwargs):
#固定写法
#创建一个空对象
obj = self.__new__(self)
#为空对象初始化独有的属性
self.__init__(obj,*args,**kwargs)
#返回一个初始好的对象,得到一个完整的对象
return obj
#修改Student的元类为Mymeta
class Student(object,metaclass=Mymeta):
def __init__(self,name,age):
self.name=name
self.age=age
def study(self):
print('正在学习!')
#调用Student这个对象时 执行的是 Student的类(type)中__call__ 方法
obj=Student('henry',29)
print(obj.name)
print(obj.age)
obj.study()
目的二:控制类的创建过程
要控制类的创建过程 只要找到类所属的类 中的__init__即可
class Mymeta(type):
#self 刚建出来的类
#第二个 类的名字
#第三个 类的父类们 元组的形式
#第四个 这个类传进来的名称空间
def __init__(self,class_nane,bases,namespace):
#控制类的名称必须大写
if not class_nane.istitle():
#该代码是主动抛出异常
raise TypeError('类名开头必须大写')
#控制刚建的类必须有__doc__这个属性
if not self.__doc__:
raise TypeError('类中必须由文档注释')
class Student(object,metaclass=Mymeta):
'''
这是文档注释 可以通过__doc__来获取
这是一个学生类
'''
def __init__(self,name,age):
self.name=name
self.age=age
def study(self):
print('正在学习!')
元类使用总结:
元类是用于创建类的类
学习元类是为了 能控制类的创建过程 以及 类实例化对象的过程
一.
控制类的创建过程
1.创建一个元类 (需要继承type)
2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 ,
可以利用这些信息在做处理
3.对于需要被控制的类 需要指定metaclass 为上面的元类
二.
控制类实例化对象的过程
1.创建一个元类 (需要继承type)
2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来
3.在__call__方法中 必须要先编写模板代码
3.1创建空对象
3.2调用类的__init__方法来初始化这个空对象
3.3返回该对象
4.加入你需要控制的逻辑
类的三个组成部分
类名 父类们 名称空间
元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象
六.单例
单例:
单例模式是一种设计模式
单个实例
一个类如果只有一个实例 那么这个类被称之为单例
什么时候使用单例?
当要处理的对象只有一份时或者当所有对象的属性都相同时
打印机类:实现单例
方法一:
class Printer:
'''
这是一个单例,请不要直接实例化,由get方法来获取实例
'''
obj=None
def __init__(self,name,brand,type):
self.name=name
self.brand=brand
self.type=type
def printing(self,test):
print('正在打印%s'%test)
@classmethod
def get_printer(cls):
if not cls.obj:
cls.obj=cls('Es005','爱普生','彩色打印机')
return cls.obj
else:
return cls.obj
p=Printer.get_printer()
print(p)
'''
通过上述方法来获取对象可以保证只有一个对象
但是这还不够,因为我们仍然可以通过调用类来产生对象
'''
方法二:
'''
就应该使用元类 来控制实例化的过程 __call__
在__call__ 中编写代码 保证每次调用call 都返回同一个实例 即可
'''
class Mymeta(type):
obj=None
def __call__(cls,*args,**kwargs):
if not Mymeta.obj:
obj=object.__new__(cls)
cls.__init__(obj,*args,**kwargs)
Mymeta.obj=obj
return Mymeta.obj
else:
return Mymeta.obj
class Printer(object,metaclass=Mymeta):
def __init__(self,name,brand,type):
self.name=name
self.brand=brand
self.type=type
def printing(self,test):
print('正在打印%s'%test)
day 26 元类的更多相关文章
- python之元编程(元类实例)
本实例是元类实例,功能是记录该的子类的类名,并以树状结构展示子类的类名. RegisterClasses继承自type,提供的功能是在__init__接口,为类创建了childrens的集合,并类名保 ...
- 【python进阶】详解元类及其应用2
前言 在上一篇文章[python进阶]详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~ 5.使⽤type创建带有 ...
- Python进阶开发之元类编程
系列文章 √第一章 元类编程,已完成 ; 本文目录 类是如何产生的如何使用type创建类理解什么是元类使用元类的意义元类实战:ORM . 类是如何产生的 类是如何产生?这个问题肯定很傻.实则不然,很多 ...
- python中面向对象元类的自定义用法
面向对象中的常用方法 1.instance 和 issubclass instance :判断两个对象是不是一类 issubclass :判断某个类是不是另一个类的子类 #两个常用方法的使用 clas ...
- 神级程序员通过两句话带你完全掌握Python最难知识点——元类!
千万不要被所谓"元类是99%的python程序员不会用到的特性"这类的说辞吓住.因为 每个中国人,都是天生的元类使用者 学懂元类,你只需要知道两句话: 道生一,一生二,二生三,三生 ...
- iOS中类、元类、isa详解
类相信大家都知道是什么,如果看过runtime的源码或者看过相关的文章对isa肯定也不陌生,不过元类(meta class)大家可能就比较陌生了.不过大家也不要担心,我会细细道来,让大家明白它到底是个 ...
- python概念-其实只要简单了解一下,但是却讲了将近两个小时的知识点:元类
说实话,我真心不太想总结这个东西,算了,炒一下egon的吧 1 引子 1 class Foo: 2 pass 3 4 f1=Foo() #f1是通过Foo类实例化的对象 python中一切皆是对象,类 ...
- python面向对象(六)之元类
元类 1. 类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍然成立: In [13]: class ObjectCreator(object): . ...
- day26——tyoe元类与object的联系、反射、函数与方法的区别、双下方法
day26 type元类与object联系 type 获取对象从属于的类 python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构 ...
随机推荐
- HttpContext.Current.Items的用途
HTTP是一个无状态的协议.每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况.而实际上,我们的系统往 ...
- 执行perl xttdriver.pl报错Can't locate Getopt/Long.pm in @INC
环境:AIX 6.1 + Oracle 10.2.0.4 现象:在做xtts测试时,源环境使用Oracle自带的perl执行xttdriver.pl报错如下: $ $ORACLE_HOME/perl/ ...
- 43.HTML--a标签之mailto邮箱属性用法
HTML 属性标记之 mailto 的用法详解 大家知道,mailto是网页设计制作中的一个非常实用的html标签,许多拥有个人网页的朋友都喜欢在网站的醒目位置处写上自己的电子邮件地址,这样网页浏 ...
- MyBatis基础入门《十 一》修改数据
MyBatis基础入门<十 一>修改数据 实体类: 接口类: xml文件: 测试类: 测试结果: 数据库: 如有问题,欢迎纠正!!! 如有转载,请标明源处:https://www.cnbl ...
- JavaScript-年月日转换12小时制
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- tp 例子=登录逻辑
<?php namespace Home\Controller; use Think\Controller; class LoginController extends Controller{ ...
- arm trustzone
arm的trustzone并不涉及到具体的crypto算法,只是实现: 1) 敏感信息的安全存储: 2) 控制bus和debug的安全访问,保证信息不被泄露: trustzone是system_lev ...
- 【转】基于Python的接口测试框架实例
下面小编就为大家带来一篇基于Python的接口测试框架实例.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 背景 最近公司在做消息推送,那么自然就会产生很多接口,测试 ...
- Lua数据类型
[1]Lua数据类型 Lua语言共有8种基本类型 [1] nil 空.最简单,有且仅有值nil,表示一个无效值(在条件表达式中相当于false) [2] boolean 布尔.包含两个值:false和 ...
- numpy高级应用
reshape重塑数组 ravel 拉平数组 concatenate 最一般化的连接,沿一条轴连接一组数组 # print(np.concatenate([arr1,arr2],axis = 0)) ...