一:可调用对象
可调用对象,是任何能通过函数操作符“()”来调用的对象。Python 有4 种可调用对象:函数,方法,类,以及一些类的实例。
1:函数
python 有 3 种不同类型的函数对象。
a:内建函数(BIFs),是用c/c++写的,编译过后放入python 解释器,然后把它们作为内建名字空间的一部分加载进系统。这些函数在_bulitin_模块中。
内建函数属性如下表:
bif.__doc__ | 文档字符串(或None) |
bif.__name__ | 字符串类型的文档名字 |
bif.__self__ | 设置为None(保留给built-in 方法) |
bif.__module__ | 存放bif 定义的模块名字(或None) |
可以用dir()列出函数的所有属性:
>>> dir(type)
['__call__', '__class__', '__cmp__', '__delattr__','__doc__','__getattribute__', '__hash__', '__init__', '__module__','__name__','__new__', '__reduce__', '__reduce_ex__','__repr__', '__self__', '__setattr__','__str__']
因为内建函数(BIFs)和内建方法(BIMs)属于相同的类型,所以对BIF或者BIM 调用type()的结果都是:
>>> type(dir)
<type 'builtin_function_or_method'>
注意这不能应用于工厂函数,因为type()正好会返回产生对象的类型:
>>> type(int)
<type 'type'>
>>> type(type)
<type 'type'>
b:用户定义的函数(UDF),通常是用python 写的,定义在模块的最高级,因此会作为全局名字空间的一部分装载到系统中。函数也可在其他的函数体内定义。
用户自定义函数属性如下表:
udf.__doc__ | 文档字符串(也可以用udf.func_doc) |
udf.__name__ | 字符串类型的函数名字(也可以用 udf.func_name) |
udf.func_code | 字节编译的代码对象 |
udf.func_defaults | 默认的参数元组 |
udf.func_globals | 全局名字空间字典; 和从函数内部调用globals(x)一样 |
udf.func_dict | 函数属性的名字空间 |
udf.func_doc | (见上面的udf.__doc__) |
udf.func_name | (见上面的udf.__name__) |
udf.func_closure | 包含了自由变量的引用的单元对象元组(自用变量在UDF 中使用,但在别处定义) |
用户自定义的函数是“函数“类型的,如:
>>> def foo(): pass
>>> type(foo)
<type 'function'>
c:通过lambda 来创建函数的对象除了没有命名之外,享有和用户自定义函数相同的属性;__name__或者func_name 属性给定为字符串"<lambda>":
>>> lambdaFunc = lambda x: x * 2
>>>type(lambdaFunc)
<type 'function'>
>>> lambdaFunc.__name__
'<lambda>'
一旦函数声明以后(且函数对象可用),程序员也可以自定义函数属性。所有的新属性变成udf.__dict__对象的一部分。
2:方法
a:内建方法(BIM)
内建方法的属性如下表:
bim.__doc__ | 文档字串 |
bim.__name__ | 字符串类型的函数名字 |
bim.__self__ | 绑定的对象 |
只有内建类型(BIT)有BIM。BIM 和BIF 两者也都享有相同属性。不同之处在于BIM 的__self__属性指向一个Python对象,而BIF 指向None:
>>> [1,2,3].append.__self__
[1,2,3]
对于内建方法,type()工厂函数给出了和BIF 相同的输出:
>>>type([].append)
<type'builtin_function_or_method'>
b:用户定义的方法(UDM)
UDM包含在类定义之中,无论UDM是否绑定,所有的UMD 都是相同的类型——“实例方法“,如下例:
>>> class C(object):
... def foo(self): pass
...
>>> c = C()
>>>type(C.foo)
<type'instancemethod'>
>>> type(c.foo)
<type'instancemethod'>
下表展示了UDM的属性:
udm.__doc__ | 文档字符串 |
udm.__name__ | 字符串类型的方法名字(与umd.im_func.__name__相同) |
udm.__module__ | 定义udm 的模块的名字(或none) |
udm.im_class | 方法相关联的类 |
udm.im_func | 方法的函数对象(见UDFs) |
udm.im_self | 如果绑定的话为相关联的实例,如果非绑定位为none |
3:类
“调用”类的结果便是创建了实例,即所谓的实例化。
4:类的实例
python 给类提供了名为__call__的特别方法,该方法允许程序员创建可调用的对象(实例)。
默认情况下,__call__()方法是没有实现的,这意味着大多数实例都是不可调用的。然而,如果在类定义中覆盖了这个方法,那么这个类的实例就成为可调用的了。调用这样的实例对象等同于调用__call__()方法。任何在实例调用中给出的参数都会被传入到__call()__中。例子如下:
>>> class C(object):
... def __call__(self, *args):
... print "I'm callable! Called with args:\n", args
...
>>> c = C()
>>> callable(c)
True
>>> c()
I'm callable! Called with arguments:
()
>>> c(3, 'no more, no less')
I'm callable! Called with arguments:
(3, 'no more, no less')
二:代码对象
每个可调用对象的核心都是代码对象,由语句,赋值,表达式,以及其他可调用对象组成。
一般说来,代码对象可以作为函数或者方法调用的一部分来执行,也可用exec 语句或内建函数eval()来执行。
如果要执行python代码,那么该代码必须先要转换成字节编译的代码(又称字节码)。这才是真正的代码对象。然而,它们不包含任何关于它们执行环境的信息,这便是可调用对象存在的原因,它被用来包装一个代码对象并提供额外的信息。
函数对象仅是代码对象的包装,方法则是函数对象的包装。
三:可执行对象内建函数
1:callable
callable()是一个布尔函数,确定一个对象是否可以通过函数操作符(())来调用。如果函数可调用便返回True,否则便是False:
>>> callable(dir) #内建函数
True
>>> callable(1) #integer #整数
False
>>> def foo(): pass
...
>>> callable(foo) #用户自定义函数
True
>>> callable('bar') #字符串
False
>>> class C(object): pass
...
>>> callable(C) #类
True
2:compile
compile()函数允许在运行时刻动态生成代码对象,然后就可以用exec语句或者内建函数eval()来执行这些对象或者对它们进行求值。
exec 和eval()都可以执行字符串格式的Python 代码。当执行字符串形式的代码时,每次都必须对这些代码进行字节编译处理。compile()函数提供了一次性字节代码预编译,以后每次调用的时候,都不用编译了。
compile 的三个参数都是必需的,第一参数代表了要编译的python代码。第二个字符串,虽然是必需的,但通常被置为空串。该参数代表了存放代码对象的文件的名字(字符串类型)。最后的参数是个字符串,它用来表明代码对象的类型。有三个可能值:’eval’, 'single', ’exec’
'eval' 可求值的表达式[和eval()一起使用],若第一个参数是语句的话,则会返回错误,比如:
>>> astr = "print'hello ,world'"
>>> compile(astr, '','eval')
Traceback (most recent calllast):
File "<stdin>", line 1, in <module>
File "", line 1
print 'hello ,world'
^
SyntaxError: invalid syntax
'single' 单一可执行语句[和exec 一起使用],如果有多条语句的话,则只会编译第一句。
'exec' 可执行语句组[和exec 一起使用]。例子如下:
>>> eval_code = compile('100 + 200', '', 'eval')
>>> eval(eval_code)
300
>>> single_code = compile('print "Hello world!"', '','single')
>>> single_code
<code object ? at 120998, file "", line 0>
>>> exec single_code
Hello world!
>>> exec_code = compile("""
... req = input('Count how many numbers? ')
... for eachNum in range(req):
... print eachNum
... """, '', 'exec')
>>> exec exec_code
Count how many numbers? 6
0
1
2
3
4
5
3:eval
eval()对表达式求值,不能处理语句。第一个参数可以为字符串或内建函数complie()创建的预编译代码对象。第二个和第三个参数,都为可选的,分别代表了全局和局部名字空间中的对象。如果给出这两个参数,globals 必须是个字典,locals可以是任意的映射对象。
如果都没给出这两个参数,分别默认为globals()和locals()返回的对象,如果只传入了一个全局字典,那么该字典也作为locals 传入。例子如下:
>>> eval('100 + 200')
300
在这种情况下,eval()接收一个字符串并把"100+200"作为表达式求值,当进行整数加法后,给出返回值300。
eval()函数的工作方式:对表达式两端的引号视而不见,接着假设“如果我是python 解释器,我会怎样去观察表达式呢?”,换句话说,如果以交互方式输入相同的表达式,解释器会做出怎么样的反应呢?按下回车后的结果应该和eval()返回的结果相同。
4:exec
exec 语句执行代码对象或字符串形式的python代码。类似地,用compile()预编译重复代码有助于改善性能。
exec 语句只接受一个参数,下面便是它的通用语法:exec obj
被执行的对象(obj)可以只是原始的字符串,比如单一语句或是语句组,它们也可以预编译成一个代码对象。例子如下:
>>> exec """
... x = 0
... print 'x is currently:', x
... while x < 5:
... x += 1
... print 'incrementing x to:', x
... """
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
exec 还可以接受有效的python 文件对象。如果我们用上面的多行代码创建一个叫xcount.py 的文件,那么也可以用下面的方法执行相同的代码:
>>> f = open('xcount.py')
>>> exec f
x is currently: 0
incrementing x to: 1
incrementing x to: 2
incrementing x to: 3
incrementing x to: 4
incrementing x to: 5
5:input
input()是eval()和raw_input()的组合,等价于eval(raw_input())。
类似于raw_input(),input()有一个可选的参数,该参数代表了给用户的字符串提示。该字符串默认为空串。
从功能上看,input 不同于raw_input(),因为raw_input()总是以字符串的形式,逐字地返回用户的输入。input()履行相同的的任务;而且,它还把输入作为python 表达式进行求值。这意味着input()返回的数据是对输入表达式求值的结果:一个python 对象。例子如下:
>>> aString = raw_input('Enter a list: ')
Enter a list: [ 123, 'xyz', 45.67 ]
>>> aString
"[ 123, 'xyz', 45.67 ]"
>>> type(aString)
<type 'str'>
>>> aList = input('Enter a list: ')
Enter a list: [ 123, 'xyz', 45.67 ]
>>> aList
[123, 'xyz', 45.67]
>>> type(aList)
<type 'list'>
虽然用户输入字符串,但是input()把输入作为python 对象来求值并返回表达式的结果。
四:执行其他Python程序
1:execfile()
通过exec语句来读取python脚本的内容并执行,例子如下:
f = open(filename, 'r')
exec f
f.close()
这3行可以调用execfile()来换掉:execfile(filename)
在某些情况下,可能需要用不同全局和局部的名字空间集合,而不是默认的集合来执行模块。execfile() 函数的语法非常类似于eval()函数的:
execfile(filename, globals=globals(), locals=locals())
类似eval(),globals 和locals 都是可选的,如果不提供参数值的话,默认为执行环境的名字空间。如果只给定globals,那么locals 默认和globals 相同。
2:将模块作为脚本执行
python2.4 里加入了一个新的命令行选项-m, 允许从shell 或DOS 提示符,直接把模块作为脚本来执行。
模块是标准库的一部分,安装在site-packages 里,或者仅仅是包里面的模块,那直接运行该模块脚本就不是那么容易了。比如,想运行免费的python web 服务器,以便创建和测试你自己的web 页面和CGI 脚本。则必须在命令行敲入如下的东西:
$ python /usr/local/lib/python2x/CGIHTTPServer.py
Serving HTTP on 0.0.0.0 port 8000 ...
如果它是第三方的,则不得不深入到site-packages 去找到它真正定位的地方。
如果不给出完全的路径名,可以用python -c 命令行开关,从命令行运行一个模块,并让python 的导入机制做这种跑腿工作:
$ python -c "import CGIHTTPServer; CGIHTTPServer.test()"
该选项允许指定想要运行的python 语句。虽然这样可以工作,但是__name__模块不是‘__main__’,而是你正在使用的模块。解释器通过import 装载了你的模块,并不是它当作脚本。因此,所有在if __name__ == '__main__' 之下的代码是不会执行的,所以不得不手动地调用模块的test()函数。
要想同时要两者的优点——能够在类库中作为脚本执行模块,而不是作为导入的模块。这就是-m 参数的动机。现在可以像这样运行脚本:
$ python -m CGIHTTPServer
五:执行其他非Python程序
也可以执行非python 程序。这些程序包括了二进制可执行文件,其他的shell 脚本等等。
1:os.system
一个非常简单的函数,接收字符串形式的系统命令并执行它。当执行命令的时候,python的运行是挂起的。当我们的执行完成之后,将会以system()的返回值形式给出退出状态,python 的执行也会继续。
system()保留了现有的标准文件,包括标准的输出,意味着执行任何的命令和程序显示输出都会传到标准输出上。
system()通常和不会产生输出的命令一起使用,通过退出状态显示成功或失败,0 表示成功,非零表示其他类型的错误。例子如下:
>>> import os
>>> result = os.system('cat /etc/motd') Have a lot of fun...
>>> result
0
>>> result = os.system('uname -a')
Linux solo 2.2.13 #1 Mon Nov 8 15:08:22 CET 1999 i586 unknown
>>> result
0
六:结束执行
1:sys.exit() 和 SystemExit
立即退出程序并返回调用程序的主要方式是sys模块中的exit()函数。语法为:
sys.exit(status=0)
当调用sys.exit()时,就会引发systemExit()异常。除非对异常在一个try 语句和合适的except子句中进行捕获,否则解释器会用给定的状态参数退出,如果没有给出的话,该参数默认为0。
SystemExit 是唯一不看作错误的异常。它仅仅表示要退出python。
2:os.kill
os 模块的kill()函数模拟传统的unix函数来发送信号给进程。kill()参数是进程标识数(PID)和你想要发送到进程的信号。发送的典型信号为SIGINT、SIGQUIT或SIGKILL,来使进程终结。