isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象
1 | class Foo(object): |
issubclass(sub, super)检查sub类是否是 super 类的派生类
1 | class Foo(object): |
反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射
通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr(object,name)
判断object中有没有一个name字符串对应的方法或属性
getattr(object, name, default=None)
1 | class People: |
setattr(x, y, v)
1 | class People: |
delattr(x, y)
1 | class People: |
反射当前模块成员
1 | import sys |
3 为什么用反射之反射的好处
好处一:实现可插拔机制
有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。
总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
1 | class FtpClient: |
不影响lili的代码编写
1 | #from module import FtpClient |
好处二:动态导入模块(基于反射当前模块成员)
__setattr__,__delattr__,__getattr__
__setattr__,__delattr__,__getattr__三者的用法演示
1 | class Foo: |
二次加工标准类型(包装)
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
1 | class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid |
练习(clear加权限限制)
1 | class List(list): |
授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
例:利用open()函数重新定制一个文件处理器,增加写内容添加时间的功能;
1 | import time |
__setitem__,__getitem,__delitem__
__setitem__,__getitem,__delitem__把对象操作属性模拟成字典的形式
1 | class Foo: |
__str__
__str__当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
1 | class People: |
结果为
1 | your name is sb |
__slots__
__slots__1 | 1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性) |
1 | class Foo: |
__next__和__iter__实现迭代器协议
__next__和__iter__实现迭代器协议模仿range的功能
1 | class My_range: |
__doc__
__doc__1 | class Foo: |
__module__和__class__
__module__和__class__1 | __module__ 表示当前操作的对象在那个模块 |
__del__
__del__析构方法,当对象在内存中被释放时,自动触发执行。
注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义del,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__
1 | class Foo: |
典型的应用场景:
创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中
当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源
__enter__和__exit__
__enter__和__exit__我们知道在操作文件对象的时候可以这么写
1 | with open('a.txt') as f: |
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
1 | class Open: |
__exit__()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
1 | class Open: |
如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
实例:
1 | import time |
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在exit中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
__call__
__call__对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 | class Foo: |