一、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 MVC的 HttpMediaTypeNotSupportedException

    使用框架:Spring3 MVC + dojo1.8 前提:配置Spring MVC以JSON数据形式响应请求 使用场景:dojo向Spring MVC发送ajax请求 异常信息: org.sprin ...

  2. 51nod 1042 数位dp

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1042 1042 数字0-9的数量 基准时间限制:1 秒 空间限制:131 ...

  3. IOS-内存分析

    一.内存分析 1.静态分析(Analyze) 不运行程序, 直接检测代码中是否有潜在的内存问题(不一定百分百准确, 仅仅是提供建议) 结合实际情况来分析, 是否真的有内存问题 2.动态分析(Profi ...

  4. Stylus的基础用法

    介绍 在学习一个 Vue.js 项目的过程中,注意到源码中样式的部分并没有用熟悉的 .css 样式文件,而是发现了代码长得和 CSS 相像的 .styl 文件.这个 .styl 以前没见过啊,你是谁? ...

  5. Django与数据库操作

    Django与数据库操作 数据库连接的方法 web 框架 django --- 自己内部实现 (ORM) + pymysql(连接) Flask,tornado --- pymysql SQLArch ...

  6. 偶然遇到的samba服务器权限问题

    也许有一些参考价值. CentOS 6.4使用命令service smb start启动samba服务器,在配置文件都正确,而且对应的共享目录权限也正确,使用smbpasswd添加了用户,这之后,使用 ...

  7. Leetcode22. Generate Parentheses(生成有效的括号组合)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/74937307冷血之心的博客) 题目如下:

  8. js 下获取子元素的方法

    笔记核心: firstElementChild只会获取元素节点对象,从名称就可以看出来,firstChild则可以获取文本节点对象(当然也可以获取元素节点对象),比如空格和换行都被当做文本节点. js ...

  9. golang实现图片上传

    golang实现图片上传 该代码为使用beego实现前后端图片上传.话不多说,直接上代码. 1.前端代码 html代码: <div class="col-5 f-l text text ...

  10. python 中出现 “IndentationError: expected an indented block” 问题

    python 学习 在定义Python函数的时候如下 >>>def hello() . . .print "hello" 这样会报错的,报错如下: Indenta ...