一、isinstance 和 issubclass
1、isinstance(obj,cls)检查是否obj是否是类 cls 的对象。
2、issubclass(sub, super)检查sub类是否是 super 类的派生类
  判断结果为布尔值:是返回True,不是返回False

 class Bar:  #定义父类
pass
class Foo(Bar): #定义子类 继承 Bar
pass class A: #定义类 A
pass obj=Foo() #实例化
a = A() #实例化
#isinstance
print(isinstance(obj,Foo)) #查看obj是否是类Foo的对象
print(isinstance(obj,Bar)) #查看obj是否是类Bar的对象
print(isinstance(a,A)) #查看a是否是类A的对象
print(isinstance(a,Foo)) #查看a是否是类Foo的对象
#issubclass
print(Foo.__bases__) #之前查看继承的方式
print(issubclass(Foo,Bar)) #查看类Foo 是否是类Bar的子类
print(issubclass(A,Bar)) #查看类A 是否是类Bar的子类 #执行结果:
True
True
True
False
(<class '__main__.Bar'>,)
True
False

二、反射:getattr,setattr,delattr,hasattr
  1、定义:

  反射:主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

    python面向对象中的反射:通过字符串的形式,操作对象的相关的属性。python中的一切事物都是对象(都可以使用反射)。

2、应用:

  1) hasattr   查找
  hasattr(object,'name') 应用于类或对象,查看有没有所对应的方法。实质还是从类或对象的名称空间去查找。判断结果返回布尔值,有为True,没有为False.

  2)getattr   获取  

  getattr(object,name,‘返回值’) 通过字符串获取 查看有没有这个属性,获取绑定方法。

  实质还是从类或对象的名称空间去查找,有的话返回为函数内存地址,加()就能运行。

  3)setattr 设置
  setattr(x,y,v)   x=类或对象, y='字符串类型的属性名',v=value 值  实质是给类或是对象添加数据属性。

  4)delattr 删除
  delattr(x,y)   x = 类或对象,y = '字符串类型的属性名'   删除类或是对象内的某个属性!

#coding = utf-8
#通过字符串的形式,为类或是对象添加属性
class People: #定义一个类
country = 'China'
def __init__(self,name):
self.name = name def test(self):
print('test') p = People('zh') #实例化 #hasattr
h = hasattr(p,'name') #查看对象p有没有name属性
print(h) #打印布尔值 #执行结果:
True #getattr(object,name,default=None(or'自定义的值'))
print(p.__dict__) #查看对象的名称空间
print(People.__dict__) #查看类的名称空间
g = getattr(p,'name') #获取对象name方法
g1 = getattr(p,'test') #获取对象test的绑定方法
g2 = getattr(People,'test') #获取类test方法
g3 = getattr(People,'work',"没有此方法!") #获取类work方法,没有打印value值
print(g,g1,g2,g3) #打印
g1() #执行对象对应的方法,不需要传值
g2(p) #执行类对应的方法,需要传值 #执行结果:
{'name': 'zh'}
{'__module__': '__main__', 'country': 'China', '__init__': <function People.__init__ at 0x00000000028EC9D8>, 'test': <function People.test at 0x00000000028ECA60>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
zh <bound method People.test of <__main__.People object at 0x00000000028FF208>> <function People.test at 0x00000000028ECA60> 没有此方法!
test
test #setattr()只能更改类或是对象内的 数据属性,函数属性没法变更。
print(p.__dict__) #设置前查看对象的名称空间
setattr(p,'sex','male') #设置sex属性
setattr(p,'age',18) #设置age属性
print(p.__dict__) #设置后查看对象的名称空间
print(p.sex,p.age) #打印 #执行结果:
{'name': 'zh'}
{'name': 'zh', 'sex': 'male', 'age': 18}
male 18 #delattr
print(p.__dict__) #删除前查看对象的名称空间
delattr(p,'age') #删除 对象 的数据属性
print(p.__dict__) #删除操作完成,在对象的名称空间查看 #执行结果:
{'name': 'zh', 'sex': 'male', 'age': 18}
{'name': 'zh', 'sex': 'male'}

  5)反射当前位置的模块成员。

  此处先明确两个概念:

    脚本文件:将程序写到一个文件中,以***.py的方式保存,使用的时候 利用python ***.py进行执行,该文件就称为脚本文件。

    模块:import 模块名 导入的文件就是模块,文件名就是模块名。

    在当前位置获取当前文件中定义的函数,如果直接将本文件以模块的形式导入文件中,程序执行直接触发递归,无法实现功能,此时在自己位置就不能导入自己的模块。此时就需要把本文件转成一个脚本模块,既可以导入到别的模块或文件中用,另外该模块自己也可执行。所以就需要使用下面的方法:
方法:import sys  #导入sys模块

this_modules = sys.modules[__name__](有返回值)  获取一个模块,将当前位置的文件转成一个脚本模块(有具体的文件地址)

print(__name__)

注意:__name__的用法:  如果我们是直接在本文件执行,那该文件中'__name__' == '__main__',但是如果从另外一个.py文件通过import导入该文件的时候,这时__name__的值就是我们这个py文件的名字而不是__main__。(有一种加上保护锁的感觉)

import sys  #导入sys模块
def add():
print('add') def change():
print('change') def search():
print('search') def delete():
print('delete') this_module = sys.modules[__name__] #利用sys模块中的modules方法,将本文件转成脚本模块
print(this_module) #查看
print(__name__) #查看__name__
while True:
m = input('input something:').strip()
if not m :continue
if hasattr(this_module,m): #判断输入的内容在不在模块 类中
func = getattr(this_module,m) #获取这个方法,拿到返回值
func() #执行函数
else:
print('没有此方法!') #执行结果:
<module '__main__' from 'F:/py_fullstack_s4/day31/__name__及反射的用途.py'>
__main__
input something:add
add
input something:work
没有此方法!

3、反射的好处:

  好处一:可以利用反射实现可插拔机制。

  可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,即事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。不影响其他人员对程序的调用和开发。

class FtpClient:
'ftp客户端,但是还没有实现具体的功能'
def __init__(self,addr):
print('正在连接服务器[%s]' %addr)
self.addr=addr
def get(self):
print('get------->')

ftpclient.py

import ftpclient   #将文件以模块形式导入
'''ftp服务端,需要用到客户端的功能'''
f1=ftpclient.FtpClient('192.168.1.1') #调用文件中的类
if hasattr(f1,'get'): #判断是否有这功能
func_get=getattr(f1,'get') #获取功能,得到返回值(对应函数的内存地址)
func_get() #执行函数
else:
print('---->不存在此方法')
print('处理其他的逻辑')

ftpsever.py

正在连接服务器[192.168.1.1]
get------->

执行ftpsever.py结果

  好处二:通过字符串动态导入模块

#不推荐利用__import__(字符串) 的方法,官方推荐importlib.import_module(字符串)的方式
import importlib
# m = input('please input something:')
t = importlib.import_module('time')
print(t.time()) #执行结果:
1493024228.788776

三、内置attr:__getattr__,__setattr__,__delattr__
大前提:类内部设置
  1、__setattr__

  以函数方式,设置在类内部,实例化传值自动触发,直接获取为对象设置的属性,导致对象的名称空间中无法找到方法。

class Foo:
def __init__(self,name): #初始化属性
self.name = name
def __setattr__(self, key, value): # 拿到实例化的值
print('---setattr---key:%s,value:%s'%(key,value))
#self.__dict__[key] = value #在对象的名称空间中添加方法 #调用__setattr__的方法
f = Foo('zh') #类的实例化
f.age = 18 #给类定义一个数据属性
print(f.__dict__) #打印当前字典 #执行结果:
---setattr---key:name,value:zh
---setattr---key:age,value:18
{}

  利用此种方法可以加上自己的限制,然后再通过 self.__dict[key]=value 的方法 添加到对象的名称空间中。

 2、__delattr__   

   删除某个属性,但不会真正删除。若删除的话必须通过 self.__dict__.pop(item)  在方法字典中 删除 

 3、__getattr__  (特别注意该内置函数的方法!!!)

  类内该属性不存在的情况下,才会触发执行,返回None;只要有该方法,就不执行。

class Foo:
def __init__(self,x): #初始化属性
self.name = x
# self.name = x ------------> self = self;key = name; value = x
def __setattr__(self, key, value): # 自动触发,获取self.属性名=值 self = self;key = 属性名;value = 值
print('---setattr---key:%s,value:%s'%(key,value))
self.__dict__[key] = value #在对象的名称空间中添加方法 def __delattr__(self, item):# 删除某项属性
print('delattr:%s'%item)
print(f.__dict__) #打印当前对象的名称空间
self.__dict__.pop(item) #删除对象内的方法 def __getattr__(self, item): # 没有方法触发
print('getattr---> %s %s'%(item,type(item))) #调用__setattr__的方法
f = Foo('zh') #类的实例化
f.age = 18 #给类定义一个数据属性
print(f.__dict__) #打印当前字典 #执行结果:
---setattr---key:name,value:zh
---setattr---key:age,value:18
{'name': 'zh', 'age': 18} #调用__delattr__的方法
del f.age
print(f.__dict__) #执行结果:
delattr:age
{'name': 'zh', 'age': 18}
{'name': 'zh'} #调用__getattr__的方法
print(f.name)
print(f.azcw) #执行结果:
zh
getattr---> azcw <class 'str'>
None

四、二次加工标准类型
1、包装:基于继承实现对标准数据类型的包装对已有的数据类型进行包装,新增/改写方些方法,用以定制我们自己的数据类型。

  实质:创建一个新的类,给数据类型格外添加新的功能或是判断的功能。

class List(list):  #以列表为例
def append(self, p_object): #重新定义append方法,只允许添加数据类型
if not isinstance(p_object,int): #判断 添加的数据是不是数据类型
raise TypeError('must be int')
super().append(p_object) #原定义的其他功能默认不动 l = List([1,2,3,4])
print(l)
l.append(5)
print(l)
l.append('a')
print(l) #执行结果:
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
File "F:/py_fullstack_s4/day31/定义自己的数据类型.py", line 12, in <module>
l.append('a')
File "F:/py_fullstack_s4/day31/定义自己的数据类型.py", line 5, in append
raise TypeError('must be int')
TypeError: must be int
#基于继承的原理,定义自己的数据类型。
#虽然更改了列表的append方法,但是对列表的其他功能没有改变
class List(list): #以列表为例
def append(self, p_object): #重新定义append方法
if not isinstance(p_object,int): #判断 添加的数据是不是数据类型
raise TypeError('must be int')
super().append(p_object) #原定义的其他功能默认不动 l = List([1,2,3,4])
print(l)
l.append(5)
print(l)
# l.append('a')
# print(l)
l.insert(0,-1) #列表的插入方法不改变
l.insert(1,'abc')
print(l) #执行结果:
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[-1, 'abc', 1, 2, 3, 4, 5]

2、授权:实现授权的关键点,就是覆盖__getattr__的方法

对系统已经定义的函数进行包装的过程叫做授权,函数不再是类,有继承的方式,而是所有需要添加的功能由类中再定义,判断结束再写入该函数。已存在的功能默认执行。

  实质:创建一个新的类,给函数格外添加新的功能或是判断的功能。

#不能用继承,来实现open函数的功能
# f=open('a.txt','w')
# print(f)
# f.write('1111111') #授权的方式实现定制自己的数据类型
import time
class Open:
def __init__(self,filepath,m='r',encode='utf-8'): #初始化定义open函数的默认属性
self.filepath=filepath
self.mode=m
self.encoding=encode
self.x = open(filepath, mode=m, encoding=encode) #定义结束,以这种方式执行原函数 def write(self,line): #重新定义写的功能:每行写入的同时也写入时间
print('f自己的write',line) #打印要添加的内容
t=time.strftime('%Y-%m-%d %X') #时间,格式:年-月-日 具体时间
self.x.write('%s %s' %(t,line)) #利用原函数写入新内容 def __getattr__(self, item): #关于其他内容
print('=------>',item,type(item))
return getattr(self.x,item) #返回原函数方法的形式,以原函数对应的这个的方法执行。 #在类中定义好的方法,实例化进行调用
f=Open('b.txt','a+') #实例化方法
print(f) #查看f的类型
f.write('hello world!\n') #执行绑定方法,在文件中写入内容
f.close() #关闭文件,此方法未定义,执行__getattr__方法,利用原函数的方法 #未在类中定义的方法,通过触发__getattr__的方式,来执行原函数的功能!
f=Open('b.txt','r+') #实例化方法
print(f.read) #查看未定义方法read 的类型
print(f.read()) #执行方法 self.x.read()
print('=-=====>',f.read()) #文件读完之后打印
f.seek(0) #将光标移动到初始开始位置
print(f.read()) #再次打印文件中的内容
# f.flush()
f.close() #关闭文件,此方法未定义,执行__getattr__方法,利用原函数的方法 #执行结果:
<__main__.Open object at 0x00000000028AA908>
f自己的write hello world! =------> close <class 'str'>
=------> read <class 'str'>
<built-in method read of _io.TextIOWrapper object at 0x000000000241AB40>
=------> read <class 'str'> 2017-04-24 18:07:07 hello world! =------> read <class 'str'>
=-=====>
=------> seek <class 'str'>
=------> read <class 'str'> 2017-04-24 18:07:07 hello world! =------> close <class 'str'>

Py修行路 python基础 (十八) 反射 内置attr 包装的更多相关文章

  1. Py修行路 python基础 (八)函数(随时更改)

    为何要用函数: 1.解决代码重用的问题 2.提高代码的可维护性,统一维护 3.程序的组织结构清晰,可读性强 定义函数 先定义后使用!!! def funcname(arg1,arg2,.....)  ...

  2. Py修行路 python基础 (二十五)线程与进程

    操作系统是用户和硬件沟通的桥梁 操作系统,位于底层硬件与应用软件之间的一层 工作方式:向下管理硬件,向上提供接口 操作系统进行切换操作: 把CPU的使用权切换给不同的进程. 1.出现IO操作 2.固定 ...

  3. Py修行路 python基础 (十一)迭代器 与 生成器

    一.什么是迭代? 迭代通俗的讲就是一个遍历重复的过程. 维基百科中 迭代(Iteration) 的一个通用概念是:重复某个过程的行为,这个过程中的每次重复称为一次迭代.具体对应到Python编程中就是 ...

  4. Py修行路 python基础 (十三)匿名函数 与 内置函数

    一.匿名函数  1.定义: 匿名函数顾名思义就是指:是指一类无需定义标识符(函数名)的函数或子程序. 2.语法格式:lambda 参数:表达式 lambda语句中,开头先写关键字lambda,冒号前是 ...

  5. Py修行路 python基础 (二十三)模块与包

    一.模块 1)定义: 模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 2)为何要用模块: 退出python解释器然后重新进入,那之前定义的函数或者变量都将丢失,因 ...

  6. Py修行路 python基础(六)前期基础整理

    计算机中,有且仅有CPU具有执行权限,能够执行指令的只有CPU! 人在应用程序上输入的文字或文本,叫做明文! 在屏幕上输入或是输出的是字符,计算机保存的是 有字符编码的 二进制数. 变量赋值规则:例如 ...

  7. Py修行路 python基础 (九)作用域 函数嵌套 闭包

    名称空间与作用域 变量,函数 分成三种 #内置名称空间  内置函数, 系统函数内部自定义的. python查看内置函数,命令: import builtins dir(builtins) #全局名称空 ...

  8. Py修行路 python基础 (二十一)logging日志模块 json序列化 正则表达式(re)

    一.日志模块 两种配置方式:1.config函数 2.logger #1.config函数 不能输出到屏幕 #2.logger对象 (获取别人的信息,需要两个数据流:文件流和屏幕流需要将数据从两个数据 ...

  9. Py修行路 python基础 (十九)面向对象进阶(下)

    item系列 __slots__方法 __next__ 和 __iter__实现迭代器  析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的格式.  例如:对象名['key'] ...

随机推荐

  1. spring3: AOP 之 通知顺序

    如果我们有多个通知想要在同一连接点执行,那执行顺序如何确定呢?Spring AOP使用AspectJ的优先级规则来确定通知执行顺序.总共有两种情况:同一切面中通知执行顺序.不同切面中的通知执行顺序. ...

  2. linux sed使用(转)

    sed入门详解教程 sed 是一个比较古老的,功能十分强大的用于文本处理的流编辑器,加上正则表达式的支持,可以进行大量的复杂的文本编辑操作.sed 本身是一个非常复杂的工具,有专门的书籍讲解 sed ...

  3. KindEditor 上传文件

    Jsp页面代码: <script> var editor; KindEditor.ready(function(K) { editor = K.create('textarea[name= ...

  4. Gogs/Gitea 在 docker 中部署

    注:Gitea是Gogs的一个分支版本,由多个维护者开发,支持搜索.lfs等,但是BUG较多,稳定性似乎没有Gogs好. #### 安装 ####// Gogs$ docker pull gogs/g ...

  5. delete 与 delete []的区别

    一. 针对类class,这两种方式的效果是不同的. 当你通过下列方式分配一个类对象数组:   class A   {   private:      char *m_cBuffer;      int ...

  6. New Concept English three (30)

    27W/m 32 words the death of ghost For years, villagers believed that Endley Farm was hunted. The far ...

  7. 《Drools7.0.0.Final规则引擎教程》第2章 追溯Drools5的使用

    2.1 Drools5简述 上面已经提到Drools是通过规则编译.规则收集和规则的执行来实现具体功能的.Drools5提供了以下主要实现API: KnowledgeBuilder Knowledge ...

  8. OneDrive网页版打不开的解决办法

    发现OneDrive文件被误删了,想去网页版找回历史文件,发现网页版无法打开,而客户端是可以正常使用的,于是猜测是域名指向的主IP被封了,于是想通过客户端的IP访问 第一步,WireShark抓包 第 ...

  9. libQt5Core.so: undefined reference to `dlclose@GLIBC_2.4'

    /******************************************************************************** * libQt5Core.so: u ...

  10. Hadoop集群中节点角色定义

    Hadoop分别从两个角度将主机划分为两种角色. 最基本的划分原则为Master和Slave,即主人和奴隶: 第一,从HDFS的角度,将主机划分为NameNode和DataNode(在分布式文件系统中 ...