标签:python 反射 getattr hasattr delattr setattr
从一开始学习这一块感觉blog就比较难写,本来就不太会写博客的问题就更严重了。
想不出什么形象的比喻。所以要写blog的时候我的心情是这样的,但是我的心情应该调整成这样的。
还是用上课时举的例子来说明白。
首先说明一下,反射要用到内置函数,
getattr(obj,name)
hasattr(obj,name)
delattr(obj,name) #操作内存,不影响文件,很少使用
setattr(obj,name) #操作内存,不影响文件,很少使用
先看一下getattr()方法的说明
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, ‘y‘) is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn‘t
exist; without it, an exception is raised in that case.
从一个对象中得到一个命名的属性, getattr(x,"y") 等价于 x.y
其他三个函数与此类似。
上面的先有个印象就好。下面开始详细说明:
首先我们先考虑一个问题。
当我们访问一个网址的时候,我们可以发现,每一个网址都有一个对应的页面。
最直观的python代码实现就是:
import web
url = raw_input("url:")
if url =="web/url01":
result = web.page01() #处理页面数据,并返回结果
print result
elif url =="web/url02":
result = web.page02() #处理页面数据,并返回结果
print result
elif url =="web/url03":
result = web.page03() #处理页面数据,并返回结果
print result
............
else:
print "404 not found"
web.py的内容如下:
def url01():
return "This is ur01"
def url01():
return "This is ur02"
def url01():
return "This is ur03"
............
如果网页少的时候是没有问题的,但是当网页越来越多的时候,这样做显然是不行的。
优化以后外面可以用下面的办法(没有加url判断,即url不存在的时候)
import web
url = raw_input("url:")
preUrl,endUrl = url.split("/")
func = getattr(web,endUrl)
result = func()
print result
运行代码,如果此时输入的url为 web/url01
那么输出结果为: This is ur01
使用正常的代码实现为:(有错误判断)
from wsgiref.simple_server import make_server
def RunServer(environ, start_response):
start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)])
url = environ[‘PATH_INFO‘]
# temp 等于方法的名字
temp = url.split(‘/‘)[1]
#导入web模块
import web
#判断web模块中是否含有 temp,用与判断成员是否存在
is_exist = hasattr(web, temp)
if is_exist:
# 将temp赋值给func,获取函数
func = getattr(web, temp)
#ret 得到func()的返回值
ret = func()
return ret
else:
return ‘404 not found‘
if __name__ == ‘__main__‘:
httpd = make_server(‘‘, 8001, RunServer)
print "Serving HTTP on port 8001..."
httpd.serve_forever()
上面的代码其实就是运行一个httpServer ,如果这个httpServer 得到一个url,就会判断这个url是否存在,如果存在就调用相应的模块和方法,如果不存在就返回 404错误
所有的操作就是对内存中内容的操作
看完下面的代码可能就会明白了
import web # 导入web模块,加载到内存
print dir(web) # 查看web模块有那些内容
print hasattr(web,"web_hasattr") #判断web模块是否含有 “web_hasattr” 方法或属性
print getattr(web,"url01") # 得到web模块中的url01方法(或属性,本文中为方法),并打印
setattr(web,"newFun","newFun value") # 给web模块增加 "newFun" 方法或属性,值为"newFun value"
该操作为内存中的操作,不影响磁盘上的文件,也就是说,源文件不会发生变化
print dir(web)
print delattr(web,"fun1")# 删除web模块中的 "newFun" 方法或属性
同样该操作为内存中的操作,不影响磁盘上的文件,也就是说,源文件不会发生变化 print dir(page01)
对比看六次print的输出结果:
[‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘fun1‘, ‘fun2‘, ‘fun3‘, ‘fun4‘, ‘fun5‘]
False
<function fun1 at 0x7fbebff587d0>
[‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘fun1‘, ‘fun2‘, ‘fun3‘, ‘fun4‘, ‘fun5‘, ‘newFun‘]
None
[‘__builtins__‘, ‘__doc__‘, ‘__file__‘, ‘__name__‘, ‘__package__‘, ‘fun2‘, ‘fun3‘, ‘fun4‘, ‘fun5‘, ‘newFun‘]
开脑洞的想法:
delattr(obj,name) 和 setattr(obj,name) 都是在内存操作,那么类也是可以存在于内存中的,那么这两个函数同样可以对内存中的类进行操作。
class foo:
staticVar= "staticVar"
def __init__(self):
self.var ="var"
def show(self):
pass
@staticmethod
def sshow():
pass
@classmethod
def cshow(cls):
pass
obj =foo()
print dir(obj)
print obj.__dict__
print hasattr(obj,"sdf")
print hasattr(obj,"show")
输出结果:
[‘__doc__‘, ‘__init__‘, ‘__module__‘, ‘cshow‘, ‘show‘, ‘sshow‘, ‘staticVar‘, ‘var‘]
{‘var‘: ‘var‘}
False
True
好,继续前面的,前面的代码主要都是使getattr(obj,name)的第二个参数为动态参数来处理不同的url
对于网站来说,不可能把所有的页面处理方法都写在一个文件里,那么如果动态的使用不同文件里的不同方法(或属性)呢?
即 动态的使用 getattr(obj,name) 的第一个参数。
看如下代码:
controller,action = raw_input("url:").split("/")
module = __import__(controller) #等价于 import 模块名 as module
func= getattr(module,action)
ret = func()
print ret
这里的代码就是上面所有代码的最终版,
也就是我们所说的反射
我理解的是反射就是
你出发某一个条件,然后系统根据找个条件去做处理,并给你返回处理结果。
就好像经过 巴甫洛夫 训练后的狗
你一摇铃铛 狗就流口水。。。
大神博客地址
http://home.cnblogs.com/u/wupeiqi/
我的blog地址:
http://www.timesnotes.com/?p=139
本文出自 “Will的笔记” 博客,请务必保留此出处http://timesnotes.blog.51cto.com/1079212/1723039
标签:python 反射 getattr hasattr delattr setattr
原文地址:http://timesnotes.blog.51cto.com/1079212/1723039