码迷,mamicode.com
首页 > 编程语言 > 详细

python-聊聊反射

时间:2016-06-20 22:20:37      阅读:1597      评论:0      收藏:0      [点我收藏+]

标签:

反射

对于初学python可能较难理解,但反射是非常有用。

试想一下,当别的程序传入给你写的这段代码一个变量(var=“math”),这个变量是一个字符串,这个字符串是一个模块或者一个模块下的某个方法,你需要通过变量来导入此模块或者方法,如何导入此模块或方法呢,如果直接执行 import var是会出错的,因为var在你的这段代码中是一个变量, 这时就需要反射, 如何使用反射呢。

1.聊聊自省

 在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及他能做什么。自省向程序员提供了极大的灵活性和控制力。

几个重要的函数:

dir函数,传入的参数是对象,返回该对象的所有属性和函数列表:

>>> dir(str)
[‘__add__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__getnewargs__‘, ‘__getslice__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mod__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__rmod__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘_formatter_field_name_split‘, ‘_formatter_parser‘, ‘capitalize‘, ‘center‘, ‘count‘, ‘decode‘, ‘encode‘, ‘endswith‘, ‘expandtabs‘, ‘find‘, ‘format‘, ‘index‘, ‘isalnum‘, ‘isalpha‘, ‘isdigit‘, ‘islower‘, ‘isspace‘, ‘istitle‘, ‘isupper‘, ‘join‘, ‘ljust‘, ‘lower‘, ‘lstrip‘, ‘partition‘, ‘replace‘, ‘rfind‘, ‘rindex‘, ‘rjust‘, ‘rpartition‘, ‘rsplit‘, ‘rstrip‘, ‘split‘, ‘splitlines‘, ‘startswith‘, ‘strip‘, ‘swapcase‘, ‘title‘, ‘translate‘, ‘upper‘, ‘zfill‘]

可以看出,string对象的所有函数,属性都列举出来了。

getatter方法,传入参数是对象和该对象的函数或者属性的名字,返回对象的函数或者属性实例,如下:

 

>>> getattr(str,rfind)
<built-in method rfind of str object at 0x7fc2e04c5b10>

 

callable方法,如果传入的参数是可以调用的函数,则返回true,否则返回false。

>>> callable(getattr(str,rfind))
True
>>> callable(getattr(str,__doc__))
False
>>> 

列出对象的所有可以执行的函数:这个地方用到了列表推导式:

>>> methodLIst = [method for method in dir(str) if callable(getattr(str,method))]
>>> print methodLIst
[__add__, __class__, __contains__, __delattr__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __getnewargs__, __getslice__, __gt__, __hash__, __init__, __le__, __len__, __lt__, __mod__, __mul__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __rmod__, __rmul__, __setattr__, __sizeof__, __str__, __subclasshook__, _formatter_field_name_split, _formatter_parser, capitalize, center, count, decode, encode, endswith, expandtabs, find, format, index, isalnum, isalpha, isdigit, islower, isspace, istitle, isupper, join, ljust, lower, lstrip, partition, replace, rfind, rindex, rjust, rpartition, rsplit, rstrip, split, splitlines, startswith, strip, swapcase, title, translate, upper, zfill]

2.python是如何体现反射的

globals()

这个函数返回一个map,这个map的key是全局范围内对象的名字,value是该对象的实例,在不导入任何module下,执行globals()的结果如下:

>>> globals()
{__builtins__: <module __builtin__ (built-in)>, __name__: __main__, __doc__: None, __package__: None}
>>> 

在导入sys后,可以发现,globals()返回的map中,多了sys module:

>>> globals()
{__builtins__: <module __builtin__ (built-in)>, __name__: __main__, sys: <module sys (built-in)>, __doc__: None, __package__: None}

在导入sgmlib如下:

>>> import sgmllib
>>> globals()
{sgmllib: <module sgmllib from /usr/lib64/python2.6/sgmllib.pyc>, __builtins__: <module __builtin__ (built-in)>, __package__: None, sys: <module sys (built-in)>, __name__: __main__, __doc__: None}

如果导入类后,在map中,可以找到类SGMLParser

>>> from sgmllib import SGMLParser
>>> globals()
{sgmllib: <module sgmllib from /usr/lib64/python2.6/sgmllib.pyc>, SGMLParser: <class sgmllib.SGMLParser at 0x7fbd2754c530>, __builtins__: <module __builtin__ (built-in)>, __package__: None, sys: <module sys (built-in)>, __name__: __main__, __doc__: None}

所以,只要将class的名字作为key,即可得到class。如下:

>>> globals()[SGMLParser]
<class sgmllib.SGMLParser at 0x7fbd2754c530>
>>> parser = globals()[SGMLParser]()
>>> parser
<sgmllib.SGMLParser instance at 0x7fbd2d64f1b8>

将模块引入,之后确定模块的相应类的名字,就可以得到了一个类对象,之后就可以实例化了。

3.反射详解

python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = wyf

class Foo(object):
    def __init__(self):
        self.name = chushiyaoyue

    def func(self):
        return func

obj = Foo()#实例化一个对象

# #### 检查是否含有成员 ####
hasattr(obj, name) #True
hasattr(obj, func) #True

# #### 获取成员 ####
getattr(obj, name)
getattr(obj, func)
#chushiyaoyue
#<bound method Foo.func of <__main__.Foo object at 0x0000000002C5F4A8>>
# #### 设置成员 ####
setattr(obj, age, 18)#添加属性
setattr(obj, show, lambda num: num + 1)#添加方法
# print vars(obj)
#{‘age‘: 18, ‘name‘: ‘chushiyaoyue‘, ‘show‘: <function <lambda> at 0x0000000002A46128>}#已经添加了一个属性和一个方法
# # #### 删除成员 ####
delattr(obj, name)
delattr(obj, func)

__import__(‘模块名字‘)

from 包 import 模块名 as 别名 ====等于=== 别名 = __import__("模块名的字符串")

针对该模块同一级下另外一个目录,也就是包,而这个包下有另一个包,而我们需要导入的模块还在其下面,这时候,不能应用包.包.模块作为字符串传入__import__来导入了,因为其只会导入第一层包,需要加入一个参数fromlist = True

a = __import__#基础的导入
__import__("a.b.c.file.login",fromlist=True)#多层级的导入
__import__("a.b.c.file.login")  #是不对的 只导入了a目录 包

python中一切实物都是对象,类,模块也是对象!反射是通过字符串的形式操作对象相关的成员!

类是对象:

 1 #!/usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3 __author__ = wyf
 4 
 5 class Foo(object):
 6 
 7     staticField = "test123"
 8 
 9     def __init__(self):
10         self.name = chushiyaoyue
11 
12     def func(self):
13         return func
14 
15     @staticmethod
16     def bar():
17         return bar
18 
19 print getattr(Foo, staticField)
20 print getattr(Foo, func)
21 print getattr(Foo, bar)

模块是对象:

技术分享
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3  
4 def dev():
5     return dev
home.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3   
 4 """
 5 程序目录:
 6     home.py
 7     index.py
 8   
 9 当前文件:
10     index.py
11 """
12   
13   
14 import home as obj
15   
16 #obj.dev()
17   
18 func = getattr(obj, dev)
19 func() 

实例小练习:根据用户输入的url执行相关的功能

技术分享
 1 #!/usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3 __author__ = wyf
 4 
 5 def login():
 6     return login
 7 
 8 def logout():
 9     return logout
10 
11 def nb():
12     return 特别牛逼的页面
account.py

最简单粗暴的方法,简单很容易想到,但是如果方法一多,你要写很多代码

技术分享
 1 #!/usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3 __author__ = wyf
 4 
 5 from lib import account
 6 
 7 url = raw_input(请输入url:)
 8 
 9 if url.endswith(login):
10     r = account.login()
11     print r
12 
13 elif url.endswith(logout):
14     r = account.logout()
15     print r
16 
17 elif url.endswith(nb):
18     r = account.nb()
19     print r
20 
21 else:
22     print 404
简单的方式

使用反射的方式,一步到位不管你有多少个方法调用,我都支持

 1 #!/usr/bin/env python
 2 #-*- coding:utf-8 -*-
 3 __author__ = wyf
 4 
 5 from lib import account
 6 url = raw_input(请输入url:)
 7 target_module,target_func = url.split(/)
 8 
 9 m = __import__(lib.,target_module,fromlist=True)
10 if hasattr(m,target_func):#判断这个函数里面是否存在这个方法
11     target_func = getattr(account,inp)#获取这个方法
12     r = target_func()#执行这个方法
13     print r
14 else:
15     print 404

 

python-聊聊反射

标签:

原文地址:http://www.cnblogs.com/chushiyaoyue/p/5599297.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!