目录

    1. 应用场景

    1. 通过配置文件,控制程序运行时的流程。配置文件中常保存的是,字符串,而不是对象
    2. 调试程序时,查看对象的全部属性值
    3. 动态模块的导入

    对于第一种场景,广泛被采用的是反射。在Java的很多框架中都使用了反射机制,Python实现的Web框架Django中,也有应用。比如url的路由。第二种场景,手动添加输出某个对象object类的属性值,非常的麻烦,而且不全。这时,可以使用dir(object)列出全部属性,然后使用反射来访问。第三中场景,通过反射也能实现。

    2. Python的反射

    通过反射,可以将字符串和对象的属性关联起来。通过dir(object),可以查看对象obejct的属性列表。

    # -*- coding: utf-8 -*-
    class Person:
        '''
        Python反射的一个举例
        '''
        count = 0
    
        def __init__(self, name="none", salary="0"):
            self.name = name
            self.salary = salary
            Person.count += 1
    
        def getName(self):
            print "i am in getName() function"
            return self.name
    
    
    >>> p = Person(name="csw")
    >>> dir(p)
    ['__doc__', '__init__', '__module__', 'count', 'getName', 'name', 'salary']
    >>> hasattr(p, 'count')
    True
    >>> getattr(p, 'count')
    1
    >>> getattr(p, 'getName')()
    i am in getName() function
    csw
    >>> setattr(p, 'ModifiedName', 'name')
    None
    >>> delattr(p, 'name')
    None
    >>> dir(p)
    ['ModifiedName', '__doc__', '__init__', '__module__', 'count', 'getName', 'salary']
    >>> getattr(p, 'getName')()
    AttributeError: Person instance has no attribute 'name'
    
    

    2.1 getattr

    方式:getattr(object,‘name‘,‘default’)

    说明:如果存在name的属性方法,则返回name的属性方法,否则返回default的属性方法。

    2.2 hasattr

    方式:hasattr(object, ’name‘)

    说明:判断对象object是否包含名为name的属性方法,存在则返回True,否则返回False。hasattr是通过调用getattr(ojbect, ’name‘)是否抛出异常来实现)。

    2.3 setattr

    方式:setattr(object,‘name’,’default‘)

    说明:设置对象object的name属性值为default,如果没有name属性,那么创建一个新的属性。

    2.4 delattr

    方式:delattr(object,’name’)

    说明:删除对象object的name属性值。

    3. Python的反射实现

    globals( )函数返回字典{ key:value },key是对象的名称,value是对象的实例。

    >>> globals()
    {'__builtins__': <module '__builtin__' (built-in)>,
     '__file__': 'E:/code/lab/python-reflection/exapmle.py',
     '__package__': None, 'Person': <class __main__.Person at 0x00215FB8>, 
    '__name__': '__main__', '__doc__': None}
    
    >>> import test
    {'__builtins__': <module '__builtin__' (built-in)>,
     '__file__': 'E:/code/lab/python-reflection/exapmle.py', 
    '__package__': None, 'Person': <class __main__.Person at 0x02045FB8>,
     'test': <module 'test' from 'D:\Python2711\lib\test\__init__.pyc'>, 
    '__name__': '__main__', '__doc__': None}
    
    >>> globals()['test']
    <module 'test' from 'D:\Python2711\lib\test\__init__.pyc'>
    
    

    在执行 import test之后,可以看到新增了 test 的 key。可以利用这一点实现类似 Java 中,Class.forName()的功能。但是这种方法,使用之前必须先 import,否则会抛出异常。

    Python中提供了 __import__(”functionName”)函数,传入参数“functionName”,就可以导入functionName模块。然后结合getattr函数进行相关的调用。

    4. 为什么不直接用 exec和eval

    熟悉python的同学应该知道,exec和eval语句,也可以用来执行储存在字符串或文件中的Python语句。 比如:

    >>> eval('2*3')
    6
    >>> eval("2+3")
    5
    

    那么为什么还要反射呢?使用exec和eval能够实现相同的功能,但是反射是一种编程方法、是设计模式的体现。反射凝聚了高内聚、低耦合的软件设计思想,不能简单的使用执行字符串的函数替代。