本篇是python getattr反射函数的结束篇,在上一篇 python反射与自省getattr应用篇 的结尾我们提到了getattr有相关的模块。本篇虽然也与getattr函数相关,但主要总结getattr相关的函数和模块方法---hasattr、setattr、delattr、inspect模块。

一、hasattr、setattr与delattr

这里我先创建一个简单的类:

 1#!/usr/bin/python
 2# coding=utf-8
 3## author: yangbk([email protected])
 4## site: www.361way.com
 5## desc: test hasattr、setattr 、delattr and getattr
 6class test:
 7    def __init__(self):
 8        self.name = 'www.361way.com'
 9    def setName(self,name):
10        self.name = name
11    def getName(self):
12        return self.name
13    def greet(self):
14        print "Hello,I'm %s" %self.name
15foo = test()

1、hasattr(object,name)

hasattr判断object中是否具有name属性,返回的是一个布尔值。存在则返回True,不存在返回flase 。

1foo = test()
2print hasattr(foo,'abc')

在类实例化后,通过上面的方法调用测试,因为不存在abc,方法,所以这里返回flase。将abc更换为getName则返回True 。

2、setattr(object,name,default)

该函数会对现有的name字符串赋值或新增一个name并对其赋值。在对上面的test类实例化为foo后,在其后加入如下代码:

1setattr(foo,'age',18)
2print getattr(foo,'age')
3print getattr(foo,'name')
4setattr(foo,'name','newname')
5print getattr(foo,'name')

执行后输出内容如下:

118
2www.361way.com
3newname

3、delattr(object,’name’)

其主要用于删除一个name字符串的值。后面新增代码如下:

1delattr(foo,'name')
2print getattr(foo,'name','not find')

这里执行后的输出为not find 。

上面这个示例的完整代码我已上传至github上

二、inspect模块

inspect模块提供了一系列函数用于帮助使用自省。下面仅列出较常用的一些函数,想获得全部的函数资料可以查看inspect模块的文档。

1、检查对象类型

is{module|class|function|method|builtin}(obj):

检查对象是否为模块、类、函数、方法、内建函数或方法。

isroutine(obj):

用于检查对象是否为函数、方法、内建函数或方法等等可调用类型。用这个方法会比多个is*()更方便,不过它的实现仍然是用了多个is*()。还是上面的例子,我们在foo实例化test类以后,加入以下代码:

1im = foo.greet
2import inspect
3if inspect.isroutine(im):
4        im()

由于greet函数存在,所以if判断是成立的,执行后打印greet输出。如果不先进行实例化,直接调用,会报这么一个错误:TypeError: unbound method greet() must be called with test instance as first argument (got nothing instead)

bound和unbound在这里的区别是:

  • im = test.greet —>直接使用类用调用其内部方法是unbound的
  • im = foo.greet —->通过实例化再调用类内的方法是bound的

2、获取对象信息

getmembers(object[, predicate]):

这个方法是dir()的扩展版,它会将dir()找到的名字对应的属性一并返回,形如[(name, value), …]。另外,predicate是一个方法的引用,如果指定,则应当接受value作为参数并返回一个布尔值,如果为False,相应的属性将不会返回。使用is*作为第二个参数可以过滤出指定类型的属性。

getmodule(object):

还在为__module__属性只返回字符串而遗憾吗?这个方法一定可以满足你,它返回object的定义所在的模块对象。

get{file|sourcefile}(object):

获取object的定义所在的模块的文件名|源代码文件名(如果没有则返回None)。用于内建的对象(内建模块、类、函数、方法)上时会抛出TypeError异常。

get{source|sourcelines}(object):

获取object的定义的源代码,以字符串|字符串列表返回。代码无法访问时会抛出IOError异常。只能用于module/class/function/method/code/frame/traceack对象。

getargspec(func):

仅用于方法,获取方法声明的参数,返回元组,分别是(普通参数名的列表, *参数名, **参数名, 默认值元组)。如果没有值,将是空列表和3个None。如果是2.6以上版本,将返回一个命名元组(Named Tuple),即除了索引外还可以使用属性名访问元组中的元素。

getargvalues(frame):

仅用于栈帧,获取栈帧中保存的该次函数调用的参数值,返回元组,分别是(普通参数名的列表, *参数名, **参数名, 帧的locals())。如果是2.6以上版本,将返回一个命名元组(Named Tuple),即除了索引外还可以使用属性名访问元组中的元素。

getcallargs(func[, *args][, **kwds]):

返回使用args和kwds调用该方法时各参数对应的值的字典。这个方法仅在2.7版本中才有。

getmro(cls):

返回一个类型元组,查找类属性时按照这个元组中的顺序。如果是新式类,与cls.__mro__结果一样。但旧式类没有__mro__这个属性,直接使用这个属性会报异常,所以这个方法还是有它的价值的。

currentframe():

返回当前的栈帧对象。

注:关于inspect获取对象信息这部分,看的感觉有点云里雾里的,并不完全理解。所以这里只是列出查到的具体的方法意义,未对其做示例说明。