Python---反射

一句话:以字符串形式导入模块,以字符串形式执行函数。

__import__(model):以字符串形式导入模块    
getattr(model. func):以字符串形式执行函数

使用反射:可以避免耦合(大型程序比如工厂模式)

开胃小菜:

来活了,你老板给你一个excle表,里面是这样的:

hostname memory
主机A  8*8
主机B 16*8

你从表中读出的数据是a = '8*8',string类型,老板想让你对里面的内容计算,怎么弄呢?

eval()

eval函数用来执行一个字符串的表达式,然后返回表达式的值。

a = '8*8'
eval(a)
>>> 64

反射来了~~~

需求:给了你字符串,通过字符串导入模块(不能直接用import sys)

temp = 'sys'  # sys是一个模块,平时就是import os 就可以了,但是我想让你通过字符串的形式导入
              # 也就是说给了你一个变量temp,不准用import sys,就把sys模块导入进来
-----------------------------------------------------------------------------------------
temp = 'sys'
model = __import__(temp)
print model.path  # path是sys模块里面的方法,用于显示路径
>>>['C:\\Users\\Mr.xiao\\PycharmProjects\\18day03\\main', 
    'C:\\Users\\Mr.xiao\\PycharmProjects\\18day03']等等

继续反射~~~

需求:
两个数据库模块,sql和sqlserver,两个模块内都有两个计算同样用户某样数据个数的函数count(),一个含有1条,一个含有2条,
之前都是使用

import sqlserverhelper
print sqlserverhelper.count()

现在该数据库down机了,要改数据库,需要下面形式进行改

import mysqlhelper
print mysqlhelper.count()

但是太麻烦了,还只是在mian函数里面改的

闪亮登场-----------反射(可以读string类型,通过字符串的形式导入模块,并且以字符串的形式执行函数)

------------以字符串的形式导入模块------------
# temp = 'mysqlhelper'    ---修改方便
temp = 'sqlserverhelper'
model = __import__(temp)
print model.count   >>>

------------以字符串的形式执行函数------------
temp = 'mysqlhelper'   模块(字符串形式)(我自己写的模块?)
func = 'count'         模块里面的函数(字符串形式)
model = __import__(temp)
Function = getattr(model, func)   # getattr就是去model这个模块中获取model中的函数,并且这个函数名是以字符串形式的
print Function   >>>function count at 0x0000000002E5C518>  

getattr(),hasattr(),delattr()

1.getattr() 获取模块中的某一个函数

2.hasattr() 判断某一个函数中有没有某一个函数
module = __import__('sqlserverhelper')
print dir(module)         >>>['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'count']
val = hasattr(module, 'version')
print val
                 >>>False
3.delattr() 删除模块中的某一个函数   
------------------------------

反射用武之地~~~

 需求:我们根据用户输入的url的不同,去返回给用户不同的界面(url 规范 xxx/xxx)

1. ************搬砖式:************
from backend import account
data = raw_input('请输入地址:')
# array = data.split('/')
if data == 'account/login':
    account.login()
elif data == 'account/logout':
    account.logout()

要是有1W个地址你写1W行????

反射上!

2. **************反射:*************所有的主流web框架在干的事
data = raw_input('请输入地址')
array = data.split('/')
userspance = __import__(array[0])  # 导入模块account,array得到的是xxx/xxx中的前一个xxx
func = getattr(userspance, array[1])    # 注意,这个func的返回值就相当于整个函数
func()   # 执行函数
# 详细解析,getattr的第一个参数是我们导入的模块,第二个参数是模块的函数,都是str类型的

但是上述代码执行不了  >>>  ImportError: No module named account

注意  我们自己导入模块的时候:

  1. from backend import account
  2. import backend.account

上面代码在执行  userspance = __import__(array[0])  的时候,是不是忘了点东西?上面的userspance是通过account.array[0],并没有加backend

所以我们这里的userspance = __import__(array[0])就相当于这一句

import backend.account(这里的backend是需要加一个字符串的拼接):__import__('backend.'+array[0])

所以说我们想要调用里面的函数的话还得再导入一次模块,因为上面是account.login(),还需要account这个模块嘛

func = getattr(userspance, array[1])

func()   

data = raw_input('请输入地址:')
array = data.split('/')
userspance = __import__('backend.'+array[0])
model = getattr(userspance, array[0])
func = getattr(model,array[1])
func()

总结:

  1.   导入模块的时候加backend这个字符串链接 __import__('backend.' + array[0])
  2.   如果有反射的话,需要再执行一次getattr()

 

 

 

 

 

你可能感兴趣的:(Python)