Python强大的自省简析

1. 什么是自省?

自省就是自我评价、自我反省、自我批评、自我调控和自我教育,是孔子提出的一种自我道德修养的方法。他说:“见贤思齐焉,见不贤而内自省也。”(《论语·里仁》)当然,我们今天不是想说党员的批评与自我批评。表明意思上,自省(introspection)是一种自我检查行为。在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。
本文介绍了 Python 编程语言的自省能力。整个 Python 语言对自省提供了深入而广泛的支持。实际上,很难想象假如 Python 语言没有其自省特性是什么样子。

2. Python的help

在进入python的终端IDE时我们就能见到help的身影:

[email protected]:~/repository/blog/python$ python
Python 2.7.3 (default, Jan  2 2013, 16:53:07)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.	

最后一行清晰的提释我们可以输入help来获取更多的信息。

>>> help		# 输入help之后,系统提示输入help()进入交互式的help界面,或者使用help(obj)来获取obj的help信息
Type help() for interactive help, or help(object) for help about object.
>>> help()		# 输入help()

Welcome to Python 2.7!  This is the online help utility.

If this is your first time using Python, you should definitely check out
the tutorial on the Internet at http://docs.python.org/2.7/tutorial/.

Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules.  To quit this help utility and
return to the interpreter, just type "quit".

To get a list of available modules, keywords, or topics, type "modules",
"keywords", or "topics".  Each module also comes with a one-line summary
of what it does; to list the modules whose summaries contain a given word
such as "spam", type "modules spam".

help> 			# 在输入一段“说明”后,进入交互式help界面(Ctrl+C或者输入quit退出)
help> list		# 输入list之后进入另一类似于“man”的窗口,完整介绍list

help> keywords	# 输入keywords只打印python的关键字列表

Here is a list of the Python keywords.  Enter any keyword to get more help.

and                 elif                if                  print
as                  else                import              raise
assert              except              in                  return
break               exec                is                  try
class               finally             lambda              while
continue            for                 not                 with
def                 from                or                  yield
del                 global              pass 

help> if		# 输入关键字if,也是类似于上面list在另一窗口下介绍if

当然,我们也可以在python的IDE下使用help(object)来获取某一对象的help信息,比如:

>>> help(os)		# 想看os模块?^_^,没门,你还没加载呢
Traceback (most recent call last):
  File "", line 1, in
NameError: name ‘os‘ is not defined
>>> import os
>>> help(os)		# 加载之后即可查看os的help信息了

>>> 

3. sys 模块

对于sys模块,使用比较频繁见的也比较多,那么它是干吗的?python官网是这么介绍的:“System-specific parameters and functions”(系统特定的参数和函数)。所以sys 模块是提供关于 Python 本身的详尽内在信息的模块。通过导入模块,并用点(.)符号引用其内容(如变量、函数和类)来使用模块。 sys 模块包含各种变量和函数,它们揭示了当前的 Python 解释器有趣的详细信息。

platform 变量告诉我们现在处于什么操作系统上: sys.platform 属性

>>> import sys
>>> sys.platform
‘linux2‘

在当前的 Python 中,版本以字符串和元组(元组包含对象序列)来表示:

>>> sys.version
‘2.7.3 (default, Jan  2 2013, 16:53:07) \n[GCC 4.7.2]‘
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=3, releaselevel=‘final‘, serial=0)

maxint 变量反映了可用的最大整数值: sys.maxint 属性

>>> sys.maxint
2147483647

argv 变量是一个包含命令行参数的列表(如果参数被指定的话)。第一项 argv[0] 是所运行脚本的路径。当我们以交互方式运行 Python 时,这个值是空字符串: sys.argv 属性

>>> sys.argv
[‘‘]

关于sys.argv的使用,我们在前面介绍函数的学习笔记中已有介绍,它可以用来接收函数的脚本,比如:

#!/usr/bin/python
import sys
print"The script name is "+sys.argv[0]
print"The first parameter is %s" % sys.argv[1]
print"The second parameter is %r" % sys.argv[2]

在脚本使用时,我们可以给脚本带入参数:
[email protected]:/tmp/test$ python arg.py 1 2 3 # 虽然程序中只要求打印前2个参数,但是我们也可以带更多的,只是没打印而已

The script name is arg.py
The first parameter is 1
The second parameter is ‘2‘

path 变量是模块搜索路径,Python 在导入期间将在其中的目录列表中寻找模块。:sys.path 属性

>>> sys.path
[‘‘, ‘/home/pobrien/Code‘,            # 最前面的空字符串 ‘‘ 是指当前目录
‘/usr/local/lib/python2.2‘,
‘/usr/local/lib/python2.2/plat-linux2‘,
‘/usr/local/lib/python2.2/lib-tk‘,
‘/usr/local/lib/python2.2/lib-dynload‘,
‘/usr/local/lib/python2.2/site-packages‘]

modules 变量是一个字典,它将当前已装入的所有模块的名称映射到模块对象。如您所见,缺省情况下,Python 装入一些特定的模块: sys.modules 属性

>>> sys.modules
{‘stat‘: <module ‘stat‘="" from="" ‘="" usr="" local="" lib="" python2.2="" stat.pyc‘="">,
‘__future__‘: <module ‘__future__‘="" from="" ‘="" usr="" local="" lib="" python2.2="" __future__.pyc‘="">,
‘copy_reg‘: <module ‘copy_reg‘="" from="" ‘="" usr="" local="" lib="" python2.2="" copy_reg.pyc‘="">,
‘posixpath‘: <module ‘posixpath‘="" from="" ‘="" usr="" local="" lib="" python2.2="" posixpath.pyc‘="">,
‘UserDict‘: <module ‘userdict‘="" from="" ‘="" usr="" local="" lib="" python2.2="" userdict.pyc‘="">,
‘signal‘: <module ‘signal‘="" (built-in)="">,
‘site‘: <module ‘site‘="" from="" ‘="" usr="" local="" lib="" python2.2="" site.pyc‘="">,
‘__builtin__‘: <module ‘__builtin__‘="" (built-in)="">,
‘sys‘: <module ‘sys‘="" (built-in)="">,
‘posix‘: <module ‘posix‘="" (built-in)="">,
‘types‘: <module ‘types‘="" from="" ‘="" usr="" local="" lib="" python2.2="" types.pyc‘="">,
‘__main__‘: <module ‘__main__‘="" (built-in)="">,
‘exceptions‘: <module ‘exceptions‘="" (built-in)="">,
‘os‘: <module ‘os‘="" from="" ‘="" usr="" local="" lib="" python2.2="" os.pyc‘="">,
‘os.path‘: <module ‘posixpath‘="" from="" ‘="" usr="" local="" lib="" python2.2="" posixpath.pyc‘="">}

4.中的自省模块

在阅读dive into python时,第四章讲到了自省,代码如下:

# apihelper.py
def info(object, spacing=10, collapse=1):
    """Print methods and doc strings.

    Takes module, class, list, dictionary, or string."""
    methodList = [method for method in dir(object) if callable(getattr(object, method))]
    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
    print "\n".join(["%s %s" %
                      (method.ljust(spacing),
                       processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])

使用起来也很方便,如下:

>>> from apihelper import info
>>> li = []
>>> info(li)
__add__    x.__add__(y) <==> x+y
__class__  list() -> new empty list list(iterable) -> new list initialized from iterable‘s items
...
>>> import apihelper
>>> info(apihelper)
info       Print methods and doc strings. Takes module, class, list, dictionary, or string.
>>> info(apihelper,20)
info                 Print methods and doc strings. Takes module, class, list, dictionary, or string.
>>> info(apihelper,20,0)
info                 Print methods and doc strings.

	Takes module, class, list, dictionary, or string.

4.1. 几个内置函数介绍

其中使用了几个函数,主要介绍如下:
dir([obj]): 
dir() 函数可能是 Python 自省机制中最著名的部分了。它返回传递给它的任何对象的属性名称经过排序的列表(会有一些特殊的属性不包含在内)。如果不指定对象,则 dir() 返回当前作用域中的名称(obj的默认值是当前的模块对象)。

eg.

>>> li
[1, 4, 8, 16, 2, 3]
>>> dir(li)
[‘__add__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__delslice__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__getslice__‘, ‘__gt__‘, ‘__hash__‘, ‘__iadd__‘, ‘__imul__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__reversed__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__setslice__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘append‘, ‘count‘, ‘extend‘, ‘index‘, ‘insert‘, ‘pop‘, ‘remove‘, ‘reverse‘, ‘sort‘]

getattr(obj, attr):
getattr是一个有用到无法置信的内置函数(自省的核心哦),可以返回任意对象的任何属性。调用这个方法将返回obj中名为attr值的属性的值,例如如果attr为‘bar‘,则返回obj.bar。使用getattr函数,可以得到一个直到运行时才知道名称的函数的引用。getattr的返回值是方法,可以调用。

eg.

	>>> li
	[1, 4, 8, 16]
	>>> li.append(2)
	>>> li
	[1, 4, 8, 16, 2]
	>>> getattr(li,‘append‘)(3)
	>>> li
	[1, 4, 8, 16, 2, 3]

类似还有:
hasattr(obj, attr): 
这个方法用于检查obj是否有一个名为attr的值的属性,返回一个布尔值。
setattr(obj, attr, val): 
调用这个方法将给obj的名为attr的值的属性赋值为val。例如如果attr为‘bar‘,则相当于obj.bar = val。

callable(obj):
可以调用表示潜在行为(函数和方法)的对象。可以用 callable() 函数测试参数对象的可调用性,参数对象可调用返回True,否则返回False。

eg.

>>> li
[1, 2 , 4, 8, 16]
>>> callable(li)
False
>>> callable(li.append)
True

string.ljust(length):
ljust用空格填充字符串以符合指定的长度。如果指定的长度(length)小于字符串的长度(len(string)),ljust将简单滴返回未变化的字符串,不会截断字符串。

eg.

	>>> s = "Zhou"
	>>> print s.ljust(10)+"Hello"
	Zhou      Hello
	>>> print s.ljust(1)+"Hello"
	ZhouHello

4.2. 列表解析

Python有着强大的列表解析即将列表映射到其他列表的强大能力。列表解析同过滤机制结合使用,使列表中有些元素被映射而跳过其他元素。
列表解析:
[mapping-expression for item in source-list]
eg.
>>> li = [1,2,4,8,16]
>>> [item*2 for item in li]
[2, 4, 8, 16, 32]
过滤列表语法: 
[mapping-expression for item in source-list if filter-expression]
eg.
>>> li = [1,2,4,8,16]
>>> [item*2 for item in li if item%2 == 0]
[4, 8, 16, 32]
如上所示,过滤列表就是列表解析的扩展,前三部分是相同的,最后一步分添加if开头的过滤表达式(过滤表达式可以是返回值为真或假的任何表达式,而在Python中几乎是任何东西)。

注意:如果仔细查看上面的apihelper.py实例,可以发现作者将一行命令放在多行,这也可以?这里可以告诉你的是“列表解析是可以一个表达式分割成多行的”,因为整个表达式都在一个方括号中括起来了。

4.3 逐析模块

对于上述模块中还有一些用法在上面两节中并没有提及。比如and-or用法和lambda函数,这些都在本系列的前文学习笔记中有所涉及,本文再不赘述。

下面对于上述模块逐句进行分析:
def info(object, spacing=10, collapse=1):
# 首先,我们可以看到,定义的函数使用了三个参数:
@ object -- 当然是我们想要查看的目标了,本函数使用dir获取object的属性,而又因dir函数的强大,所以此处的object可以是python中的任意东西,包括模块对象、函数对象、字符串对象、列表对象、字典对象...
@ spacing = 10,这里定义了一个关键参数,也就是说,如果调用info函数时没有给spacing赋值,spacing将使用默认的10。那么这个spacing是干吗的?向下看,对!没错它是给ljust做参数的!也就是说长度不足10的字符串会使用空格补气,而超过10的不做修改
@ collapse = 1,这里也定了一个关键参数,如果不赋值,使用默认值1。collapse在函数中用作and-or用法的判断语句。
"""Print methods and doc strings.

Takes module, class, list, dictionary, or string."""
# 这是什么?没错,当然是docstring了
methodList = [method for method in dir(object) if callable(getattr(object, method))]
# 使用上面介绍的过滤列表,首先使用dir对object解析获取object的所有属性的一个列表,使用列表解析对其进行映射并通过if对其进行过滤,过滤条件是object.method可调用!因此,最后得到的methodList是一个object的所有可调用的属性的列表
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
# 这一句定义了一个函数,对,只有一行的lambda函数哦,并使用第三个参数作为and-or用法的判断。如果collapse为True,processFunc = lambda s: " ".join(s.split()),也即将s先使用split函数分割在使用" ".join将其使用空格连接起来。如果collapse为False,processFunc = lambda s: s,也即对s不做任何处理
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
# 这里就是上面提到的将列表解析放在几行中使用的一个典型案例,首先使用method遍历methodList列表(上面获得的object的所有可调用的属性的列表),在使用processFunc对object.method的__doc__(docstring)进行处理,与使用ljust调整好的method名一同打印出来。并使用"\n".join将每个不同的method信息之间进行分割,分割在不同行打印。

5. 打印一些函数的可获取信息

下面是《Python 自省指南》中使用到的自省方法,主要使用了一些内置函数(id(),type(),repr()等)打印对象的信息:

def interrogate(item):
    """Print useful information about item."""
    if hasattr(item, ‘__name__‘):
        print "NAME:    ", item.__name__
    if hasattr(item, ‘__class__‘):
        print "CLASS:   ", item.__class__.__name__
    print "ID:      ", id(item)
    print "TYPE:    ", type(item)
    print "VALUE:   ", repr(item)
    print "CALLABLE:",
    if callable(item):
        print "Yes"
    else:
        print "No"
    if hasattr(item, ‘__doc__‘):
        doc = getattr(item, ‘__doc__‘)
    doc = doc.strip()   # Remove leading/trailing whitespace.
    firstline = doc.split(‘\n‘)[0]
    print "DOC:     ", firstline

我们把它添加到apihelper模块中作为我们的自省模块的另一个方法,使用起来如下:

>>> import apihelper            # 加载我们的apihelper
>>> apihelper.info(apihelper)   # 调用前面的info函数查看apihelper中有哪些属性
info       Print methods and doc strings. Takes module, class, list, dictionary, or string.
interrogate Print useful information about item.
>>> apihelper.interrogate(apihelper)    # 使用interrogate查看我们的apihelper的信息
NAME:     apihelper
CLASS:    module
ID:       3075144100
TYPE:     <type ‘module‘="">
VALUE:    <module ‘apihelper‘="" from="" ‘apihelper.py‘="">
CALLABLE: No
Traceback (most recent call last):
  File "", line 1, in
  File "apihelper.py", line 30, in interrogate
    doc = doc.strip()   # Remove leading/trailing whitespace.
AttributeError: ‘NoneType‘ object has no attribute ‘strip‘
>>> apihelper.interrogate(apihelper.info)   # 查看apihelper.info信息
NAME:     info
CLASS:    function
ID:       3075150932
TYPE:     <type ‘function‘="">
VALUE:
CALLABLE: Yes
DOC:      Print methods and doc strings.
>>> apihelper.interrogate(123)              # 查看整数的信息
CLASS:    int
ID:       153002672
TYPE:     <type ‘int‘="">
VALUE:    123
CALLABLE: No
DOC:      int(x[, base]) -> integer
>>> apihelper.interrogate("Hello")          # 查看字符串的信息
CLASS:    str
ID:       3075198208
TYPE:     <type ‘str‘="">
VALUE:    ‘Hello‘
CALLABLE: No
DOC:      str(object) -> string

至此,我们的自省模块apihelper也就有了比较强大的功能,其自省能力也是不错的~~~

时间: 2024-10-13 18:08:33

Python强大的自省简析的相关文章

10个好用的Python集成开发环境简析

Python IDE工具是每个Python工程师必须使用的开发工具,选择正确的编辑器对Python编程效率的影响是非常大的,因此选择合适的Python开发工具十分重要,以下是通过长期实践发掘的好用的Python IDE,它们功能丰富,性能先进,能够帮助开发人员快速的进行应用程序开发. 1. Pydev + Eclipse – 最好的免费python IDE Pydev的是Python IDE中使用最普遍的,原因很简单,它是免费的,同时还提供很多强大的功能来支持高效的Python编程.Pydev是

python __init__() 和__new__()简析

先看下面一个例子: 如上图,例1中,构造了函数Foo,并重写了__new__()和__init__()方法,在实例化Foo()的时候,却只调用了__new__() 例2中,在实例化Too()对象时,同时调用了__new__()和__init__()方法. 实例化对象的本质都是三个过程:创建实例对象,初始化实例对象和返回实例化对象 上面函数的__new__()方式,实际上就是在创建实例化对象,它有一个必传的参数,cls:cls是当前正在实例化的类. 而__init__()则是在初始化实例对象. 在

功能强大的图片截取修剪神器:Android SimpleCropView及其实例代码重用简析(转)

功能强大的图片截取修剪神器:Android SimpleCropView及其实例代码重用简析 SimpleCropView是github上第一个第三方开源的图片修剪截取利器,功能强大,设计良好.我个人认为SimpleCropView比附录文章1介绍的cropper更为强大和完备,但也更为复杂,如果是简单的应用场景,那么cropper也是一个不错的选择,SimpleCropView则适应图片裁剪截取复杂的需求任务.SimpleCropView在github上的项目主页是:https://githu

[转载] Thrift原理简析(JAVA)

转载自http://shift-alt-ctrl.iteye.com/blog/1987416 Apache Thrift是一个跨语言的服务框架,本质上为RPC,同时具有序列化.发序列化机制:当我们开发的service需要开放出去的时候,就会遇到跨语言调用的问题,JAVA语言开发了一个UserService用来提供获取用户信息的服务,如果服务消费端有PHP/Python/C++等,我们不可能为所有的语言都适配出相应的调用方式,有时候我们会很无奈的使用Http来作为访问协议;但是如果服务消费端不能

JDK源码简析--java.util包中的工具类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.util包所包

ONOS预热篇之架构简析(二)

ONOS是首款专门面向服务提供商和企业骨干网的开源SDN网络操作系统,是由一家名为开放网络实验室(ON.Lab)的非盈利性组织打造的一款商用控制器,并将于美国时间2014年12月5日全球首发.ONOS旨在为服务提供商和企业骨干网提供高可用性(HA).可横向扩展及高性能的网络需求.由于该项目得到了业界各知名大佬包括服务提供商AT&T.NTT,网络供应商Ciena.Ericsson.Fujitsu.Huawei.Intel.NEC,网络运营商Internet2.CNIT.CREATE-NET的资助和

JUC锁简析(基于源码的详解后续会陆续发出)

张图说明下要分享的内容: 01. Lock接口 JUC包中的 Lock 接口支持那些语义不同(重入.公平等)的锁规则.所谓语义不同,是指锁可是有"公平机制的锁"."非公平机制的锁"."可重入的锁"等等. "公平机制"是指"不同线程获取锁的机制是公平的", 而"非公平机制"则是指"不同线程获取锁的机制是非公平的","可重入的锁"是指同一个锁能够被一个

web应用构架LAMT及tomcat负载简析

Httpd    (mod_jk.so) workers.properties文件 uriworkermap.properties文件 <--AJP1.3--> Tomcat  --> jdk 大致流程:apache服务器通过mod_jk.so 模块处理jsp文件的动态请求.通过tomcat worker等待执行servlet/JSP的tomcat实例.使用 AJP1.3协议与tomcat通信.tomcat有借助jdk解析. 负载就是 多台tomcat.共同解析apache发送的jsp请

CentOS的网络配置简析

我们在进行对CentOS的网络配置时,一般会从IP地址(IPADDR).子网掩码(NETMASK).网关(Gateway).主机名(HOSTNAME).DNS服务器等方面入手.而在CentOS中,又有着不同的命令或配置文件可以完成这些配置操作,接下来,我们将从ifcfg系命令,iproute2系命令以及配置文件3个方面来简析网络配置的方法. 一.ifcfg系命令 ifcfg系命令包括ifconfig,route,netstat和hostname. 1.ifconfig命令 用来配置一个网络接口.