python调用其他程序并控制输入输出_python调用外部子进程,通过管道实现异步标准输入和输出的交互...

我们通常会遇到这样的需求:通过C++或其他较底层的语言实现了一个复杂的功能模块,需要搭建一个基于Web的Demo,方法查询数据。由于Python语言的强大和简洁,其用来搭建Demo非常合适,Flask框架和jinja2模块功能为python提供了方便的web开发能力。同时,python能够很方便的同其他语言的代码交互。因此我们选择python作为开发Demo的工具。假设我们需要调用的模块(提供底层服务)通过标准输入循环读入数据,处理完毕后把结果写出到标出输出,这样的场景在Linux环境下很常见,依赖于Linux强大的重定向能力。然而,非常不幸的是,底层模块有一个很重的初始化过程,因此我们不能够每次查询请求都去重新生成调用底层模块的子进程。解决方案就是只生成一次子进程,然后对每个请求通过管道(pipe)来和子进程交互。

Python的subprocess模块可以很容易地生成子进程,类似Linux系统调用fork和exec。subprocess模块的Popen对象可能以非阻塞的方式调用外部可执行程序,因此我们使用Poen对象来实现需求。如果我们想要把数据写入子进程的标准输入stdin,那么在创建Popen对象的时候就需要指定参数stdin为subprocess.PIPE;同样,如果我们需要从子进程的标准输出中读取数据,那么在创建Popen对象的时候就需要指定参数stdout为subprocess.PIPE。先看一个简单的例子:

from subprocess importPopen, PIPE

p= Popen('less', stdin=PIPE, stdout=PIPE)p.communicate('Line number %d.\n' % x)

communicate函数返回一个二元组(stdoutdata, stderrdata),包含了子进程的标准输出和标出错误的输出数据。然而,由于Popen对象的communicate函数会阻塞父进程,同时还会关闭管道,因此每个Popen对象只能调用一次communicate函数,如果有多个请求必须重新生成Popen对象(重新初始化子进程),不能满足我们的需求。

因此,我们只有往Popen对象的stdin和stdout对象里写入和读取数据才能实现我们的需求。然而,不幸的是subprocess模块默认情况下只运行在子进程结束的时候读取一次标准输出。Both subprocess and os.popen* only allow input and output one time, and the output to be read only when the process terminates.

进过一番研究之后我发现通过fcntl模块的fcntl函数可以把子进程的标准输出改为非阻塞的方式,从而达到我们的目的。这样困扰我许久的问题终于得到了完美解决。代码如下:

1 #!/usr/bin/python

2 #-*- coding: utf-8 -*-

3 #author:

4 from subprocess importPopen, PIPE5 importselect6 importfcntl, os7 importtime8

9 classServer(object):10 def __init__(self, args, server_env =None):11 ifserver_env:12 self.process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=server_env)13 else:14 self.process = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)15 flags =fcntl.fcntl(self.process.stdout, fcntl.F_GETFL)16 fcntl.fcntl(self.process.stdout, fcntl.F_SETFL, flags |os.O_NONBLOCK)17

18 def send(self, data, tail = '\n'):19 self.process.stdin.write(data +tail)20 self.process.stdin.flush()21

22 def recv(self, t=.1, stderr=0):23 r = ''

24 pr =self.process.stdout25 ifstderr:26 pr =self.process.stdout27 whileTrue:28 if notselect.select([pr], [], [], 0)[0]:29 time.sleep(t)30 continue

31 r =pr.read()32 returnr.rstrip()33 returnr.rstrip()34

35 if __name__ == "__main__":36 ServerArgs = ['/path/to/server', '/path/to/args']37 server =Server(ServerArgs)38 test_data = '拿铁', '咖啡'

39 for x intest_data:40 server.send(x)41 print x, server.recv()

另外,调用一些外部程序时,可能需要指定相应的环境变量,方式如下:

my_env =os.environ

my_env["LD_LIBRARY_PATH"] = "/path/to/lib"server= server.Server(cmd, my_env)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源介绍】 基于PySide6框架+python的智能充电桩调度计费系统前端源码+项目说明文档.zip 基于 PySide6 框架与 Python3.10 开发。 开发环境配置 下载安装 Python3.10(Windows 建议使用微软商店) 克隆项目仓库 在项目根目录执行 python3.10 -m pip install -r requirements.txt 使用 python3.10 admin/main.py 与 python3.10 user/main.py 分别启动用户客户端与管理员客户端程序 调试方法 调试 AcssFrontend 的方法与调试 AcssBackend 的方法一致 使用 Visual Studio Code 打开本项目,并点击右下角 Python 版本切换至 Python3.10 在调试选项中选择 Python 文件 并创建 launch.json 在希望调试的位置添加断点 使用功能键 F5 启动调试 代码要求 不可以在代码中使用同步阻塞操作,例如 sleep(1); 所有阻塞操作均需要使用使用支持 asyncio 的函数,并在函数前添加 await 关键字; 使用 await 关键字的函数 def 前需要添加 async 关键字。 基本代码逻辑说明 程序入口模块 main.py 这里执行一些基本初始化操作,并且定义按钮点击事件的响应函数,并将它们绑定到 Qt 控件上。 Qt 以阻塞的方式调用 Python 函数,所以直接在函数中执行网络IO是不可行的(等待响应的过程用户界面会失去响应),所以这里使用 qasync 模块兼容了 Python异步框架 asyncio。通过这种方法,所有阻塞操作全部可以使用异步方式调用,这样就不会阻塞用户界面了。异步调用示例如下: import api import qasync @qasync.asyncSlot() async def on_login_clicked(): try: kwargs = await api.login('jinuo', 'i-hate-bupt') except ApiError as e: some_toast(str(e)).show() token = kwargs['token'] is_admin = kwargs['is_admin'] # rest codes 响应函数调用 API 模块提供的函数以与服务端进行交互。捕获 ApiError 并显示提示框,若未发生异常则从返回值中获取服务器返回的数据,并对用户界面进行相应的更新。 主窗口模块 mainwindow.py 该模块负责加载窗口,并保存控件的 Python 对象。显然这样的写法不是最佳实践,我没有花时间找到加载UI文件并继承 QWidget 类的方法(又不是不能用)。 API 模块 api.py 所有对网络的调用全部在 API 模块内完成。 API 模块内的 api_post 与 api_get 两个函数封装了 requests 库的 get 与 post 操作。这两个函数需要能够自动在其中添加 Authorization 请求头。 api_post 与 api_get 中使用 requests 模块时,需要捕获网络 IO 异常(如超时),并且使用 raise ApiError("网络异常") from e 将相关异常以 ApiError 异常的类型抛出。 api_post 与 api_get 在获取到响应时,需要判断 code 是否为 0,为 -1 时需要抛出 ApiError(response['message']) 异常。 API 模块除 api_post 与 api_get 的函数与 开放 API 文档 内的接口一一对应,需要调用 api_post 与 api_get 对服务端发起请求。 这些函数不需要捕获 ApiError 异常,对异常的捕获应该发生在 API 模块的调用者处,以决定是否要反馈到用户界面中(Toast)。 调用者捕获到 ApiError 异常时,仅需要使用 str(e) 即可获取到异常的文本信息, 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载交流,互相学习,共同进步!
【资源说明】 基于Flask的Python全国招聘岗位就业可视化系统源码+项目部署说明+详细注释.zip 1、该资源内项目代码都是经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能。 1 开发环境** * 1 系统:Window 10 家庭中文版。 * 2 语言:Python(3.8.5)、MySQL(5.5)。 * 3 Python所需的库:flask、pymysql、pandas、numpy、time、datetime、requests、etree、jieba、re、json、decimal(没有的话pip或conda安装一下~)。 * 4 编辑器:jupyter Lab(jupyter notebook)、Pycharm(主用)、Navicat。 2 运行说明** 本项目下面有五个.py的文件,下面分别阐述各个文件所对应的功能:<br> * 1 data_collection:分别从前程无忧网站和猎聘网上以关键词`job_name`爬取相关数据。其中,前程无忧爬取的数据主要用来进行相关图表的绘制;而猎聘网上主要为岗位要求文本数据,这部分进行词云的可视化展示。 * 2 data_clean:对爬取到的数据进行清洗,包括去重去缺失值、变量重编码、特征字段创造、文本分词等。 * 3 data_store:将清洗后的数据全部储存到`MySQL`中,其中对文本数据使用`jieba.analyse`下的`extract_tags`来获取文本中的关键词和权重大小,方便绘制词云。 * 4 utils:大多为app调用MySQL数据库中的工具类函数;同时,里面也有引用data_collection、data_clean、data_store等函数,我们也主要使用该工具类进行岗位数据的爬取、清洗和存储。 * 5 app:使用`Python`一个小型轻量的`Flask`框架来进行`Web`可视化系统的搭建,在static中有css和js文件,js中大多为百度开源的[ECharts](https://echarts.apache.org/examples/zh/index.html),再通过自定义`controller.js`来使用ajax调用flask已设定好的路由,将数据异步刷新到templates下的`main.html`中。 * 6 如何运行:先运行utils,提前进行数据采集、数据清洗、数据存储操作,之后更改app修改好`datatable`和`job_name`,这部分信息务必与utils中输入的保持一致(因为发现app一运行的话就会直接给出网页,所以没法在控制台上同步将变量赋值过去*_*)。 * 7 温馨提示:由于我在数据采集部分使用了一个用redis搭建的代理IP池,所以一开始运行的话需要将里面的proxies删掉,使用time.sleep即可(使用代理池能防止被封IP,同时可以更快爬取数据,实现可视化操作)。 3 你将会学到** * 1 Python爬虫:盗亦有道,掌握requests和xpath的相关用法。 * 2 数据清洗:能详细知道项目中数据预处理的步骤,包括去重去缺失值、变量重编码、特征字段创造和文本数据预处理,玩转pandas、numpy相关用法。 * 3 数据库知识:select、insert等操作,掌握pymysql相关用法。 * 4 前后端知识:了解到HTML、JQuery、JavaScript、Ajax的相关用法。 * 5 Flask知识:能快速建立起一个轻量级的Web框架,利用Python实现前后端交互
### 回答1: Python调用API可以使用Python中的requests库。这个库提供了一些简单易用的方法,可以发送HTTP请求到API服务端,并获取响应数据。使用requests库,你可以方便地发送HTTP GET、POST、PUT、DELETE等请求,并可以设置请求头、请求参数、请求体等信息。 例如,如果你想调用一个返回JSON格式数据的API服务,可以使用如下代码: ```python import requests url = "https://api.example.com/users" params = {'username': 'user1', 'password': 'pass1'} headers = {'Authorization': 'Bearer xxxxxxxxx'} response = requests.get(url, params=params, headers=headers) if response.status_code == 200: data = response.json() print(data) else: print("Request failed with status code:", response.status_code) ``` 在这个例子中,我们使用requests库发送了一个HTTP GET请求到https://api.example.com/users这个URL,并设置了请求参数和请求头。如果API服务端返回了HTTP状态码200,则说明请求成功,我们可以通过response.json()方法将返回的JSON格式数据解析为Python对象。如果请求失败,则打印出HTTP状态码。 ### 回答2: Python可以通过调用API与其他应用程序进行交互。API(Application Programming Interface)是一组预定义的函数和方法,用于与外部软件或服务进行通信。 要使用Python调用API,首先需要安装相关的库,例如requests,它是一个常用的HTTP库,可以发送HTTP请求和接收响应。 首先,使用pip安装requests库:pip install requests 接下来,导入requests库: import requests 然后,使用requests库发送HTTP请求并接收响应。例如,可以使用GET方法获取某个API的数据: response = requests.get(url) 其中,url是API的地址。 发送请求后,可以通过response对象获取API的响应。例如,可以获取响应的状态码: status_code = response.status_code 可以获取API返回的数据,例如,获取返回的JSON数据: data = response.json() 通过API返回的数据,可以进一步处理和分析。例如,可以将数据保存到本地文件、数据库或进行进一步的计算和展示。 需要注意的是,每个API可能有不同的要求和授权方式。有些API可能需要提供API密钥或其他认证信息,以确保请求的安全性和合法性。 另外,对于涉及大量数据或频繁调用的API,可以考虑使用异步请求和批量处理来提高效率和性能。 总结起来,Python通过调用API可以方便地获取其他应用程序或服务的数据,并进行进一步的处理和分析。通过使用适当的库和认证信息,可以实现与各种API的交互。 ### 回答3: Python调用API是指使用Python编程语言去访问和调用外部的应用程序接口(API)。API是一种提供给开发者使用的接口,它定义了不同应用程序之间的交互规则和数据传输方式,开发者可以通过API来获取或发送数据,调用外部功能,实现不同应用之间的协作。 在Python中,可以使用第三方库来调用API,例如requests库、urllib库等。首先,需要通过API提供的文档了解API的使用方式和参数。然后,可以使用Python发送HTTP请求,获取API返回的数据。 以使用requests库为例,可以通过以下步骤来调用API: 1. 导入requests库:`import requests` 2. 发送HTTP请求:使用requests库的get()、post()等方法发送HTTP请求,并指定API的URL和请求参数。例如:`response = requests.get('http://api.example.com/data', params={'key': 'value'})` 3. 处理返回的数据:根据API返回的数据类型(如JSON、XML等),可以使用requests库的json()、text()等方法来解析返回的数据。例如:`data = response.json()` 4. 使用返回的数据:根据API的文档,可以使用返回的数据来进行相应的操作或展示。例如:`print(data['name'])` 需要注意的是,在调用API时可能需要提供一些身份验证或密钥信息,可以在请求头或请求参数中添加相应的信息来实现身份验证。 总之,Python调用API是一种灵活便捷的方式,可以帮助开发者快速获取外部数据或实现不同应用之间的交互。通过学习API的使用方式和相应的Python库,开发者可以更加方便地调用API实现各种功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值