如何分享(传递)一个Python函数?需要以什么形式进行分享(传递)?

19
我的工作最终产出应该是一个Python函数,它以JSON对象作为唯一的输入,并返回另一个JSON对象作为输出。更具体地说,我是一名数据科学家,我所说的函数是从数据中派生出来的,它提供预测结果(换句话说,它是一个机器学习模型)。
那么,我的问题是如何将这个函数交给“技术团队”,让他们将其整合到Web服务中。
目前我面临几个问题。首先,技术团队不一定在Python环境下工作。因此,他们不能只是“复制并粘贴”我的函数到他们的代码中。其次,我想确保我的函数在与我的环境相同的环境中运行。例如,我可以想象我使用了一些技术团队没有的库,或者他们使用的版本与我使用的版本不同。 补充说明: 作为可能的解决方案,我考虑以下方法。我启动一个Python进程来监听一个套接字,接受传入的字符串,将它们转换成JSON,将JSON传递给“发布”的函数,并将输出JSON作为字符串返回。这种解决方案有什么缺点吗?换句话说,“发布”一个Python函数作为后台进程来监听套接字是一个好主意吗?

请尝试查看 pex 工具 https://github.com/pantsbuild/pex - Compadre
1
你可以尝试搭建一个Django服务器并使用Django REST框架,网址为http://www.django-rest-framework.org/。你可以控制环境,那些知道如何编码的人可以编辑函数。不知道如何编码的人可以通过curl或类似工具调用URL并传递JSON数据。这可以轻松地集成到更高级别的Web服务中。 - Josh
关于问题2,您可能需要编写一些单元测试。如果Web团队的单元测试通过了,那么就可以放心使用了。 - user1157751
你能解释一下他们的Web服务吗?你的功能是否必须与他们的无缝配合?我的意思是,它是否必须自动化并迁移到他们的服务中?如果不需要,你可以只使用Flask Web应用程序和基本的HTML输入(文本字段、文本区域、文件上传等等),它将接受你的输入并将输出返回给用户。他们可以通过链接访问该应用程序。如果这个想法不适用,你完全可以忽略它。由于我不太了解你的技术团队如何工作,所以我不知道这是否有帮助。 - Harrison
然而,如果您采用这种方法,它仍然可以自动化,因为他们可以使用超级简单的网络爬虫来访问您的工具,输入数据并抓取输出。根据他们的知识水平(他们有编程技能吗?),这将是一项简单的任务,只需要几行代码。如果您认为其中任何部分可能有效,我可以指导您编写flask应用程序。这将相对较短。只需将html输入路由到一个函数,该函数获取输入并将其传递给您的函数即可。 - Harrison
5个回答

9
你使用套接字的想法是正确的,但有很多框架可以完全满足你的需求。像hleggs一样,我建议你查看Flask来构建微服务。这将允许其他团队通过HTTP请求向你的flask应用程序发布JSON对象并接收JSON对象。无需了解底层系统或其他要求! 这是一个回复和响应JSON的flask应用程序模板。
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/', methods=['POST'])
def index():
    json = request.json
    return jsonify(your_function(json))


if __name__=='__main__':
    app.run(host='0.0.0.0', port=5000)

编辑: 根据Peter Britain的建议,直接嵌入我的代码


1
另外还有两点想法... 1) 如果您直接嵌入代码而不是链接到外部 gist,那么您的答案会更好(并且通常在 SO 上鼓励这样做)。2) 针对 OP 的问题,版本控制方面怎么处理? - Peter Brittain
@app 符号的含义是什么?这是我第一次在 Python 中看到这样的东西。另外,请建议使用 HTTPS 而不是 HTTP。 - code_dredd
我不确定这完全回答了主要问题:如何分发Python函数? - Philippe Ombredanne
@PeterBrittain 在我的回答https://dev59.com/aFkT5IYBdhLWcg3wX-Zo#38891638中,我试图更具体地回答OP的问题。你觉得呢? - Philippe Ombredanne
@ray - @ 在 Python 中表示一个装饰器。你可以在文档中了解更多关于它的信息。这个回答在解释 Flask 中使用时做得非常好。 - Justin Bell
@JustinBell,我之前没有遇到过像那样的装饰器符号,所以一开始认为它与装饰器无关。谢谢。 - code_dredd

3

根据我的理解,您的问题是:

我如何与团队共享一个Python库,而他们可能没有使用Python?

我如何确保接收方团队运行的是我的代码及其依赖项?

并且接收方团队可以在大多数地方轻松安装这些依赖项吗?

这个问题没有简单的答案...因为您提到可能将其集成到某个Web服务中,但您不知道该服务的实际平台。

您还问道:

作为一种可能的解决方案,我考虑以下内容。我启动一个Python进程来监听套接字,接受传入的字符串,将它们转换为JSON,将JSON给予“发布”函数,并将输出JSON作为字符串返回。这个解决方案有什么缺点吗?换句话说,“发布”Python函数作为后台进程监听套接字是一个好主意吗?

最简单的情况下,我会总体上说不建议。启动网络服务器(例如内置于Python中的HTTP服务器)非常容易。但是,即使被称为“微型”,服务也意味着基础架构、安全等等。

  • 如果部署机器上没有您期望的端口会怎样?-当您重新启动该机器时会发生什么?
  • 在失败时,服务器将如何启动或重新启动?
  • 是否也需要提供Linux上的upstart或systemd服务?
  • 您简单的套接字或Web服务器是否支持多个并发请求?
  • 暴露套接字是否存在安全风险?

等等。在部署后,我对“简单”的套接字服务器的经验是,它们最终并不那么简单。

在大多数情况下,最好避免一开始就重新分发套接字服务。如果需要,这里提出的方法可以在以后更简单地打包整个服务。

相反,我建议使用简单的命令行界面进行美好的打包安装

需要考虑的最小要素为:

  1. 提供可在许多操作系统上调用函数的便携式机制
  2. 确保您打包函数时可以安装所有正确的依赖项
  3. 使其易于安装并提供一些文档!

步骤1。最简单的共同点是提供一个命令行界面,接受JSON文件的路径,并在标准输出上返回JSON。 这将在Linux、Mac和Windows上运行。

这里的说明应该适用于Linux或Mac,并需要稍微调整Windows(仅针对下面的configure.sh脚本)

一个最简单的Python脚本可能是:

#!/usr/bin/env python

"""
Simple wrapper for calling a function accepting JSON and returning JSON.
Save to predictor.py and use this way::
    python predictor.py sample.json
    [
      "a",
      "b",
      4
    ]
"""

from __future__ import absolute_import, print_function
import json
import sys


def predict(json_input):
    """
    Return predictions as a JSON string based on the provided `json_input` JSON
    string data.
    """
    # this will error out immediately if the JSON is not valid
    validated = json.loads(json_input)
    # <....> your code there
    with_predictions = validated
    # return a pretty-printed JSON string
    return json.dumps(with_predictions, indent=2)


def main():
    """
    Print the JSON string results of a prediction, loading an input JSON file from a
    file path provided as a command line argument.
    """
    args = sys.argv[1:]
    json_input = args[0]
    with open(json_input) as inp:
        print(predict(inp.read()))


if __name__ == '__main__':
    main()

您可以通过传递JSON文件的路径来处理大量输入。
第二步。将您的函数打包。在Python中,这可以通过创建setup.py脚本实现。它会安装Pypi中的任何相关代码。这将确保您所依赖的库的版本是您期望的版本。在此示例中,我添加了nltk作为依赖项。添加您自己的依赖项:例如scikit-learn、pandas、numpy等。这个setup.py还会自动创建一个bin/predict脚本,这将是您的主要命令行接口。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

from __future__ import absolute_import, print_function
from setuptools import setup
from setuptools import find_packages


setup(
    name='predictor',
    version='1.0.0',
    license='public domain',
    description='Predict your life with JSON.',
    packages=find_packages(),
    # add all your direct requirements here
    install_requires=['nltk >= 3.2, < 4.0'],
    # add all your command line entry points here
    entry_points={'console_scripts': ['predict = prediction.predictor:main']}
)

此外,为了使安装代码更简单,与 Python 常见的做法一样,我创建了一个“Python 包”目录并将预测器放在此目录中。 第三步。 现在您需要将它们打包,以便轻松安装。一个简单的 configure.sh 脚本可以完成这项工作。它安装了 virtualenvpipsetuptools,然后在项目所在目录下创建了一个 virtualenv 并在其中安装您的预测工具(pip install .python setup.py install 的作用是相同的)。通过此脚本,您确保运行的代码是您希望运行的代码,并拥有正确的依赖关系。此外,您还确保这是一个隔离的安装,对目标系统的依赖和影响最小。这在 Python 2 上经过了测试,但在 Python 3 上也很可能有效。
#!/bin/bash
#
# configure and installs predictor
#

ARCHIVE=15.0.3.tar.gz
mkdir -p tmp/
wget -O tmp/venv.tgz https://github.com/pypa/virtualenv/archive/$ARCHIVE
tar --strip-components=1 -xf tmp/venv.tgz -C tmp
/usr/bin/python tmp/virtualenv.py .
. bin/activate
pip install .
echo ""
echo "Predictor is now configured: run it with:"
echo "   bin/predict <path to JSON file>"

最终,您将获得一个完全配置好、隔离的、易于安装的代码片段,并配有简单、高度可移植的命令行界面。您可以在这个小仓库中查看所有内容:https://github.com/pombredanne/predictor。您只需克隆或获取该repo的zip或tarball,然后查看README文件,即可开始使用。
请注意,如果需要更复杂的应用程序,包括依赖关系的销售和易于安装而不依赖于网络的更积极方式,您可以查看我维护的这个https://github.com/nexB/scancode-toolkit工具包。
如果您真的想要公开Web服务,您可以重新利用这种方法,并使用简单的Web服务器(例如Python标准库或瓶子或Flask或gunicorn中内置的服务器)打包它,并提供configure.sh以安装所有内容并生成启动命令行。

0

你的任务(一般而言)是将一个机器学习模型投入生产,其中模型的使用者可能与开发模型所用的环境不同。我过去几年一直在尝试解决这个问题。许多公司都面临着这个问题,由于数据科学家和开发人员之间的技能、目标以及环境(语言、运行时)不匹配,这个问题变得更加严重。根据我的经验,以下解决方案/选项可供选择,每种方案都有其独特的优点和缺点。

  • 选项1:使用Python中的任何轻量级工具(例如Flask),将模型的预测部分构建为独立的Web服务。您应该尽可能地将模型开发/训练和预测部分解耦。您开发的模型必须被序列化为某种形式,以便Web服务器可以使用它。

    • 您的机器学习模型更新频率如何?如果不是非常频繁,则可以将序列化的模型文件(例如Python pickle文件)保存到Web服务器可以访问的公共位置(例如s3),并在内存中加载。独立的Web服务器应提供用于预测的API。
    • 请注意,使用Flask公开单个模型预测很简单。但是,如果需要扩展此Web服务器,配置正确的库、验证传入请求等都是非平凡的任务。只有在您有开发团队准备好帮助处理这些问题时,才应选择此路线。

    • 如果模型经常更新,则对模型文件进行版本控制是一个不错的选择。因此,实际上,您可以通过检入整个模型文件来搭载任何版本控制系统,如果文件不太大。Web服务器可以在启动/更新时反序列化(pickle.load)此文件,并将其转换为Python对象,您可以在其上调用预测方法。

  • 选项2:使用预测建模标记语言。PMML专门为此目的开发:预测建模数据交换格式独立于环境。因此,数据科学家可以开发模型,将其导出到PMML文件中。用于预测的Web服务器可以消耗PMML文件以进行预测。您应该绝对检查开放评分项目,它允许您通过REST API公开机器学习模型以部署模型并进行预测。

    • 优点:PMML是标准化格式,开放评分是具有良好开发历史的成熟项目。
    • 缺点:PMML可能不支持所有模型。开放评分主要在技术团队选择的开发平台为JVM时有用。从Python导出机器学习模型并不简单。但是,R对将模型导出为PMML文件具有良好的支持。
  • 选项3:有一些供应商提供了专门的解决方案。您将需要评估许可证成本、硬件成本以及这些解决方案的稳定性。
无论您选择哪种选项,请考虑支持该选项的长期成本。如果您的工作处于概念验证阶段,那么基于Python flask的Web服务器+腌制模型文件将是最佳选择。希望这个答案对您有所帮助!

0

正如其他答案中已经建议的那样,最好的选择是创建一个简单的Web服务。除了Flask之外,您可能还想尝试bottle,这是一个非常轻量级的单文件Web框架。您的服务可能看起来很简单:

from bottle import route, run, request

@route('/')
def index():
    return my_function(request.json)

run(host='0.0.0.0', port=8080)

为了保持环境一致,请查看 virtualenv,创建隔离环境以避免与已安装的软件包冲突,并使用 pip 安装确切版本的软件包到虚拟环境中。

-1

我猜你有三种可能性:

  • 将Python函数转换为JavaScript函数:

假设“tech-team”使用JavaScript进行Web服务,您可以尝试使用empythoned(基于emscripten)直接将Python函数转换为JavaScript函数(这将非常容易集成到Web页面中)

这种方法的缺点是每次需要更新/升级Python函数时,您都需要再次将其转换为JavaScript,然后检查和验证该函数是否继续工作。

  • 简单的API服务器+JQuery

如果转换方法不可行,我同意@justin-bell的观点,您可以使用FLASK

获取JSON作为输入>将JSON转换为函数参数>运行Python函数>将函数结果转换为JSON>提供JSON结果

假设您选择FLASK解决方案,“tech-team”只需要发送一个异步的GET/POST请求,其中包含所有参数作为JSON对象,当他们需要从您的Python函数获取一些结果时。
  • websocket服务器+socket.io
您还可以查看Websocket来分派到Web服务(查看flask + websocket以及socket.io用于Web服务端)。
=> 当您需要与许多用户进行低成本和低延迟的数据推送/接收时,Websocket确实非常有用(不确定Websocket是否最适合您的需求)。
此致

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接