一、反射
1、模块导入
为方便反射的讲解,首先我们先引入import导入的方式(我们已经在python开发[第九篇]中讲解过一些基本知识)的进一步提升。
模块的导入的常见方式是:
import commons #当导入的模块与现在的正在编写的模块在同一个级别,或者是在上一级目录中 import commons as CC #给模块重新命令 from lib.test import index #当模块在一个多级目录下 import lib.test.index #当模块在一个多级目录下
上面的导入方式皆是最简单的方式,而且我们也不能得知导入的模块属性是什么(字符串,还是其他什么),如:commons 我们并不知道他的类型是什么。为了解决这个问题,我们发现了 __import__("模块名")方法,如下:
__import__("commons") #导入同级或者上一级的模块 __import__("lib.test.index",fromlist=True) #导入多级目录下的模块, fromlist就是为了实现目录的依次查询
从上面可以看见,模块名——>>使用的是字符串格式。
2、反射
python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。如下详解:
"""
假设现在有模块,commons.py 。模块内容如下:
name="alex"
def f1():
return "ff"
"""
#######getattr方法####### #1 import commons
#将f1方法以字符串的格式传入。在commons模块下,寻找f1属性,并将属性赋值给target_func
target_func = getattr(commons,"f1") target_func() #执行结果:ff
#2
DD = __import__("commons) #通过另一中方式导入模块
target_func = getattr(DD,"f1")
# 设置默认值,没有找到为默认值
target_func = getattr(DD,"f1",None) #None是设置的默认值,如果没有找到,那么print(target_func)=None。
# 还可以获取全局变量
str_ = getattr(DD,"name",None)
#########hasattr方法######### # 判断 函数或变量存在与否, true or false r= hasattr(commons,"name") r= hasattr(commons,"func")
########setattr方法######### 设置 变量或者定义函数 fuc = setattr(commons,"f4", lambda x:x+2) str_s = setattr(commons,"name3", "weiwei") #注意:这个添加只是内存上的添加,并不会在模块文件中出现添加
#########delattr方法####### 删除 变量或者定义函数 f = delattr(commons,"name")
#注意:这个删除方法也只是在内存上的删除,并不会删除文件中的内容
3、使用反射查找类中成员
当我们要访问一个对象的成员时,应该是这样操作:
class Foo(object):
def __init__(self):
self.name = 'alex'
def func(self):
return 'func'
obj = Foo()
# 访问字段
obj.name
# 执行方法
obj.func()
那么问题来了?
a、上述访问对象成员的 name 和 func 是什么?
答:是变量名
b、obj.xxx 是什么意思?
答:obj.xxx 表示去obj中或类中寻找变量名 xxx,并获取对应内存地址中的内容。
c、需求:请使用反射寻找类中的成员
class Foo(object): def __init__(self): self.name = 'alex' def func(self): return 'func' r=hasattr(Foo,"__init__") print(r) #执行结果:True t=hasattr(Foo,"name") print(t) #执行结果:False #说明name不是类的成员
c、需求:请使用其他方式获取obj对象中的name变量指向内存中的值 “alex”,该如何做?
答:有两种方式,如下:
#####方式一 class Foo(object): def __init__(self): self.name = 'alex' def func(self): return 'func' # 不允许使用 obj.name来进行访问 obj = Foo() print (obj.__dict__['name']) #######方式二 # 不允许使用 obj.name来进行访问 obj = Foo() print (getattr(obj, 'name')) #因为name是obj对象中封装的。所以name本就在对象中
print(getatter(obj,"func"))
结论:1.反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!
2.成员是指:当前对象(模块)下所具有的实际变量(不包含形式参数)、函数以及类
4、实战1:
""" 有模块accout.py是网页的后台程序。 如果用户输入:www.etitian.org/accout/login。那么就意味着要去accout模块,执行login函数。针对这种情况,可以进行如下代买 """ import accout def runserver(url): x=url.split("/").[-1] if hasattr(accout,x): target=getattr(accout,x) target() else: print("404") if __name__=="__main__": inp=input("请输入url地址:") runnserver(inp)
实战2:
现在我们知道了文件下有类,类下有对象。那么我们如何通过反射从文件里去获取对象中的方法
#假设现在有模块(文件)index.py。模块中存有如下代码:
class Foo(object): def __init__(self): self.name = 'alex' def func(self): return 'func'
实现方法:
target=__import__("s2",fromlist=True) #导入模块文件 xx=getattr(target,"Foo") #从模块中获取类 r=xx() #创建类对象 name=getattr(r,"name") #从对象中获取成员 print(name)
浙公网安备 33010602011771号