Python之面向对象反射

  isinstance(obj,cls)检查是否obj是否是类 cls 的对象  

1 class Foo(object):
2 pass
3
4 obj = Foo()
5
6 isinstance(obj, Foo)

  issubclass(sub, super)检查sub类是否是 super 类的派生类

class Foo(object):
pass class Bar(Foo):
pass issubclass(Bar, Foo)

  反射:

1 什么是反射

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

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

四个可以实现自省的函数

下列方法适用于类和对象(一切皆对象,类本身也是一个对象)

hasattr(object,name)
判断object中有没有一个name字符串对应的方法或属性
 def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass

getattr(object, name, default=None)

 def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v''
"""
pass

setattr(x, y, v)

 def delattr(x, y): # real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y''
"""
pass

delattr(x, y)

 class BlackMedium:
feature='Ugly'
def __init__(self,name,addr):
self.name=name
self.addr=addr def sell_house(self):
print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
def rent_house(self):
print('%s 黑中介租房子啦,傻逼才租呢' %self.name) b1=BlackMedium('万成置地','回龙观天露园') #检测是否含有某属性
print(hasattr(b1,'name'))
print(hasattr(b1,'sell_house')) #获取属性
n=getattr(b1,'name')
print(n)
func=getattr(b1,'rent_house')
func() # getattr(b1,'aaaaaaaa') #报错
print(getattr(b1,'aaaaaaaa','不存在啊')) #设置属性
setattr(b1,'sb',True)
setattr(b1,'show_name',lambda self:self.name+'sb')
print(b1.__dict__)
print(b1.show_name(b1)) #删除属性
delattr(b1,'addr')
delattr(b1,'show_name')
delattr(b1,'show_name111')#不存在,则报错 print(b1.__dict__)

四个方法的使用演示

 class Foo(object):

     staticField = "old boy"

     def __init__(self):
self.name = 'wupeiqi' def func(self):
return 'func' @staticmethod
def bar():
return 'bar' print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

类也是对象

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import sys def s1():
print 's1' def s2():
print 's2' this_module = sys.modules[__name__] hasattr(this_module, 's1')
getattr(this_module, 's2')

反射当前模块成员

导入其他模块,利用反射查找该模块是否存在某个方法

 #!/usr/bin/env python
# -*- coding:utf-8 -*- def test():
print('from the test')

module_test.py

 #!/usr/bin/env python
# -*- coding:utf-8 -*- """
程序目录:
module_test.py
index.py 当前文件:
index.py
""" import module_test as obj #obj.test() print(hasattr(obj,'test')) getattr(obj,'test')()
 class People:
country='China'
def __init__(self,name):
self.name=name
# def walk(self):
# print('%s is walking' %self.name)
p=People('egon')
#
# People.country
# print(People.__dict__) # print(p.name)
# print(p.__dict__) # p.name #hasattr
# print('name' in p.__dict__)
# print(hasattr(p,'name'))
# print(hasattr(p,'name1213')) # print(hasattr(p,'country')) #p.country
# print(hasattr(People,'country')) #People.country
# print(hasattr(People,'__init__')) #People.__init__ #getattr
# res=getattr(p,'country') #res=p.country
# print(res)
#
# f=getattr(p,'walk') #t=p.walk
# print(f)
#
# f1=getattr(People,'walk')
# print(f1)
#
# f()
# f1(p) # print(p.xxxxxxx)
# print(getattr(p,'xxxxxxxx','这个属性确实不存在')) #
# if hasattr(p,'walk'):
# func=getattr(p,'walk')
# func()
#
# print('================>')
# print('================>') #setattr # p.sex='male'
# print(p.sex)
# print(p.__dict__) # setattr(p,'age',18)
# print(p.__dict__)
# print(p.age)
# print(getattr(p,'age')) #delattr
# print(p.__dict__)
# del p.name
# print(p.__dict__) print(p.__dict__)
delattr(p,'name')
print(p.__dict__)

3 为什么用反射之反射的好处

好处一:实现可插拔机制

有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

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

还没有实现全部功能

 #from module import FtpClient
f1=FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func_get=getattr(f1,'get')
func_get()
else:
print('---->不存在此方法')
print('处理其他的逻辑')

不影响lili的代码编写

好处二:动态导入模块(基于反射当前模块成员)

  反射的用途:

    

import sys
def add():
print('add') def change():
print('change') def search():
print('search') def delete():
print('delete') this_module=sys.modules[__name__]
while True:
cmd=input('>>:').strip()
if not cmd:continue
if hasattr(this_module,cmd):
func=getattr(this_module,cmd)
func()
# if cmd in func_dic: #hasattr()
# func=func_dic.get(cmd) #func=getattr()
# func() # func_dic={
# 'add':add,
# 'change':change,
# 'search':search,
# 'delete':delete
# } # while True:
# cmd=input('>>:').strip()
# if not cmd:continue
# if cmd in func_dic: #hasattr()
# func=func_dic.get(cmd) #func=getattr()
# func() # class Foo:
# x=1
# def __init__(self,name):
# self.name=name # def walk(self):
# print('walking......')
# f=Foo('egon') # Foo.__dict__={'x':1,'walk':....}
# 'x' in Foo.__dict__ #hasattr(Foo,'x')
# Foo.__dict__['x'] #getattr(Foo,'x')
# print(Foo.x) #'x' in Foo.__dict__

  反射实现可插拔机制:

    FTP Server:

 import ftpclient
#
# print(ftpclient)
# print(ftpclient.FtpClient)
# obj=ftpclient.FtpClient('192.168.1.3')
#
# print(obj)
# obj.test() #
f1=ftpclient.FtpClient('192.168.1.1')
if hasattr(f1,'get'):
func=getattr(f1,'get')
func()
else:
print('其他逻辑')

    FTP Client:

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

  通过字符串导入模块:

# m=input("请输入你要导入的模块:")

# m1=__import__(m)  #官方不推荐
# print(m1)      #官方不推荐
# print(m1.time())  #官方不推荐 #官方推荐使用方法
import importlib
t=importlib.import_module('time')
print(t.time())

  attr系列:

  __getattr__、__setattr__、__delattr__

  setattr:为对象设置属性的时候回触发setattr的运行。

 getattr:只有在使用点调用属性且属性不存在的时候才会触发
 class Foo:
x=1
def __init__(self,y):
self.y=y def __getattr__(self, item):
print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value):
print('----> from setattr')
# self.key=value #这就无限递归了,你好好想想
# self.__dict__[key]=value #应该使用它 def __delattr__(self, item):
print('----> from delattr')
# del self.item #无限递归了
self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行
f1=Foo(10)
print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
f1.z=3
print(f1.__dict__) #__delattr__删除属性的时候会触发
f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
del f1.a
print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.xxxxxx

三者的用法演示

  定制自己的数据类型:    

# l=list([1,2,3])
#
# l.append(4)
# l.append('5')
# print(l) # class List(list):
# pass
#
# l1=List([1,2,3])
# print(l1)
# l1.append(4)
# print(l1)
# l1.append('5')
# print(l1) #基于继承的原理,来定制自己的数据类型(继承标准类型) # class List(list):
# def append(self, p_object):
# # print('--->',p_object)
# if not isinstance(p_object,int):
# raise TypeError('must be int')
# # self.append(p_object)
# super().append(p_object)
# def insert(self, index, p_object):
# if not isinstance(p_object,int):
# raise TypeError('must be int')
# # self.append(p_object)
# super().insert(index,p_object)
#
# l=List([1,2,3])
# # print(l)
# # l.append(4)
# # print(l)
#
# # l.append('5')
# print(l)
# # l.insert(0,-1)
# l.insert(0,'-1123123213')
# print(l) # def test(x:int,y:int)->int:
# return x+y
# print(test.__annotations__)
#
# print(test(1,2))
# print(test(1,'3'))
#
# def test(x,y):
# return x+y #不能用继承,来实现open函数的功能
# f=open('a.txt','w')
# print(f)
# f.write('1111111') #授权的方式实现定制自己的数据类型
import time class Open:
def __init__(self,filepath,m='r',encode='utf-8'):
self.x=open(filepath,mode=m,encoding=encode) self.filepath=filepath
self.mode=m
self.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','w')
# # print(f)
# f.write('111111\n')
# f.write('111111\n')
# f.write('111111\n') f=Open('b.txt','r+')
# print(f.write)
print(f.read) res=f.read() #self.x.read()
print(res) print('=-=====>',f.read())
f.seek(0)
print(f.read())
# f.flush()
# f.close() 

  作业:

 #基于继承来定制自己的数据类型
class List(list): #继承list所有的属性,也可以派生出自己新的,比如append和mid
def append(self, p_object):
' 派生自己的append:加上类型检查'
if not isinstance(p_object,int):
raise TypeError('must be int')
super().append(p_object)
#
@property
def mid(self):
'新增自己的属性'
index=len(self)//2
return self[index] # l=List([1,2,3]) # print(l.mid) #基于授权来定制自己的数据类型: # class Open:
# def __init__(self,filepath,mode,encode='utf-8'):
# self.f=open(filepath,mode=mode,encoding=encode)
# self.filepath=filepath
# self.mode=mode
# self.encoding=encode # def write(self,line):
# print('write')
# self.f.write(line) # def __getattr__(self, item):
# return getattr(self.f,item) # # f=Open('a.txt','w')
# # f.write('123123123123123\n')
# # print(f.seek)
# # f.close()
# #
# # f.write('111111\n') # f=open('b.txt','w')
# f.write('bbbbbb\n')
# f.close()
# print(f) # class Foo:
# def test(self):
# pass
#
# print(getattr(Foo,'test'))
#
# obj=Foo()
# print(getattr(obj,'test')) class List:
def __init__(self,x):
self.seq=list(x) def append(self,value):
if not isinstance(value,str):
raise TypeError('must be str')
self.seq.append(value)
@property
def mid(self):
index=len(self.seq)//2
return self.seq[index]
def __getattr__(self, item):
return getattr(self.seq,item) def __str__(self):
return str(self.seq) l=List([1,2,3]) l.append('') print(l.mid)
l.insert(0,123123123123123123123123123)
# print(l.seq) print(l) obj.name='egon'
del obj.name

链接:详细

Python之面向对象反射的更多相关文章

  1. Python之面向对象-反射

    一.什么是反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问,检测和修改它本省状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被 ...

  2. python基础-9__import__ 反射和面向对象基础 self 封装 继承(多继承顺序) 多态

    一 反射 python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员.获取成员.设置成员.删 ...

  3. python基础——面向对象进阶

    python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...

  4. python学习------面向对象的程序设计

    一 面向对象的程序设计的由来 1940年以前:面向机器 最早的程序设计都是采用机器语言来编写的,直接使用二进制码来表示机器能够识别和执行的指令和数 据.简单来说,就是直接编写 和 的序列来代表程序语言 ...

  5. 【转】Python之面向对象与类

    [转]Python之面向对象与类 本节内容 面向对象的概念 类的封装 类的继承 类的多态 静态方法.类方法 和 属性方法 类的特殊成员方法 继承层级关系中子类的实例对象对属性的查找顺序问题 一.面向对 ...

  6. Python OOP面向对象

    一.什么是面向对象的程序设计 1.面向过程 程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式. 优点是 ...

  7. Python 3 面向对象进阶

    Python 3 面向对象进阶 一.    isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的 ...

  8. python初始面向对象

    阅读目录 楔子 面向过程vs面向对象 初识面向对象 类的相关知识 对象的相关知识 对象之间的交互 类命名空间与对象.实例的命名空间 类的组合用法 初识面向对象小结 面向对象的三大特性 继承 多态 封装 ...

  9. Python 基础 三 反射

    Python 基础 三 反射 今天我们先介绍一下反射这个概念,啥是反射?反射就是自己检测自己.在我们Python的面向对象中的反射是啥意思呢?就是通过字符串的形式操作对象相关的属性.python中的一 ...

随机推荐

  1. bzoj1048(记忆化搜索)

    1048: [HAOI2007]分割矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1218  Solved: 890[Submit][Statu ...

  2. VI/VIM修改Tab为4个空格

    配置方法 在当前用户目录下创建或修改~/.vimrc Root用户下修改/etc/virc 和 /etc/vimrc set ts= set softtabstop= set expandtab se ...

  3. Frequency of String CodeForces - 963D

    http://codeforces.com/contest/963/problem/D 题解:https://www.cnblogs.com/Blue233333/p/8881614.html 记M为 ...

  4. 浏览器 cookie session

    浏览器的cookie被禁用的话,则服务端的session不起作用 session是基于cookie实现的, 还是办理会员卡的问题, cookie客户端支持,即客户手上的会员卡记录了所有信息, sess ...

  5. 12c debug 转 12C 连接CDB和PDB

    来源:David Dai -- Focus on Oracle 连接到CDB 12c debug 和普通实例一样的连接. 指定ORACLE_SID 以后可以使用OS认证,也可以使用密码进行连接. [o ...

  6. vijos P1426兴奋剂检查 多维费用背包问题的hash

    https://vijos.org/p/1426 这是个好题,容易想到用dp[i][v1][v2][v3][v4][v5]表示在前i个物品中,各种东西的容量是那个的时候,能产生的最大价值. 时间不会T ...

  7. 轻松搞懂Java中的自旋锁

    前言 在之前的文章<一文彻底搞懂面试中常问的各种“锁”>中介绍了Java中的各种“锁”,可能对于不是很了解这些概念的同学来说会觉得有点绕,所以我决定拆分出来,逐步详细的介绍一下这些锁的来龙 ...

  8. 使用 Java 发送邮件

    在我们的应用程序中有时需要给用户发送邮件,例如激活邮件.通知邮件等等.那么如何使用 Java 来给用户发送邮件呢? 使用 java 代码发送邮件 使用工具类发送邮件 使用Spring进行整合发送邮件 ...

  9. Mac OS 下安装和配置 maven

    1. 安装 Maven 前的必须准备 需先安装 Java 环境 下载合适的 JDK 配置 JDK 环境变量 JAVA_HOME:为 JDK 安装目录 Path:为 JDK/bin 目录 测试是否成功: ...

  10. git 学习笔记1

    目前我属于粗放型的[学习者],接下来需要做一些改变,让自己更加规范.首先需要学习的就是版本控制系统,本科在工作室的时候使用过一点Subversion,不过到现在已经基本没有印象了.git现在越来越成为 ...