(四)脚本上下文

上下文,是指python脚本执行时所处的环境。

(本文大部分内容都是对文档《programming python》(第四版)第三章的选摘和翻译。如果有不正确的地方或者存疑之处,请参考原文。)

当前工作目录(CWD)

对于python脚本而言,当前工作目录是一个十分重要的概念:脚本在读写文件时,如果没有指明绝对路径,则默认文件所处的路径为当前工作目录。我们可以调用os.getcwd方法显式地获取CWD,也可以通过os.chdir修改它。

所以,文件名在没有指明绝对路径的情况下会映射到CWD下,和环境变量PYTHONPATH没有任何关系。脚本是在CWD下执行的,而不是脚本所处的文件目录。相反,import语句总是先搜索脚本所处的文件目录,不是CWD(除非脚本刚好处在CWD下)。为了清晰这个概念,下面进行一步说明。
cwd,文件和导入路径
在命令行解析器(如Windows中的MS-DOS)中执行python脚本时,CWD指命令行光标所处的当前路径。如图:
CWD的值为"C:\\Users\\huwz",不是"D:".
另外,python会自动将CWD和脚本所处的文件目录插入到sys.path的0和1号索引位置。CWD和脚本所处的目录一般是不同的,如果想要这两个值相同,可以双击脚本文件,直接执行脚本(最好在脚本结束的位置添加交互的语句用于暂停,否则运行结束后,DOS窗口会迅速消失)。
前面提到一个PYTHONPATH的概念,用于指明脚本所处的目录。可以在系统环境变量中添加PYTHONPATH,进行手动设置。一旦设置之后,处在PYTHONPATH路径下的python脚本可以在任意位置执行。
有一点需要注明:如果脚本处于用户自定义的包目录下(比如:D:/PP4E/python_scripts)不在PYTHONPATH中,那么其他脚本文件想要import该目录下的模块(.py文件),需要在import语句中添加完整包目录(import PP4E.python_scripts.*)。如果顶级包(PP4E)所处的目录不在sys.path中,必须添加到到PYTHONPATH中,否则就会抛出ImportError异常。

命令行参数

如何获取命令行中的参数,就好像函数调用传递参数一样呢?模块属性sys.argv可以完成这个工作。sys.argv是一个列表,用于收集命令行执行脚本时传递的参数。例如:

脚本test.py中sys.argv的值为:['test.py','hello,world']。由这个例子可知:sys.argv从目标模块名开始收集,以空白符为分隔符,顺序将所有的命令行参数收集起来,组织成列表。当然,你可以将参数分为位置参数和选项参数。所谓位置参数,就是按照命令行出现的顺序依次排列的参数,参数值和次序严格对应;选项参数是"-name value"对,比如:-h helpinfo。这里helpinfo和-h相关联。在处理选项参数时,可以先获取选项名,再根据选项名,来得到对应的选项参数的值。
当然还可以参考以下模块工具来解析命令行参数
  • getopt
  • optparse

标准流

分为标准输入流,标准输出流和标准错误信息流,和C++中的标准输入输出流相似。对应的python对象分别为sys.stdin,sys.stdout和sys.stderr。常规用法如下:
sys.stdout.write('hello\n')	# print('hello')
str = sys.stdin.readline()		# str = raw_input(),3.x支持sys.stdin.read()
sys.stderr.write('error\n')	# 在IDLE中高亮显示错误信息"error"
这三个对象实际上是python自动创建的文件对象,属于可递归的对象,支持 for...in...的语法
一般而言,标准输出流将文本打印在程序启动的控制台窗口中(比如IDLE,MS-DOS),标准输入流从键盘获取文本信息,标准错误信息流将python错误信息打印到控制台窗口中。
有必要解释下流的概念。流其实是指数据传输。计算机中,数据的传输在硬件层面上是以字节进行的,如果不关心数据的具体内容,数据的传输就是字节的传输,就像流动的水一样,所以称为流。流的行为需要媒介支持,纯粹的硬件媒介就是数据线。当然这里讨论“硬媒介”是没有意义的,我们关注的是与硬件媒介相对应的“软媒介”。在Windows中存在这样的“软媒介”,也是我们所熟知的系统缓冲区。
依据个人的理解,Windows操作系统在与外部设备交换数据时,由于数据处理速度以及串并行的差别,需要进行数据缓冲,这样可以保证数据不会丢失。默认情况下,缓冲区的入口和出口连接的分别是系统和外设(如键盘和显示器)。比如python中的标准输入流和input(),缓冲区入口为键盘设备,出口为系统调用;标准输出流和print(),缓冲区的入口为系统调用,出口是打印终端(就是前文提到的控制台窗口)。系统缓冲区属于公共资源,因而可以用于不同进程间的信息交换。
python的默认缓冲区就是系统缓冲区,只是它既可以从系统写入数据(输出流),也可以读出数据到系统(输入流),所以扮演不同的角色,也就有输入缓冲区和输出缓冲区的分别。
能不能改变这种模式呢?Windows操作系统存在流重定向指令("<"," >")和管道指令,其实质就是将缓冲区的入口或者出口进行重定向。
(以上关于流的解释纯属个人见解,有兴趣的同学可以去参考相关资料)
通过重定向指令"<",">"来实现流的重定向
将数据文件data.txt中的数据作为tes.py脚本的输入。
tes.py:
import sys

dataList = []
while True:
    try:
        data = raw_input()
    except EOFError:
        dataList.sort()
        print dataList
        break
    else:
        dataList.append(int(data))
执行结果如下:


通过管道指令实现重定向
数据来源变为dataFrom.py脚本,通过"|"指令,将该脚本的打印内容赋值给tes.py
dataFrom.py:
print "1\n2\n8\n9\n0\n11"
执行结果:

管道指令是可以串联的,而且不限定于py脚本,只要可以在shell窗口中执行的程序都可以。所谓的串联,举个例子说明就清楚了。如果有A.py,B.py和C.py脚本,可以有如下的命令行:python A.py | B.py | C.py,表示A.py的打印结果给B.py,然后再将打印结果给C.py。
python的脚本通过管道可以实现通信。比如上例中A.py的数据存入sys.stdout,B.py可以通过sys.stdin.readline()(读取的内容包括'\n')读取A.py打印的文本。也就是说只要A.py中有打印结果,B.py就可以获取。
重定向指令的弊端和解决办法
前面介绍了重定向的方法:将文件作为缓冲区的入口或者出口,进行流的重定向。这个方法的弊端也很明显,如果将一个很大的文件读入内存,因为是一次性读入,等待时间会很长。改进的办法是分块读入,分块处理。管道指令可以解决这个问题。将数据放入.py脚本中,通过for循环进行数据分解,得到的数据块存入sys.stdout,这样只要缓冲区中有数据,管道另一端的脚本就可以通过syss.stdin.readline()获取。
例如A.py循环打印字符串数组;B.py接受一个输入的字符串然后打印。可以在A.py和B.py之间建立管道。代码如下:
A.py:
import sys

strings = ['name: python\n', 'country: china\n', 'version: 2.7.2\n']

for i in strings:
    sys.stdout.write(i)
B.py:
import sys

while True:
    strs = sys.stdin.readline()
    if not strs:
        break;
    sys.stdout.write("B=> " + strs)
执行结果:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值