概述
反射其实就是动态的加载模块,而不需要像之前的那样,需提前import各种模块的方式.
hasattr,getattr
同一目录下有两个文件:
.
|____commons.py
|____impor.py
commons.py内容:
def login():
print('login!!!')
def logout():
print('logout!!!!')
def index():
print('home page!!!')
if __name__ == '__main__':
login()
impor.py文件中想调用commons模块里的函数,一般规则就是先import commons,然后得提前知道commons的已定义函数名称才能正常调用,否则报错
那我们能否判断是否有函数名然后再调用其函数呢?看下例子:
import commons
res=hasattr(commons,'login') #1
print(res)
res1=hasattr(commons,'loginxxx')
print(res1)
res2=getattr(commons,'login') #2
print(res2) #3
res2() #4
输出结果:
True
False
<function login at 0x10137b7b8>
login!!!
看出来了吧:
- 标志符#1中hasattr判断commons模块中是否有叫login函数的,注意是字符串字符串字符串,如果有是True,否则我False
- 标志符#2中getattr用来获取login函数的内存中的地址,注意函数名也为*字符串字符串字符串**
- 标识符#3,打印了res2的内存地址
- 后面加括号执行函数login()
setarr:
setattr(commons,'test','this is a test')
res=getattr(commons,'test')
print(res)
out:
this is a test
delattr:
import commons
res=hasattr(commons,'login')
print(res)
delattr(commons,'login')
res1=hasattr(commons,'login')
print(res1)
out:
True
False
来总结下:
函数 | 功能 | 用法注意事项 |
---|---|---|
hasattr | 判断某模块是否有指定的模块 | hasattr(aaa,'bbb'),其中aaa为模块名称,不带引号,bbb为函数名称,是字符串 |
getattr | 从模块中获取指定的模块 | getattr(aaa,'bbb'),与hasattr用法相同 |
setattr | 在指定模块中设置模块 | setattr(aaa,'bbb','ccc'),在模块aaa中设置一个叫bbb的函数或者变量,此变量名称叫ccc,注意字符串 |
delattr | 在模块中删除某函数 | delattr(aaa,'bbb'),从aaa模块中删除bbb的函数,但对模块本身文件不会做修改 |
这就是反射:利用字符串的形式去对象(模块)中操作(寻找/检查/删除/设置)成员
动态加载模块
python中使用了__import__的方法,可以动态的导入模块,实现反射的功能.import()可以根据参数导入指定的模块,参数可为字符串,也可为字符串赋值的变量,来个例子:
m,f=['commons','login']
obj=__import__(m,f)
print(obj)
out:
<module 'commons' from '/Users/shane/PycharmProjects/Py_study/Base/s6/commons.py'>
obj=__import__('commons','login')
print(obj)
out:
<module 'commons' from '/Users/shane/PycharmProjects/Py_study/Base/s6/commons.py'>
那么我们新写一个模块,来导入上面例子中commons模块吧:
while True:
inp=input('input the url:')
m,f=inp.split('/')
obj=__import__(m)
print(obj)
if hasattr(obj,f):
func=getattr(obj,f)
func()
else:
print('404!!')
out:
input the url:commons/login
<module 'commons' from '/Users/shane/PycharmProjects/Py_study/Base/s6/commons.py'>
login!!!
input the url:commons/index
<module 'commons' from '/Users/shane/PycharmProjects/Py_study/Base/s6/commons.py'>
home page!!!
input the url:commons/ddd
<module 'commons' from '/Users/shane/PycharmProjects/Py_study/Base/s6/commons.py'>
404!!
效果还不错哇!!!
这种方式,可以解决N多个模块的导入问题,模块最上面也不需要写辣么多import啦.
不同目录的模块加载
有个目录类似于下面:
.
|____page.py
|____tester
| |______pycache__
| | |____commons.cpython-35.pyc
| |____commons.py
page.py 想调用tester中的commons模块,怎么搞?
m,f=['commons','login']
obj=__import__('tester.'+m)
print(obj)
res=hasattr(obj,f)
result=getattr(obj,f)
print(res)
result()
out:
<module 'tester' (namespace)>
Traceback (most recent call last):
File "/Users/shane/PycharmProjects/Py_study/Base/test/page.py", line 26, in <module>
result=getattr(obj,f)
AttributeError: module 'tester' has no attribute 'login'
测试下,加个fromlist=True:
m,f=['commons','login']
obj=__import__('tester.'+m,fromlist=True)
print(obj)
res=hasattr(obj,f)
result=getattr(obj,f)
print(res)
result()
out:
<module 'tester.commons' from '/Users/shane/PycharmProjects/Py_study/Base/test/tester/commons.py'>
True
login!!!
Binggo!!!!
fromlist是一个允许从列表导入的功能,使用方式:import('xx.xx.xx.xx',fromlsit=True)
看这个例子:
obj=__import__('tester.commons',fromlist=True)
print(obj)
res=hasattr(obj,'login')
print(res)
out:
<module 'tester.commons' from '/Users/shane/PycharmProjects/Py_study/Base/test/tester/commons.py'>
True
以上案例写完就是这个样子的:
while True:
inp=input('input the url:')
m,f=inp.split('/')
obj=__import__('tester.'+m,fromlist=True)
if hasattr(obj,f):
res=getattr(obj,f)
res()
else:print('404')
out:
input the url:commons/index
home page!!!
input the url:commons/login
login!!!
input the url: