> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chaintable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Function 是什么

> 一行进、一行出的转换逻辑，可以直接写在 Notebook 里，也可以引用一个已保存的 Function 资源。

Function 是 Chaintable 里最小的转换单元：**输入一行数据，返回一行数据（或者 `None`）**。它不管数据从哪来、不管结果写到哪去——那是 [Notebook](/indexing/notebooks/overview) 和平台的事。

```python theme={null}
def to_transfer(record, chain_id):
    value = float(record.get("value") or 0)
    if value <= 0:
        return None          # 返回 None：这一行被丢弃，不写入任何地方
    return {"id": record["id"], "value": value}   # 返回 dict：这一行会被写入目标表
```

<Note>
  Function **只负责算，不负责写**。它的返回值交给调用方（比如 Pipeline 的 Handler）决定怎么处理——写表、丢弃，还是原样返回给你看。Function 本身不会主动往任何表里写数据。
</Note>

## 两种给法

`Trigger(func=...)` 接受两种东西，混用也没问题：

<Columns cols={2}>
  <Card title="直接写一个 Python 函数" icon="code">
    在 Notebook 驱动脚本里写一个 `def`，直接传给 `func=`。SDK 会把这段源码原样发给 worker 执行，不需要预先创建任何东西。

    上手最快，[建你的第一条索引管道](/get-started/first-pipeline) 用的就是这种写法。

    ```python theme={null}
    def to_transfer(record, chain_id):
        ...

    Trigger(table="chain.trace.eth", func=to_transfer, params=[SOURCE_ROW, "eth"])
    ```
  </Card>

  <Card title="引用一个已保存的 Function" icon="database">
    通过「New Function」创建的独立资源，有自己的名字、详情页、Test Case，也能被 [Open API](/openapi/overview) 直接调用。把它的 ID（`<space>.<函数名>`）作为字符串传给 `func=` 即可：

    ```python theme={null}
    Trigger(table="chain.event.eth",
            func="token.event_to_token_transfer",
            params=["eth", SOURCE_ROW])
    ```

    这种写法更适合：转换逻辑要被多个管道复用，或者你想在 Function 详情页单独调试它。
  </Card>
</Columns>

<Tip>
  一个 Function 资源也可以被另一个 Function 调用：`blockx.function.call(function_id, *args, timeout=5)`。
</Tip>

## 编写规则

不管哪种形态，Function 本身遵守同一套规则：

<Card title="编写约定" icon="list-checks" href="/indexing/functions/conventions">
  参数怎么传、返回值有什么要求
</Card>

<Card title="沙箱限制" icon="shield" href="/indexing/functions/sandbox">
  能引用什么、能 import 什么
</Card>
