python基础之反射

概述

反射其实就是动态的加载模块,而不需要像之前的那样,需提前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. 标志符#1中hasattr判断commons模块中是否有叫login函数的,注意是字符串字符串字符串,如果有是True,否则我False
  2. 标志符#2中getattr用来获取login函数的内存中的地址,注意函数名也为*字符串字符串字符串**
  3. 标识符#3,打印了res2的内存地址
  4. 后面加括号执行函数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:
原文地址:https://www.cnblogs.com/ccorz/p/5587109.html