All Products
Search
Document Center

MaxCompute:UDF development (Python 3)

Last Updated:Aug 21, 2026

MaxCompute supports developing user-defined functions (UDFs) in Python 3 to implement custom business logic.

UDF code structure

You can use MaxCompute Studio to write a UDF in Python 3. The code must contain the following components:

  • Module import: required.

    UDF code must include from odps.udf import annotate, which is used to import the function signature. This way, MaxCompute can identify the function signature that is defined in the code. If you want to reference files or tables in UDF code, the UDF code must include from odps.distcache import get_cache_file or from odps.distcache import get_cache_table.

  • Function signature: Required.

    The format is @annotate(<signature>), where signature defines the data types of the function's input parameters and return value. For more information about function signatures, see Function signatures and data types.

  • Custom Python class: Required.

    The class organizes your UDF code and defines the variables and methods that implement your business logic. You can also reference a built-in third-party library or reference file and table resources in your code. For more information, see Third-party library or Reference resources.

  • evaluate method: required.

    The evaluate method is contained in the custom Python class. The evaluate method defines the input parameters and return value of the UDF. Each Python class can contain only one evaluate method.

The following code provides a UDF example.

# Import the function signature module.
from odps.udf import annotate
# Define the function signature.
@annotate("bigint,bigint->bigint")
# Define the custom Python class.
class MyPlus(object):
# Implement the evaluate method.
    def evaluate(self, arg0, arg1):
        if None in (arg0, arg1):
            return None
        return arg0 + arg1

Limits

  • Access the Internet by using UDFs

    By default, MaxCompute does not allow you to access the Internet by using UDFs. If you want to access the Internet by using UDFs, fill in the network connection application form based on your business requirements and submit the application. The MaxCompute technical support team will contact you promptly to enable network connectivity. For more information about how to fill in the network connection application form, see Network connection process.

  • Access a VPC by using UDFs

    By default, MaxCompute does not allow you to access resources in VPCs by using UDFs. To use UDFs to access resources in a VPC, you must establish a network connection between MaxCompute and the VPC. For more information about related operations, see Access VPC resources from a UDF.

  • Read table data by using UDFs, UDAFs, or UDTFs

    You cannot use UDFs, UDAFs, or UDTFs to read data from the following types of tables:

    • Table on which schema evolution is performed

    • Table that contains complex data types

    • Table that contains JSON data types

    • Transactional table

Usage notes

Python 3 is not compatible with Python 2, and both cannot be used in the same SQL statement. Consider compatibility before switching.

Note

Python 2 reached its end of life (EOL) in early 2020. We recommend that you migrate your projects based on their type.

UDF development: General workflow

UDF development involves preparing the environment, writing code, uploading and registering the UDF, and then calling it. The following sections walk through this workflow using MaxCompute Studio, DataWorks, and odpscmd.

MaxCompute Studio

  1. Prerequisites

    Install MaxCompute Studio and connect it to a MaxCompute project before you begin. For more information, see the following topics:

    1. Install MaxCompute Studio

    2. Create a MaxCompute project connection

    3. Configure a Python development environment

  2. Write UDF code.

    1. In the Project panel, under the MaxCompute Studio directory, right-click scripts and select New > MaxCompute Python.

    2. In the Create new MaxCompute python class dialog box, enter a class name for Name, select Python UDF as the type, and then click OK.

    3. Write the UDF code in the editor.

      from odps.udf import annotate
      
      @annotate("string,bigint->string")
      class GetUrlChar(object):
      
          def evaluate(self, url, n):
              if n == 0:
                  return ""
              try:
                  index = url.find(".htm")
                  if index < 0:
                      return ""
                  a = url[:index]
                  index = a.rfind("/")
                  b = a[index + 1:]
                  c = b.split("-")
                  if len(c) < n:
                      return ""
                  return c[-n]
              except Exception:
                  return "Internal error"
                  
      Note

      For information about how to debug Python UDFs locally, see Test a UDF.

  3. Upload and register the UDF.

    Right-click the target Python program and select Deploy to server…. Configure the function name and click OK. For more information, see Upload a file and register a function.

    In this example, the function name is set to UDF_GET_URL_CHAR.

  4. Call the UDF.

    In the left-side navigation pane, click Project Explore. Right-click the target MaxCompute project, select Open Console, then enter and run the SQL statement to call the UDF.

    SET odps.sql.python.version=cp37; -- This command is required to enable Python 3 for the UDF.
    SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);

    The following result is returned:

    +-----+
    | _c0 |
    +-----+
    |  a  |
    +-----+

DataWorks

  1. Prerequisites

    Activate DataWorks and associate it with a MaxCompute project before you begin. For more information, see Connect to MaxCompute by using DataWorks.

  2. Write UDF code.

    You can develop the UDF code in any Python development tool and package it. The following code is an example.

    from odps.udf import annotate
    
    @annotate("string,bigint->string")
    class GetUrlChar(object):
    
        def evaluate(self, url, n):
            if n == 0:
                return ""
            try:
                index = url.find(".htm")
                if index < 0:
                    return ""
                a = url[:index]
                index = a.rfind("/")
                b = a[index + 1:]
                c = b.split("-")
                if len(c) < n:
                    return ""
                return c[-n]
            except Exception:
                return "Internal error"
                
  3. Upload and register the UDF.

    Upload the packaged code and register the UDF in DataWorks. For more information, see the following topics:

    1. Create and use MaxCompute resources

    2. Create and use a user-defined function

  4. Call the UDF.

    After you register the UDF, create an ODPS SQL node to write and run SQL statements that call the UDF. For more information about ODPS SQL nodes, see Develop an ODPS SQL task. The following code provides an example of the SQL statement.

    SET odps.sql.python.version=cp37; -- This command is required to enable Python 3 for the UDF.
    SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);

odpscmd

  1. Prerequisites

    Download and install odpscmd, then configure the config file to connect to a MaxCompute project. For more information, see Connect by using the MaxCompute client (odpscmd).

  2. Write UDF code.

    You can develop the UDF code in any Python development tool and package it. The following code is an example.

    from odps.udf import annotate
    
    @annotate("string,bigint->string")
    class GetUrlChar(object):
    
        def evaluate(self, url, n):
            if n == 0:
                return ""
            try:
                index = url.find(".htm")
                if index < 0:
                    return ""
                a = url[:index]
                index = a.rfind("/")
                b = a[index + 1:]
                c = b.split("-")
                if len(c) < n:
                    return ""
                return c[-n]
            except Exception:
                return "Internal error"
                
  3. Upload and register the UDF.

    Upload the packaged code and register the UDF by using odpscmd. For more information, see the following topics:

    1. ADD PY

    2. CREATE FUNCTION

  4. Call the UDF.

    After you register the UDF, write and run an SQL statement to call it.

    SET odps.sql.python.version=cp37; -- This command is required to enable Python 3 for the UDF.
    SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);

Install the NumPy library

The built-in Python 3 runtime environment does not include NumPy. If your UDF requires NumPy, manually upload the WHEEL package. When you download the package from PyPI or a mirror site, the file name is in the format numpy-<version>-cp37-cp37m-manylinux1_x86_64.whl. For more information about uploading a package, see Resource operations or Use a third-party package in a Python UDF.

For a list of standard libraries that Python 3 supports, see Python 3 standard library.

Function signatures and data types

Format of function signatures:

@annotate(<signature>)

The signature parameter is a string that specifies the data types of input parameters and return value. When you run a UDF, the data types of the input parameters and return value of the UDF must be consistent with the data types specified in the function signature. The data type consistency is checked during semantic parsing. If the data types are inconsistent, an error is returned. Format of a signature:

'arg_type_list -> type'

Parameter description:

  • arg_type_list: specifies the data types of input parameters. If multiple input parameters are used, their data types are separated by commas (,). The following data types are supported: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, DECIMAL(precision,scale), CHAR, and VARCHAR. Complex data types, such as ARRAY, MAP, and STRUCT, and nested complex data types are also supported.

    arg_type_list can be represented by an asterisk (*) or left empty ('').

    • If arg_type_list is represented by an asterisk (*), a random number of input parameters are allowed.

    • If arg_type_list is left empty (''), no input parameters are used.

  • type: specifies the data type of the return value. For a UDF, only one column of values is returned. The following data types are supported: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, DECIMAL, FLOAT, BINARY, DATE, and DECIMAL(precision,scale). Complex data types, such as ARRAY, MAP, and STRUCT, and nested complex data types are also supported.

Note

When you write UDF code, you can select a data type based on the MaxCompute data type edition that is used by your MaxCompute project. For more information about MaxCompute data type editions and the data types supported in each edition, see Data type editions.

The following table provides examples of valid function signatures.

Function signature

Description

'bigint,double->string'

The data types of the input parameters are BIGINT and DOUBLE and the data type of the return value is STRING.

'*->string'

A random number of input parameters are used and the data type of the return value is STRING.

'->double'

No input parameters are used and the data type of the return value is DOUBLE.

'array<bigint>->struct<x:string, y:int>'

The data type of the input parameters is ARRAY<BIGINT> and the data type of the return value is STRUCT<x:STRING, y:INT>.

'->map<bigint, string>'

No input parameters are used and the data type of the return value is MAP<BIGINT, STRING>.

The following table describes the mappings between the data types that are supported in MaxCompute SQL and the Python 2 data types. You must write Python UDFs based on the mappings to ensure the consistency of data types.

MaxCompute SQL type

Python 3 type

BIGINT

INT

STRING

UNICODE

DOUBLE

FLOAT

BOOLEAN

BOOL

DATETIME

DATETIME.DATETIME

FLOAT

FLOAT

CHAR

UNICODE

VARCHAR

UNICODE

BINARY

BYTES

DATE

DATETIME.DATE

DECIMAL

DECIMAL.DECIMAL

ARRAY

LIST

MAP

DICT

STRUCT

COLLECTIONS.NAMEDTUPLE

Referencing resources

You can reference files or tables in Python 2 UDF code by using the odps.distcache module.

  • odps.distcache.get_cache_file(resource_name, mode): Returns the content of a specified file resource in the specified mode.

    • resource_name is a string that specifies the name of an existing table in your MaxCompute project. If the table name is invalid or the table does not exist, an error is returned.

    • The mode parameter is a STRING. The default value is 't'. If you set mode to 't', the file is opened in text mode. If you set mode to 'b', the file is opened in binary mode.

    • The return value is a file-like object. If this object is no longer used, you must call the close method to release the open file.

    The following code shows how to reference a file.

    from odps.udf import annotate
    from odps.distcache import get_cache_file
    @annotate('bigint->string')
    class DistCacheExample(object):
    def __init__(self):
        cache_file = get_cache_file('test_distcache.txt')
        kv = {}
        for line in cache_file:
            line = line.strip()
            if not line:
                continue
            k, v = line.split()
            kv[int(k)] = v
        cache_file.close()
        self.kv = kv
    def evaluate(self, arg):
        return self.kv.get(arg)
  • odps.distcache.get_cache_table(resource_name): Returns the content of a specified table resource.

    • The resource_name parameter specifies an existing table resource in the current MaxCompute project. An exception is thrown if the resource name is invalid or the resource does not exist. Supported data types: BIGINT, STRING, DOUBLE, BOOLEAN, DATETIME, FLOAT, CHAR, VARCHAR, BINARY, DATE, DECIMAL, ARRAY, MAP, and STRUCT.

    • The return value is a Generator. Each iteration yields one table record as an array.

The following code shows how to reference a table.

from odps.udf import annotate
from odps.distcache import get_cache_table
@annotate('->string')
class DistCacheTableExample(object):
    def __init__(self):
        self.records = list(get_cache_table('udf_test'))
        self.counter = 0
        self.ln = len(self.records)
    def evaluate(self):
        if self.counter > self.ln - 1:
            return None
        ret = self.records[self.counter]
        self.counter += 1
        return str(ret)

Calling UDFs

After developing a Python 3 UDF by following the development workflow, you can call it in MaxCompute SQL as follows:

Enable Python 3

By default, MaxCompute uses Python 2. To use Python 3, include the following session flag in your SQL statement.

set odps.sql.python.version=cp37;

Call the function

  • Use a UDF in a MaxCompute project: The method is similar to that of using built-in functions. You can use a user-defined function in the same way that you use a built-in function.

  • Use a UDF across projects: Use a UDF of Project B in Project A. The following statement shows an example: select B:udf_in_other_project(arg0, arg1) as res from table_t;. For more information about cross-project sharing, see Cross-project resource access based on packages.

Migrate Python 2 UDFs

Python 2 reached its EOL in early 2020. We recommend migrating your projects based on their type:

  • New projects: For new MaxCompute projects or projects where you are writing Python UDFs for the first time, use Python 3 for all Python UDFs.

  • Existing projects: For projects with many Python 2 UDFs, exercise caution when enabling Python 3. To gradually migrate, use the following methods:

    • New jobs and new UDFs: Use Python 3 to write UDFs and enable Python 3 at the session level. For more information about how to enable Python 3, see Enable Python 3.

    • Python 2 UDFs: Rewrite Python 2 UDFs to make them compatible with both Python 2 and Python 3. For more information about how to rewrite the UDFs, see Porting Python 2 Code to Python 3.

      Note

      If you write public UDFs shared across multiple MaxCompute projects, ensure they are compatible with both Python 2 and Python 3.

UDF examples