全部产品

Python

更新时间:2017-09-18 14:06:51   分享:   

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

  • Python 2.7 (runtime = python2.7)

在函数计算服务使用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参数是用户调用函数时传入的数据,其类型是str
  3. context参数
    • context参数中包含一些函数的运行时信息(例如request id/临时AK等)。其类型是FCContext,具体结构和使用在下面的使用context介绍
  4. 返回值
    • 函数的返回值会作为调用函数的结果返回给用户,它可以是任意类型:对于简单类型会函数计算会把它转换成str返回,对于复杂类型会把它转换成JSON字符串返回

进阶使用

使用event

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

  1. import json
  2. def my_handler(event, context):
  3. evt = json.loads(event)
  4. 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 FunctionMeta:
  7. def __init__(self, name, handler, memory, timeout):
  8. self.name = name
  9. self.handler = handler
  10. self.memory = memory
  11. self.timeout = timeout
  12. class FCContext:
  13. def __init__(self, request_id, credentials, function_meta):
  14. self.request_id = request_id
  15. self.credentials = credentials
  16. self.function = function_meta

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

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

例如下面的代码使用临时密钥,向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运行环境中还包含了一些常用模块,用户可以直接引用,目前包含的模块有:

例如使用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作为图片的二进制数据并且直接把生成的图片作为二进制数据返回。

使用自定义的模块

如果用户需要使用自定义的模块,则需要将它们与代码一起打包。下面将演示通过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

调用外部命令

用户的函数可能会用到一些工具,而这些工具并不是用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

异常处理

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

  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

本文导读目录
本文导读目录
以上内容是否对您有帮助?