python3调用python2文件的简单用法

Python 3和Python 2的主要差异

Python 3打破了对Python 2的向后兼容。但它并不是完全重新设计的。而且,也并不是说2.x版本的Python模块在Python 3下都无法运行。代码可以完全跨版本兼容,无需其他工具或技术在两大版本上都可以运行,但一般只有简单应用才能做到这一点。
Python 3引入的重要差异一般可分为以下几个方面:
• 语法变化,删除/修改了一些语法元素,并添加了一些新的语法元素。
• 标准库中的变化。
• 数据类型与集合的变化。

所以,有时由于一些客观原因,不得不在python3环境中引入Python 2文件,并且这两者没法完全兼容,就需要进行另外的一些设计,下文中是具体实现的一种简单的方法。

确定需求

在我的项目中,通过pyhton3环境设计了一个属性检查的文件;但我的图形(拓扑)检查是基于ArcGIS的站点包ArcPy设计的,这两者显然没法都在pyhton3环境下运行。(ArcPy只支持python2.7)

我需要在python3环境中调用我的python2.7设计的检查文件。

具体实现

使用python标准库的subprocess(子进程管理)模块;subprocess 模块允许你生成新的进程,连接它们的输入、输出、错误管道,并且获取它们的返回码。这是python官方文档的链接

ps:当然也可以使用 multiprocessing(基于进程的并行)模块来实现同样的功能。

script = [self.obj.exename, ".\\recourse\\CheckTopology.py", self.obj.filename]
proc = subprocess.Popen(script, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
proc.communicate()

以上内容,使用Popen 构造函数开启了一个子进程命名为proc,Popen 类的实例拥有以下方法:
Popen.poll()
检查子进程是否已被终止。设置并返回 returncode 属性。否则返回 None。
Popen.wait(timeout=None)
等待子进程被终止。设置并返回 returncode 属性。如果进程在 timeout 秒后未中断,抛出一个 TimeoutExpired 异常,可以安全地捕获此异常并重新等待。
注意:当 stdout=PIPE 或者 stderr=PIPE 并且子进程产生了足以阻塞 OS 管道缓冲区接收更多数据的输出到管道时,将会发生死锁。当使用管道时用 Popen.communicate() 来规避它。
Popen.communicate(input=None, timeout=None)
与进程交互:将数据发送到 stdin。 从 stdout 和 stderr 读取数据,直到抵达文件结尾。 等待进程终止并设置 returncode 属性。
Popen.terminate()
停止子进程。
Popen.kill()
杀死子进程。

这里选择Popen.communicate,原因是要获取子进程的输出信息,以监测子进程的运行情况;上文中的script是开启子进程的信息列表,用法例如[python2.exe, my.py, argv]从左向右依次是开启子进程的执行程序、py文件、py文件的参数;stdout=subprocess.PIPE是开启管道获取标准输出,stderr=subprocess.STDOUT是开启管道获取错误输出。

communicate() 返回一个 (stdout_data, stderr_data) 元组。如果文件以文本模式打开则为字符串;否则字节。

outs, errs = proc.communicate()
outs, errs 就是子进程的输出信息。

项目实例

以下内容是我的项目最终文件的一部分内容,因为需要在GUI界面上展示子进程的输出信息,所以还开启了另外的线程循环以信号的形式发送该进程的输出信息。

 def Threading_topo(self):  # CheckTopology子进程输出读取方法
        script = [self.obj.exename, ".\\recourse\\CheckTopology.py", self.obj.filename]

        def output_reader(proc, outq):
            for line in iter(proc.stdout.readline, b''):
                outq.put(line.decode('gbk'))

        def main(script1):
            # Note the -u here: essential for not buffering the stdout of the subprocess
            proc = subprocess.Popen(script1, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
            outq = queue.Queue()
            t = threading.Thread(target=output_reader, args=(proc, outq))
            t.start()

            try:
                for i in range(500):
                    if proc.poll() == 0:
                        self.sinOut.emit('......拓扑检查完成。\n')
                        proc.terminate()
                        break
                    print(i)
                    try:
                        line = outq.get(block=False)
                        # 这里是我最终的输出信息
                        self.sinOut.emit(line)
                    except queue.Empty:
                        pass

                    time.sleep(1)
            finally:
                proc.terminate()
                try:
                    proc.wait(timeout=1)
                    print('== subprocess exited with rc =', proc.returncode)
                except subprocess.TimeoutExpired:
                    print('subprocess did not terminate in time')
            t.join()

        main(script)

总结及反思

if __name__ == "__main__":
    in_path = sys.argv[1]
    my_Topology = CheckTopology(in_path)
    my_Topology.CreateNewGdb()
    my_Topology.CreateFeatureDataset()
    my_Topology.CreateTopology()
    my_Topology.AddRules_ValidateTopology()

这是我的python2文件的结尾,确保该python2文件独立运行正常的情况下,将需要的参数以上文的形式传入该文件内;这里我的参数是in_path,在开启子进程的script列表中根据上下文获取的外部参数通过sys.argv[1]传入该文件。

你可能感兴趣的:(python,python)