洗礼灵魂,修炼python(44)--巩固篇—反射之重新认识hasattr,gettattr,setattr,delattr
不急着进入正题。先动手完成一个小程序:
设计一套简单的服务开启关闭程序,每次开启或关闭都得打印服务当前的状态:
class Server(object): def __init__(self): self.status='stop' #初始状态 def start(self): #开启服务 if self.status=='running': #执行服务前检测当前状态,根据状态不同做相应处理 print("the Server was running,dont't need to start") else: print('starting the Server') self.status = 'running' def stop(self): #关闭服务 if self.status == 'stop': #执行服务前检测当前状态,根据状态不同做相应处理 print("the Server was stop,dont't need to stop") else: print('stopping the Server') self.status = 'stop' def restart(self):#重启服务 self.stop() self.start()
测试结果:
很简单的就把问题解决了,由于我们这是在python的交互式界面下操作的,那么是针对于py文件,在操作系统下以脚本运行的方式输入【python py文件名】命令就运行呢?这就得稍微有点难度,不过也不是不行,就是运行了没有任何结果:
这虽然没报错,但是没有任何输出对吧?这样的程序等于废的了,之前说过,有个sys模块,可以通过sys发送指令,并让系统执行,那么我们导入sys模块并用argv方法捕获命令看看:
捕获到了我们输入的test,好办了对吧?我可以直接在后面输入start,stop等命令,让服务执行相应操作了,稍微改动下代码是可行的:
既然这样可行了,但是我们想优化一下,因为假如说是一个大型项目,难道每一个命令我们都要手动输入一遍,并调用吗?是不是觉得这就不行了,完全违背了python的简洁优雅宗旨了吧?那么有没有具体的优化方案呢?
利用字典,在字典内做一个命令到方法的映射,瞬间就把效率提升了对吧?但是,我想你应该看到了,当调用的并不是方法的时候会报错,你说我再加一层if判断一下就行啊或者改代码就行啊对吧?这些都还不是主要的问题,如果在字典定义时,如果不慎将方法名或者属性名输入错误呢?那么程序就不行了啊对吧?这就和前几篇里的从游戏《绝地求生-大逃杀》了针对面向对象编程一个原理了对吧,那么那一篇里使用面向对象解决的,这里也是吗?喂喂,我这里就是面向对象啊,就是用的类在解决问题啊,那么这里到底怎么办呢?主角终于登场了(终于进入正题了,你们看着也累,其实我也觉得累)
使用什么方法呢?用hasattr和getattr搞定:
前面hasattr已经说过是判断属性是否存在类里,如果存在则返回True,反之返回False,这里的意思是如果这个类存在这个属性(而这个属性就是我们输入的字符串名),那么就获取到对应的属性的内存id,后面个括号表示实例化。问题解决了吧?
还有右边的为什么已经启动过一次关闭服务会提示已经关闭,因为代码初始的时候self.status='stop',命令每次运行都是从头开始的,并不是连贯的命令,所以出现这情况(感兴趣的自己去优化了,这个问题在本篇博文里不是重点)
那么你想,加入我要传入一个参数呢?又怎么搞呢?
赋值给一个变量就行,括号内传参。其他代码大体不变,不过今天的重点不在这,而是在类外层定义一个方法时,通过特使的方法让非类里的方法能调用类里的方法和属性,这个效果觉得有点不切实际是吧?但是使用setattr是可以的,并且还可以实现刚才的传参功能
import sys class Server(object): def __init__(self): self.status='stop' #初始状态 def start(self): #开启服务 if self.status=='running': #执行服务前检测当前状态,根据状态不同做相应处理 print("the Server was running,dont't need to start") else: print('starting the Server') self.status = 'running' def stop(self): #关闭服务 if self.status == 'stop': #执行服务前检测当前状态,根据状态不同做相应处理 print("the Server was stop,dont't need to stop") else: print('stopping the Server') self.status = 'stop' def restart(self):#重启服务 self.stop() self.start() def test(name): #测试方法,注意不在类里,这里的name表示是可以传参的, print('this is a test') print('by:%s'%name) if __name__ == '__main__': s=Server() if hasattr(s,sys.argv[1]): getattr(s,sys.argv[1])() #获取实例的方法并调用 setattr(s,'test',test) #绑定到一个非类下的方法 s.test('yang') #传入值并返回
测试结果:
是不是瞬间觉得很屌啊?注意这里有个共识,这个test方法和类的start等方法有区别的对吧?那么怎么显得没有什么区别呢?还有怎么调用类里的方法呢?
先看看setattr的使用方法:
那么我们试着改下看看:
import sys class Server(object): def __init__(self): self.status='stop' #初始状态 def start(self): #开启服务 if self.status=='running': #执行服务前检测当前状态,根据状态不同做相应处理 print("the Server was running,dont't need to start") else: print('starting the Server') self.status = 'running' def stop(self): #关闭服务 if self.status == 'stop': #执行服务前检测当前状态,根据状态不同做相应处理 print("the Server was stop,dont't need to stop") else: print('stopping the Server') self.status = 'stop' def restart(self):#重启服务 self.stop() self.start() def test(self,name): #self参数表示自身,为了和类里的方法统一 print('this is a test') print('the status [%s] was by %s looked'%(self.status,name)) if __name__ == '__main__': s=Server() if hasattr(s,sys.argv[1]): func=getattr(s,sys.argv[1]) func() setattr(s,'test',test) s.test(s,'yang') #括号里的s则是self,因为并不是类的方法,所以直接写自身
测试结果:
成功了对吧?这个功能是不是有那么一点想装饰器啊?是的,确实挺像的,可以为定义好的类动态的扩展功能。
有扩展那么肯定有删除啊是吧?有吗?有的,delattr:
但这里却出错了,为什么,我删start删不掉啊,想想为什么?我这对象是s对吧?是Server的实例化对象,start是类的方法对吧?只是被s实例化后得到的方法,所以报错,那如果我删status可以不?
果然可行,报错提示的是不存在叫【status】属性名
那么你说我可以直接删类的方法不?就刚才报错没删掉的?试试看:
果然可行的。
好的,那么hasattr,getattr,setattr,delattr的实际用法就是这样,很实用的对吧?在实际开发中会经常用到的。像这种类似装饰器对类进行增删扩展操作的方法就叫反射。这就是本篇博文的主题。
这四个内置方法在前面就提过的,相关的总结也就不提了,本篇博文是作为对四个内置函数的巩固的。
洗礼灵魂,修炼python(44)--巩固篇—反射之重新认识hasattr,gettattr,setattr,delattr的更多相关文章
- python 内置函数的补充 isinstance,issubclass, hasattr ,getattr, setattr, delattr,str,del 用法,以及元类
isinstance 是 python中的内置函数 , isinstance()用来判断一个函数是不是一个类型 issubclass 是python 中的内置函数, 用来一个类A是不是另外一个 ...
- isinstance/type/issubclass的用法,反射(hasattr,getattr,setattr,delattr)
6.23 自我总结 面向对象的高阶 1.isinstance/type/issubclass 1.type 显示对象的类,但是不会显示他的父类 2.isinstance 会显示的对象的类,也会去找对象 ...
- python反射hasattr getattr setattr delattr
反射 : 是用字符串类型的名字 去操作 变量 相比于用eval('print(name)') 留有 安全隐患 反射 就没有安全问题 hasattr 语法: hasattr(object, name)o ...
- Python hasattr,getattr,setattr,delattr
#!/usr/bin/env python # -*- coding:utf-8 -*- # 作者:Presley # 邮箱:1209989516@qq.com # 时间:2018-11-04 # 反 ...
- 反射hasattr; getattr; setattr; delattr
hasattr(obj,name_str):#判断一个对象obj里面是否有对应的name_str字符串的方法,返回True或者Falsegetattr(obj,name_str):#根据字符串去获取对 ...
- hasattr getattr setattr delattr --> (反射)
class Room: def __init__(self,name): self.name = name def big_room(self): print('bigroot') R = Room( ...
- python动态函数hasattr,getattr,setattr,delattr
hasattr(object,name) hasattr用来判断对象中是否有name属性或者name方法,如果有,染回true,否则返回false class attr(): def fun( ...
- 洗礼灵魂,修炼python(46)--巩固篇—如虎添翼的property
@property 在前面装饰器一章中,提过一句话,装饰器也可以用于类中,确实可以的,并且python的类也内置了一部分装饰器.并且在前两章的hasattr等四个内置方法中,也说过其用法很类似装饰器, ...
- python全栈开发day23-面向对象高级:反射(getattr、hasattr、setattr、delattr)、__call__、__len__、__str__、__repr__、__hash__、__eq__、isinstance、issubclass
一.今日内容总结 1.反射 使用字符串数据类型的变量名来操作一个变量的值. #使用反射获取某个命名空间中的值, #需要 #有一个变量指向这个命名空间 #字符串数据类型的名字 #再使用getattr获取 ...
随机推荐
- 一些java多线程的经验
多线程的时候,可以try--catch后再catch中加continue让程序继续运行(当然,前提是这个异常的数据不影响后续的操作)
- Centos 7 Asp.net core 使用QRCoder 报“Unable to load DLL 'gdiplus'"
环境: Centos7 .Net core 2.0 问题: 使用QRCoder 报“Unable to load DLL 'gdiplus'" 同 https://q.cnblogs.com ...
- msysGit在GitHub代码托管
(转:http://www.cnblogs.com/xing901022/p/4388190.html) 代码的管理,在日常开发中是很重要的环节,程序员的修炼三部曲——版本控制,单元测试,项目自动化. ...
- simhash文章排重
原文链接:https://www.cnblogs.com/baochuan/p/9089244.html 背景 提升产品体验,节省用户感知度.——想想,如果看到一堆相似性很高的新闻,对于用户 ...
- javaWeb代码工程统计
直接放在src/test/java包内运行 /** * 代码行数统计 * @author ThinkGem * @version 2014-7-22 */ public class CodeCount ...
- 关系型数据库 VS NOSQL
转载:https://mp.weixin.qq.com/s/FkoOMY8_vnqSPPTHc2PL1w 行式数据库(关系型数据库) 行式数据库有如下几个缺点: 大数据场景下 I/O 较高,因为数据是 ...
- MongoDB比较两列大小 使用$subtract函数
是找出整个表 a大于b的总数量,要怎么操作数据库呢,那就要用到$subtract函数 MongoDB比较两列大小 使用$subtract函数, // MongoDB 比较两列大小求出 啊>b 的 ...
- Ubuntu Docker版本的更新与安装
突然发现自己的docker版本特别的低,目前是1.9.1属于古董级别的了,想更新一下最新版本,这样最新的一下命令就可以被支持.研究了半天都没有更新成功,更新后的版本始终都是1.9.1 :查阅了官网资料 ...
- 【jQuery源码】整体架构
jQuery源码可以精简为以下内容: 方框上面的代码根据Jq注释我们可以知道是对AMD规范的支持. jQuery整体上被包裹在一个匿名函数中,这个匿名函数再作为另一个匿名函数的参数被传入,形参fact ...
- linux下xdebug的安装和配置方法
xdebug简介 Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具),可以用来跟踪,调试和分析PHP程序的运行状况. xdebug安装 首先让php错误显示,只需要修改php.in ...