Python伪装文件类对象输入输出重定向方法研究
2020-06-29亓雪冬李霞
亓雪冬 李霞
摘 要:针对Python程序自动评测过程中被测试程序输入输出流重定向问题进行研究。分析了基于操作系统输入输出重定向方法的缺点与不足,基于Python的动态性提出了Python伪装文件类对象输入输出重定向方法。设计并实现了满足标准输入输出流接口特性的伪装文件对象,在Python程序内部接管输入流和输出流,提高了重定向接口的灵活性,减少磁盘空间占用,严格限制输出流数据尺寸,保障评测过程稳定进行。该方法在实际应用中效果良好。
关键词: Python; Online judge; 自动测评; 输入输出重定向
中图分类号: TP 393
文献标志码: A
Abstract: The paper studies problems about the IO stream redirection in the automatic evaluation of python language programs.Thepaper analyzes and points out shortcomings of the OS-based IO redirection method, and proposes an IO redirection method using python masquerading file class object. The paper designsand implement masquerading file class objectwhich meets the characteristics of standard IO stream interfaces. This object takes over IO streams inside a python program,increases flexibility of the redirection interface, reduces disk space usage, limits the output stream data size strictly, ensures the stability of the automatic evaluationprocess. This method works well in practical applications.
Key words: Python; Online judge; automatic evaluation; IO redirection
0 引言
程序设计类课程是当前大学教育课程体系重要组成部分,是重要的通识教育类课程,该类课程着重培养学生使用程序设计语言和算法解决实际问题的能力,使学生深刻理解计算机自动计算工作原理,建立计算思维为特征的普遍思维模式。近几年,Python语言以其语法简洁、易学易用、交互性、动态性和具有丰富的第三方程序库等特点逐渐被国内外高校所认可,开设了大量以Python语言的载体的程序设计类课程。嵩天等提出,Python语言是程序设计课程教学改革的理想选择[1]。
为了提高学习效率并提升教学效果,程序设计类课程均需快速对学生编写的程序进行自动评判[2-3]。程序自动测评实现了批改和反馈的自动化[4-6],是维护课堂秩序、保障教学效果和提升教学质量的重要技术手段。程序自动测评涉及到多种关键技术,如标准输入输出流重定向、文件输出重定向和管理,程序执行时间和内存开销管理、GUI评测方法等等。此外,不同编程语言的程序自动评判时具有其自身的特点,本文针对Python语言程序自动评测中,被测试程序输入输出流的重定向问题进行研究,在分析传统的基于操作系统输入输出重定向方法的基础上,提出了Python伪装文件类对象输入输出重定向方法,该方法在程序内部而不是进程外部对被输入输出数据别进行管理,具有更强的灵活性和自主性。
1 操作系统输入输出重定向方法
学生编写的Python程序通常包含输入和输出语句,程序在正常执行时,输入语句会阻塞程序等待用户在标准控制台中输入数据,输出语句需要向标准控制台输出数据,因此需要用户与程序之间的交互处理。
然而在程序自动评测时,这个过程需要自动完成,在实践中常常将标准输入流、标准输出流和标准错误流重定向到相关文件中。操作系统一般提供了基于文件的输入输出重定向功能,例如学生的Python程序为stud.py,执行程序的命令可写为:
Pythonstud.py< in.txt> out.txt2>&1
执行时,文件in.txt的内容将被重定向到标准输入流中,因此输入语句会从文件in.txt中直接读取数据而无需等待用户输入;程序运行时产生的标准输出流和标准错误流将重定向到文件out.txt中。
然而,由于被测试程序编写不当导致程序陷入死循环中,并在死循环中持续向标准输出流输出数据时,如不对输出数据尺寸进行限制,会在短时间内产生超大尺寸文件而占满磁盘空间导致系统崩溃。以笔者电脑为例,CPU为Intel Core i7-8565U 1.8 GHz,内存8 G,硬盘512 G。在每次循环中分别输出32字节、64字节、128字节和256字节的数据,程序运行5秒后被强制关闭。每种情况下均实验20次并统计平均值,程序产生输出数据文件尺寸,如图1所示。
随着单次输出字节數的增加,程序产生输出文件的尺寸也随之增大,两者之间基本呈线性关系。以单次输出128字节为例,程序运行5秒产生733 M字节数据,平均1秒产生146.6 M字节的数据。可见必须采取措施对传向标准输出流的数据字节数进行限制。
操作系统输入输出重定向方式的优点是:1)由操作系统直接支持,无需改动已编好的程序;2)使用文件作为重定向的源和目标,配置和查看数据非常方便。但这种方式也存在一些缺点,主要体现在:1)输入数据需要提前保存在相关文件中,程序运行时输出数据也将写入指定文件,不仅占用磁盘空间,频繁文件读写也易造成磁盘损坏;2)输入数据通过文件读取而非通过程序接口读取,缺乏可编程能力,灵活性较弱;3)输出数据流向文件写入时未加入任何限制措施,若测试程序陷入死循环,可能导致输出文件尺寸过大而占满磁盘空间,影响系统运行的稳定性。
2 Python伪装文件类对象输入输出重定向方法
笔者从Python的动态性和Python文件类对象接口角度出发,提出了基于伪装文件类对象的输入输出重定向方法,这种方法将Python程序内部的标准输入流对象(sys.stdin)、输出流对象(sys.stdout)和错误流对象(sys.stderr)等对象引用重置到自行实现的伪装的文件类对象,实现了更加普遍适用的重定向方式,解决了上面提出的各种问题。
实现原理为:由于Python的动态性,Python中任何在方法上与文件类似的对象都可以充当标准流,这与对象的实际数据类型无关,而取决于接口(也被称为协议)。具体来说,任何定义了类似于文件write方法的对象都可以赋值给sys.stdout,则所有标准输出数据将发送到该对象的write方法上;任何定义了类似于文件read方法的对象都可以赋值给sys.stdin,则所有标准输入数据将通过该对象的read方法获取。由于Python中的input和print两个输入输出函数只是简单的调用sys.stdin和sys.stdout所引用对象的write和readline方法,而程序运行错误也是通过sys.stderr所引用对象的write方法输出,因此我们可以使用该技术设计实现伪装文件类对象来拦截标准输入输出流和错误流。
伪装输入文件类对象的程序为:
class Input:
def __init__(self, data=[]):
self.data = data
self.index = 0
def readline(self):
if self.index text = str(self.data[self.index]) self.index+=1 else: text = '' return text 伪装输入文件类类名为Input,对象初始化方法__init__一方面设定数据列表,将其存储在self.data属性中,这个列表表示输入流中可被读取的数据行,列表的每一个元素代表一行数据;另一方面设定待读取数据的位置self.index为0,表示即将要读取列表中下标为0的元素数据。 被测试程序运行前,需要使用Input类的实例对象对sys.stdin变量赋值,修改标准输入流向。如sys.stdin = Input([10,20,'abc']),列表中的3个元素表示输入流中的3行数据。被测试程序执行input函数时,会调用上述实例对象的readline方法,读取列表中的下一个数据。如果列表的所有数据都已读完,则readline返回空字符串,表示没有读到数据。伪装输入文件类的设计使得输入数据不需要提前写入文件,而是采用Python标准数据结构的形式保存,操作和读取都具有很高的灵活性。比如Input([10,20,'abc']*3),对输入数据列表进行运算,快速产生9行输入数据。 伪装输出文件类对象的程序为: class Output: def __init__(self,MaxSize=4096): self.MaxSize = MaxSize self.text = '' def write(self,text): n = self.MaxSize-len(self.text) if n>0: self.text += text[0:n] 伪装输出文件类类名为Output,对象初始化方法__init__可设定输出文件的最大尺寸self.MaxSize,默认输出文件最大尺寸限制为4K字节。当程序向输出流中发送数据时,会调用该类实例对象的write方法,将输出数据写入对象的self.text属性。write方法累计统计输出数据字节数,若超过了最大尺寸self.MaxSize的预设值,超出部分的数据将被丢弃。 另外,被测试程序运行前,需要使用Output类的实例对象对sys.stdout变量赋值,修改标准输出和标准错误流向。如sys.stdout = Output() ; sys.stderr = sys.stdout。被测试程序执行时,print函数等向标准输出流以及程序出错时向标准错误流发送的数据会被发送到上述实例对象,保存到self.text属性中。被测试程序结束后,可以通過读取上述实例对象的self.text属性获取程序实际输出。伪装输出文件类的设计使得程序输出不是写入文件中,而存储在内存中,不占用磁盘空间,而且可以严格限制输出数据最大字节数,确保系统稳定运行。 3 总结 本文针对Python语言程序自动评测中,被测试程序输入输出流的重定向问题进行研究,阐述了传统的基于操作系统的输入输出重定向方法,分析和总结了这种方法的缺点与不足,并基于Python的动态性提出了Python伪装文件类对象输入输出重定向方法,通过设计实现满足标准输入输出流接口特性的文件对象,在Python程序内部接管输入流和输出流数据,有效改善输入输出重定向的灵活性。该方法在实际应用中效果良好,对其它程序语言自动测评中输入输出流重定向问题的研究也具有一定的启发性作用。 参考文献 [1] 嵩天,黄天羽,礼欣.Python语言:程序设计课程教学改革的理想选择[J].中国大学教学,2016(2):42-47. [2] Kurnia A,Lim A,Cheang B. Online judge[J]. Computers & Education,2001,36(4): 299-315. [3] 杜祥军,李建波,李敏,等.基于Online Judge的计算机类课程教学评价方法研究[J].计算机教育,2019(3):55-57. [4] 陈荣钦,胡永良,应建健,等.在线评测系统中的源码相似度检测研究与实现[J].实验技术与管理,2014,31(4):109-111. [5] 崔舒宁,吴宁,叶丹.建立抽象语法树模型评测C++代码[J].计算机应用,2015,35(S1):183-185. [6] 张晓莹,卢卫,程一舰,等.面向慕课的在线SQL自动评测系统及应用[J].实验技术与管理,2018,35(4):16-22. (收稿日期: 2019.08.26)