Python reflect
就在日落之前 人气:0reflect反射
首先,我们要区分两个概念——“标识名”和“字符串”。
两者字面上看起来一样,却是两种东西:
前者是函数func的函数名,后者只是一个叫“func”的字符串,两者是不同的事物。我们可以用func()的方式调用函数func,但我们不能用"func"()的方式调用函数。说白了就是,不能通过字符串来调用名字看起来相同的函数!
那么反射的作用或者意义是什么呢?
实例分析
考虑有这么一个场景:需要根据用户输入url的不同,调用不同的函数,实现不同的操作,也就是一个WEB框架的url路由功能。
首先,有一个commons.py文件,它里面有几个函数,分别用于展示不同的页面。
# commons.py pass
其次,有一个visit.py文件,作为程序入口,接收用户输入,并根据输入展示相应的页面
# visit.py pass
这就实现了一个简单的url路由功能,根据不同的url,执行不同的函数,获得不同的页面。
然而,让我们思考一个问题,
如果commons文件里有成百上千个函数呢(这很常见)?难道在visit模块里写上成百上千个elif?显然这是不可能的!那么怎么办?
仔细观察visit.py中的代码,会发现用户输入的url字符串和相应调用的函数名好像!
如果能用这个字符串直接调用函数就好了!但是,前面已经说了字符串是不能用来调用函数的。为了解决这个问题,Python提供了反射机制,帮助我们实现这一想法!
现在将前面的visit.py修改一下,代码如下:
# visit.py pass
getattr()函数的使用方法
接收2个参数,前面的是一个类或者模块,后面的是一个字符串,注意了!是个字符串!func = getattr(commons,inp)语句是关键,通过getattr()函数,从commons模块里,查找到和inp字符串“外形”相同的函数名,并将其返回,然后赋值给func变量。变量func此时就指向那个函数,func()就可以调用该函数。
这个过程就相当于把一个字符串变成一个函数名的过程。这是一个动态访问的过程,一切都不写死,全部根据用户输入来变化。
瑕疵:前面的代码还有个小瑕疵,那就是如果用户输入一个非法的url,比如jpg,由于在commons里没有同名的函数,肯定会产生运行错误
那怎么办呢?python提供了一个hasattr()的内置函数,用法和getattr()基本类似,它可以判断commons中是否具有某个成员,返回True或False。
现在将代码修改一下:
# visit.py pass
这下就没有问题了!通过hasattr()的判断,可以防止非法输入导致的错误,并将其统一定位到错误页面。
setattr() 函数对应函数 getattr()
用于设置对象的属性值,该属性不一定是存在的。
setattr() 语法:
getattr(object, name)
参数:
- object -- 对象。
- name -- 字符串,对象属性。
- return:value -- 属性值。
setattr(object, name, value)
参数:
- object -- 对象。
- name -- 字符串,对象属性。
- value -- 属性值。
使用:设置真实存在的属性值
pass
如果属性不存在会创建一个新的对象属性,并对属性赋值:
pass
delattr 函数用于删除属性
语法:
delattr(object, name)
参数:
- object -- 对象。
- name -- 必须是对象的属性。
使用:
pass
单例模式
单例模式是一种常用的软件设计模式。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于被外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
单例模式的要点有三个;
- 某个类只能有一个实例;
- 它必须自行创建这个实例;
- 它必须自行向整个系统提供这个实例。
应用场景
比如,某个服务器的配置信息存在在一个文件中,客户端通过AppConfig类来读取配置文件的信息.如果程序的运行的过程中,很多地方都会用到配置文件信息,则就需要创建很多的AppConfig实例,这样就导致内存中有很多AppConfig对象的实例,造成资源的浪费.其实这个时候AppConfig我们希望它只有一份,就可以使用单例模式.
加载全部内容