执行环境
1. 可调用对象
可调用,即可以通过函数操作符“()”来调用的对象,包括函数、方法、类、实例。
1.1 函数
Python有三类函数, 即内置函数(Build-in Function, BIF)和用户定义函数(User Defined Function, UDF) 和 lambda表达式。
内置函数 BIF
定义在模块__bulitin__中的函数,整个__bulitin__会被默认地载入Python 解释器,print locals(), 会看到:
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
print __bulitins__.__dict__就可以看到内置函数列表(其实不止内置函数)。
假如bif为一个内置函数,那么可以通过bif.__doc__查看函数的文档——其实函数就是Python中一种特殊的类型,也是有它自己的一系列属性的。
用户定义函数 UDF
用户定义在模块最外层(最顶级)的函数。
lambda表达式
用lamdba表达式生成的匿名函数。
使用方法如:
# 方法 1,即匿名函数直接作为参数传入。
sortedDictItems = sorted(d.items(), key = lamdba x:x[1], reverse=True)
# 方法 2,将匿名函数赋予一个引用,然后通过函数引用调用。
lambdaFunc = lambda x: x * 2
lambdaFunc(2) /*结果 4*/
print lambdaFunc.__doc__ /*结果 <lambda>*/
1.2 方法
方法实际上就是定义在类内部的函数。 也可以分为内置方法(BIM)和用户自定义方法(UDM).
1.3 类
假设类名为A,则 a = A()会生成类的一个实例,也就是说,类的调用实际上就是实例化的过程。
1.4 实例
一般情况下,实例是不能(通过函数操作符“()”)调用的,但如果类实现了__call__方法的话,那么该类的实例就能通过函数操作符()调用了,其行为即__call__函数的行为。
class A(object):
def __call__(self, *args):
print 'now instance is callable, args:', args
a = A()
a(self, 1, 'parameter 2')
/*结果:now instance is callable, args: (1, 'parameter 2')*/
2. 代码对象
- 代码对象的定义:Python代码编译而成的字节码(Python代码执行都需要先转化成字节码).
- 代码对象的执行:可以作为函数或者方法的一部分来执行,也可以用内建函数exec或者eval来执行。
- 代码对象与函数、方法:在用户自定义函数UDF中,有一个属性udf.func_code, 即函数的字节码,而在用户自定义方法UDM中,有一个属性udm.im_func即方法对应的函数,而udm.im_func.func_code就是其字节码,也就是说,代码对象、函数、方法之间构成了这样的一种关系——函数对象是对代码对象的包装,方法则是对函数的包装。
3. 代码的编译与执行
介绍几个用于编译和执行代码(字节码代码对象或者字符串代码)的函数。
3.1 callable
callable(obj)判断obj是否可调用。
3.2 compile
输入字符串代码,生成代码对象,用于eval或者exec中执行,而不必在eval或者exec中每次都重新去编译一次。
compile有三个参数:
compile(code, filename, type)
即字符串代码,保存代码对象的文件名(通常我们并不保存为文件,因此置为空串),代码对象类型,类型有三种:
- 'eval': 用于eval函数的可求值的表达式
- 'single': 用于exec的单一可执行语句
- 'exec': 用于exec的可执行语句组
如:
eval_code = compile('100 + 200', '', 'eval')
eval(eval_code) /*结果:300*/
single_code = compile('print "hi"', '', 'single')
exec(single_code) /*结果:hi*/
3.3 eval
对表达式进行求值,当然其中还包括将代码中的变量转化为合适的类型,因此:eval('[1,2,3]')会返回一个list类型的[1,2,3].
eval有三个参数,eval(code, globals, locals),即:
- 代码(字符串,or 代码对象)
- 全局空间中的对象:必须是个字段,一般不传这个参数,默认为globals()
- 局部作用域中的对象,一般不传这个字段,默认为locals()
3.4 exec
exec可以执行的对象有三种:
- 字符串代码
- 代码对象(如compile编译成的代码对象)
-
文件对象(如python代码文件),执行完一遍之后,文件指针就移到了文件末尾。
f = open('code.py') exec f print f.tell(), os.path.getsize('code.py') /*两者相等*/ f.seek(0) /*重新移回文件头*/ exec f /*又可以执行了*/
一种应用的场景是可以根据用户的输入,在运行时来生成并执行不同的代码,不过问题是,这不也能通过函数和函数参数来实现吗,有不能用函数而需要动态生成代码的场景吗?
3.5 input
相当于eval(raw_input()), raw_input得到字符串形式的用户输入,eval再将它转化为合适的类型返回。
str_input = raw_input('please enter a list:')
//输入[1, 2, 3]后的结果是 字符串"[1,2,3]"
processed = input('please enter a list')
// 输入[1,2,3]后返回即是list类型的[1,2,3]
3.6 其他代码执行方式
- import导入模块:导入时会执行模块最外层的代码(因此最外层的可执行代码中那句判断if __name__ == __main__是多么地重要!)。
-
execfile(file_name):执行代码文件,相当于:
f = open(filename, 'r') exec f f.close()
- 将模块最为模块执行, 即python code.py para1 para2
4. 执行非Python程序
主要是通过os系列函数来执行其他非Python程序。
4.1 os.system(cmd)
执行cmd(shell) 命令。
会像执行cmd程序一样,将结果直接输出到stdout上,因此在特定的应用程序如CGI中可能会导致出问题--将我们并不希望输出到stdout的命令结果混入到有效的html字符串。因此,我们需要下面的命令:
4.2 os.popen(cmd)
执行cmd,并将结果以一个类(似)文件对象的形式返回(而不是直接输出到stdout中)。如:
import os
f = os.popen('uname -a')
result = f.readline()
f.close()
print result
4.3 os.fork()
创建一个子进程,常见的模式为:
ret = os.fork()
if ret == 0:
child_code
else:
parent_code
child_code中通常会用到os.exec*系列函数,来在子程序中装载入新的程序并设置其参数,根据不同的参数类型需要选择os.exec*系列的不同函数(详细列表见《Python核心编程 第二版》 P429)。
parent_code中则可能会用到os.wait*系列,用于等待子程序的返回或者特定的信号。
5. 终止执行
- sys.exit() 相当于 C++中的exit(), 可以有返回值,如sys.exit(1), 会引发SystemExit异常。
- os._exit(status): 不建议使用,只适用于特定的平台。
- os.kill(pid, sig): 给特定pid的进程发送信号
6. 各类操作系统接口
就记几个比较有用的吧。
- uname:获取系统信息
- getuid/setuid: 获取/设置uid
- getpid: 获取Pid
- getppid: 获取父进程pid
- getsid/setsid: 获取/设置会话ID
- getenv(ev): 获取环境变量ev的值
- setenv(ev, val): 设置环境变量ev的值为val
- strerror(code): 将错误码转化为错误描述