全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网

Python

更新时间:2017-11-17 13:47:09

函数计算目前支持以下Python运行环境:

  • Python 2.7 (runtime = python2.7)
  • Python 3.6 (runtime = python3)

在函数计算服务使用Python编程,需要定义一个Python函数作为入口,一个最简单的函数定义如下:

  1. def my_handler(event, context):
  2. return 'hello world'
  1. 函数名
    • my_handler需要与创建函数时的”Handler”字段相对应:例如创建函数时指定的Handler为main.my_handler,那么函数计算会去加载main.py中定义的my_handler函数
  2. event参数
    • event参数是用户调用函数时传入的数据,在Python2.7中是str类型,在Python3中是bytes类型
  3. context参数
    • context参数中包含一些函数的运行时信息(例如request id/临时AK等)。其类型是FCContext,具体结构和使用在下面的使用context介绍
  4. 返回值
    • 函数的返回值会作为调用函数的结果返回给用户,它可以是任意类型:对于简单类型会函数计算会把它转换成str返回,对于复杂类型会把它转换成JSON字符串返回

进阶使用

使用event

event是用户调用函数时传入的数据,它可以是一个简单的string,也可以是一个JSON string,还可以是一个图片(二进制数据)。函数中的event参数是个字节流,在Python2.7中是str类型,在Python3中是bytes类型,用户在函数中可以根据实际情况对event进行转换:例如输入数据是一个JSON string的话,用户可以把它转换成一个dict:

  1. # -*- coding: utf-8 -*-
  2. import json
  3. def my_handler(event, context):
  4. evt = json.loads(event)
  5. return evt['key']

使用context

context是函数计算在运行时生成的一个对象,其中包含一些运行时有用的信息,用户在代码中可以使用这些信息。context的类型是FCContext,其定义如下:

  1. class Credentials:
  2. def __init__(self, access_key_id, access_key_secret, security_token):
  3. self.access_key_id = access_key_id
  4. self.access_key_secret = access_key_secret
  5. self.security_token = security_token
  6. class ServiceMeta:
  7. def __init__(self, service_name, log_project, log_store):
  8. self.name = service_name
  9. self.log_project = log_project
  10. self.log_store = log_store
  11. class FunctionMeta:
  12. def __init__(self, name, handler, memory, timeout):
  13. self.name = name
  14. self.handler = handler
  15. self.memory = memory
  16. self.timeout = timeout
  17. class FCContext:
  18. def __init__(self, request_id, credentials, function_meta, service_meta, region):
  19. self.requestId = request_id
  20. self.credentials = credentials
  21. self.function = function_meta
  22. self.request_id = request_id
  23. self.service = service_meta
  24. self.region = region

可以看到context中包含了5个信息:

  1. request_id: 本次调用请求的唯一id,用户可以把它记录下来在出现问题的时候方便调查
  2. function: 当前调用的函数的一些基本信息如函数名/函数入口/函数内存/超时时间
  3. credentials: 函数计算服务通过扮演用户提供的服务角色获得的一组临时密钥,其有效时间是5分钟。用户可以在代码中使用它去访问相应的服务(例如OSS),这就避免了用户把自己的AK信息写死在函数代码里。
  4. service: 当前调用的函数所在的service的信息,包括service的名字,接入的SLS的logProject和logStore
  5. region: 当前调用的函数所在区域,如cn.shanghai

例如下面的代码使用临时密钥,向OSS中上传了一个文件:

  1. import json
  2. import oss2
  3. def my_handler(event, context):
  4. evt = json.loads(event)
  5. creds = context.credentials
  6. auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token)
  7. bucket = oss2.Bucket(auth, evt['endpoint'], evt['bucket'])
  8. bucket.put_object(evt['objectName'], evt['message'])
  9. return 'success'

使用logging

用户的函数向stdout打印的内容会被收集到用户在创建Service时指定的LogStore中,有两种打log的方法:

  1. 直接使用print: 这会把内容原样地输出到日志中

    1. def my_handler(event, context):
    2. print 'hello world'
    3. return 'done'

    上面的代码输出的日志内容是:

    1. message:hello world
  2. 使用logging模块: 这会在每条日志中包含时间/requestId/日志级别等信息

    1. import logging
    2. def my_handler(event, context):
    3. logger = logging.getLogger()
    4. logger.info('hello world')
    5. return 'done'

    上面的代码输出的日志内容是:

    1. message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [INFO] hello world

推荐使用logging模块打印log,自动包含requestId能信息方便在出错的时候定位问题日志。

使用内置的模块

除了Python的标准模块,函数计算的Python运行环境中还包含了一些常用模块,用户可以直接引用,目前包含的模块有:

注意:tablestore目前仅支持python2.6和Python2.7,暂不支持python3,所以在python3 runtime 中没有内置tablestore模块

例如使用wand进行图片翻转的函数如下:

  1. from wand.image import Image
  2. def my_handler(event, context):
  3. with Image(blob=event) as img:
  4. print img.size
  5. with img.clone() as i:
  6. i.rotate(180)
  7. return i.make_blob()

注意,上面的函数直接使用event作为图片的二进制数据并且直接把生成的图片作为二进制数据返回。

tips 还有其他第三方库使用的小demo可以查看这里fc-python-demo

使用自定义的模块

如果用户需要使用自定义的模块,则需要将它们与代码一起打包。下面将演示通过fcli添加一个访问mysql的模块PyMySQL的步骤:

  1. 建立一个目录用于存放代码和依赖模块:

    1. mkdir /tmp/code
  2. 新建代码文件,例如/tmp/code/main.py,在代码中使用pymysql:

    1. import pymysql.cursors
    2. # Connect to the database
    3. connection = pymysql.connect(host='localhost',
    4. user='user',
    5. password='passwd',
    6. db='db',
    7. charset='utf8mb4',
    8. cursorclass=pymysql.cursors.DictCursor)
    9. def my_handler(event, context):
    10. with connection.cursor() as cursor:
    11. # Read a single record
    12. sql = "SELECT count(*) FROM `users`"
    13. cursor.execute(sql)
    14. result = cursor.fetchone()
    15. print(result)
    16. return result
  3. 在/tmp/code目录下安装依赖:

    1. cd /tmp/code
    2. pip install -t . PyMySQL

    安装完成之后,/tmp/code目录的内容应该是这样:

    1. ls -l /tmp/code
    2. drwxr-xr-x 9 rockuw staff 306 Jul 5 16:48 PyMySQL-0.7.11.dist-info
    3. -rw-r--r-- 1 rockuw staff 74 Jul 5 16:02 main.py
    4. drwxr-xr-x 26 rockuw staff 884 Jul 5 16:48 pymysql
  4. 使用fcli创建函数并调用:

    1. ./fcli shell
    2. mkf my-func -h main.my_handler --runtime python2.7 -d /tmp/code
    3. invk my-func
需要注意的是,如果引用的module使用C/C++/go编译出来的可执行文件或者库文件,请查看sbox

调用外部命令

用户的函数可能会用到一些工具,而这些工具并不是用Python写的(例如shell脚本/C++或者go编译出来的可执行文件)。用户仍然可以将它们与代码一起打包,然后在函数中通过运行外部命令的方法来使用它们。下面的例子中演示了如何运行一个shell脚本:

  1. import subprocess
  2. def my_handler(event, context):
  3. ret = subprocess.check_output(['bash', '/code/' + 'script.sh'])
  4. return ret

需要注意的是,使用C/C++/go编译出来的可执行文件,需要与函数计算的运行环境兼容。函数计算的Python运行环境是:
  • Linux内核版本:Linux 4.4.24-2.al7.x86_64
  • docker基础镜像:docker pull python:2.7 ; docker pull python:3.6

这边推荐使用fcli工具sbox命令,这边runtime为python2.7,安装mysql-python(含有.so文件)为例:

  1. 执行sbox -d code -t python2.7,其中 -d参数指定代码所在目录,它将被挂载到沙盒环境的”/code”位置;-t参数指定语言类型;(注:第一次执行这个命令由于要pull image,可能要耗费不少时间,请耐心等待…)

  2. 进入沙盒环境后,运行pip install -t . mysql-python安装依赖库

  3. 完成后执行exit退出沙盒环境。此时mysql-python库(含有_mysql.so)已经安装到了code目录下

    注意

    1. sbox命令要求您的机器上已安装docker。docker的具体安装步骤,请参阅相关文档

    2. sbox用到的镜像存储在docker官方镜像库上,国内用户访问速度较慢。建议您使用阿里云镜像加速服务,具体设置请参阅相关文档

    3. 在 linux 下使用docker,要求有 root 权限。所以您需要使用 sudo fcli shell 的方式启动命令行工具;或者您可以参照相关文档设置,以非 root 用户管理 docker。

    4. 这边推荐您总是在沙盒环境中打包第三方库,测试函数和调查问题,这样能避免由于开发环境和运行环境不一致所引起的一些问题。特别是当您的函数依赖二进制文件时,请在沙盒环境中编译相关依赖。

  1. demo fcli shell
  2. Welcome to the function compute world. Have fun!
  3. >>> sbox -d code -t python2.7
  4. Entering the container. Your code is in the /code direcotry.
  5. root@c5adc6ffd861:/code# pip install -t . mysql-python
  6. Collecting mysql-python
  7. Downloading MySQL-python-1.2.5.zip (108kB)
  8. 100% |████████████████████████████████| 112kB 440kB/s
  9. Building wheels for collected packages: mysql-python
  10. Running setup.py bdist_wheel for mysql-python ... done
  11. Stored in directory: /root/.cache/pip/wheels/38/a3/89/ec87e092cfb38450fc91a62562055231deb0049a029054dc62
  12. Successfully built mysql-python
  13. Installing collected packages: mysql-python
  14. Successfully installed mysql-python-1.2.5
  15. root@c5adc6ffd861:/code# exit

异常处理

用户的函数在执行过程如果抛出异常,那么函数计算会把异常捕获并将异常信息返回。例如下面的代码:

  1. def my_handler(event, context):
  2. raise Exception('something is wrong')

调用时收到的响应为:

  1. {
  2. "errorMessage": "something is wrong",
  3. "errorType": "Exception",
  4. "stackTrace": [
  5. [
  6. "File \"/code/main.py\"",
  7. "line 2",
  8. "in my_handler",
  9. "raise Exception('something is wrong')"
  10. ]
  11. ]
  12. }

发生异常时,函数调用的响应的HTTP header中会包含X-Fc-Error-Type: UnhandledInvocationError

本文导读目录