Python Interpreter (PythonREPLComponent) 组件分析
一、组件概述
1. 基本信息
| 属性 | 值 |
|---|---|
| 组件名称 | Python Interpreter |
| 类名 | PythonREPLComponent |
| 分类 | Processing(数据处理) |
| 图标 | square-terminal |
| 描述 | Run Python code with optional imports. Use print() to see the output. |
| 文档 | docs.langflow.org/components-… |
| 源码位置 | langflow/components/processing/python_repl_core.py |
2. 组件用途
Python Interpreter 组件允许用户在 Langflow 工作流中执行 Python 代码,支持:
- 数学计算和数据处理
- 使用常用库(math, pandas, numpy 等)
- 自定义逻辑处理
- 数据转换和分析
二、代码结构分析
1. 完整源码
import importlib
from langchain_experimental.utilities import PythonREPL
from langflow.custom.custom_component.component import Component
from langflow.io import MultilineInput, Output, StrInput
from langflow.schema.data import Data
class PythonREPLComponent(Component):
display_name = "Python Interpreter"
description = "Run Python code with optional imports. Use print() to see the output."
documentation: str = "https://docs.langflow.org/components-processing#python-interpreter"
icon = "square-terminal"
inputs = [
StrInput(
name="global_imports",
display_name="Global Imports",
info="A comma-separated list of modules to import globally, e.g. 'math,numpy,pandas'.",
value="math,pandas",
required=True,
),
MultilineInput(
name="python_code",
display_name="Python Code",
info="The Python code to execute. Only modules specified in Global Imports can be used.",
value="print('Hello, World!')",
input_types=["Message"],
tool_mode=True,
required=True,
),
]
outputs = [
Output(
display_name="Results",
name="results",
type_=Data,
method="run_python_repl",
),
]
def get_globals(self, global_imports: str | list[str]) -> dict:
"""Create a globals dictionary with only the specified allowed imports."""
global_dict = {}
try:
if isinstance(global_imports, str):
modules = [module.strip() for module in global_imports.split(",")]
elif isinstance(global_imports, list):
modules = global_imports
else:
msg = "global_imports must be either a string or a list"
raise TypeError(msg)
for module in modules:
try:
imported_module = importlib.import_module(module)
global_dict[imported_module.__name__] = imported_module
except ImportError as e:
msg = f"Could not import module {module}: {e!s}"
raise ImportError(msg) from e
except Exception as e:
self.log(f"Error in global imports: {e!s}")
raise
else:
self.log(f"Successfully imported modules: {list(global_dict.keys())}")
return global_dict
def run_python_repl(self) -> Data:
try:
globals_ = self.get_globals(self.global_imports)
python_repl = PythonREPL(_globals=globals_)
result = python_repl.run(self.python_code)
result = result.strip() if result else ""
self.log("Code execution completed successfully")
return Data(data={"result": result})
except ImportError as e:
error_message = f"Import Error: {e!s}"
self.log(error_message)
return Data(data={"error": error_message})
except SyntaxError as e:
error_message = f"Syntax Error: {e!s}"
self.log(error_message)
return Data(data={"error": error_message})
except (NameError, TypeError, ValueError) as e:
error_message = f"Error during execution: {e!s}"
self.log(error_message)
return Data(data={"error": error_message})
def build(self):
return self.run_python_repl
2. 代码结构图
PythonREPLComponent
│
├── 输入参数 (Inputs)
│ ├── global_imports (StrInput)
│ │ ├── 类型: 字符串
│ │ ├── 默认值: "math,pandas"
│ │ └── 说明: 全局导入模块列表
│ │
│ └── python_code (MultilineInput)
│ ├── 类型: 多行文本
│ ├── 默认值: "print('Hello, World!')"
│ ├── input_types: ["Message"]
│ ├── tool_mode: True
│ └── 说明: 要执行的 Python 代码
│
├── 输出参数 (Outputs)
│ └── results (Output)
│ ├── 类型: Data
│ ├── 方法: run_python_repl
│ └── 说明: 执行结果
│
└── 核心方法 (Methods)
├── get_globals() # 构建全局导入字典
├── run_python_repl() # 执行 Python 代码
└── build() # 组件构建方法
三、参数详解
1. 输入参数
global_imports(全局导入)
| 属性 | 说明 |
|---|---|
| 类型 | 字符串 (StrInput) |
| 显示名称 | Global Imports |
| 必填 | 是 |
| 默认值 | "math,pandas" |
| 说明 | 逗号分隔的模块列表,例如:math,numpy,pandas |
支持的常用模块:
| 模块 | 用途 |
|---|---|
math | 数学函数(三角函数、对数等) |
pandas | 数据分析和处理 |
numpy | 数值计算 |
json | JSON 数据处理 |
datetime | 日期时间处理 |
re | 正则表达式 |
collections | 高级数据结构 |
python_code(Python 代码)
| 属性 | 说明 |
|---|---|
| 类型 | 多行文本 (MultilineInput) |
| 显示名称 | Python Code |
| 必填 | 是 |
| 默认值 | print('Hello, World!') |
| input_types | ["Message"] - 可接收 Message 类型输入 |
| tool_mode | True - 支持工具模式 |
| 说明 | 要执行的 Python 代码,只有 Global Imports 中指定的模块可以使用 |
2. 输出参数
results(执行结果)
| 属性 | 说明 |
|---|---|
| 类型 | Data 对象 |
| 显示名称 | Results |
| 方法 | run_python_repl |
| 返回结构 | {"result": "执行结果字符串"} 或 {"error": "错误信息"} |
四、参数传递机制
1. 数据流图
┌─────────────────┐
│ 上游组件 │
│ (Chat/Input) │
└────────┬────────┘
│ Message/Data
↓
┌─────────────────────────────────────────┐
│ Python Interpreter │
│ │
│ ┌───────────────────────────────────┐ │
│ │ global_imports: "math,pandas" │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────┐ │
│ │ python_code (可接收上游输入) │ │
│ │ - 输入类型: ["Message"] │ │
│ │ - tool_mode: True │ │
│ └───────────────────────────────────┘ │
│ │
│ 执行: run_python_repl() │
│ ┌───────────────────────────────────┐ │
│ │ 1. get_globals() │ │
│ │ 2. PythonREPL(_globals) │ │
│ │ 3. python_repl.run(code) │ │
│ └───────────────────────────────────┘ │
└────────────────┬────────────────────────┘
│ Data
↓
┌────────────────┐
│ 下游组件 │
└────────────────┘
2. input_types 参数说明
input_types=["Message"] 表示 python_code 输入可以接收来自上游组件的 Message 对象:
# 当上游组件输出 Message 时
# python_code 会自动接收 Message.content 作为代码
3. tool_mode 参数说明
tool_mode=True 表示该组件可以作为工具被 Agent 调用:
# Agent 可以动态调用此组件执行代码
tool = PythonREPLComponent()
result = agent.run("用 Python 计算 15 * 23")
4. 参数传递示例
# 场景 1: 静态代码执行
global_imports = "math,numpy"
python_code = "print(math.sqrt(16))"
# 输出: {"result": "4.0"}
# 场景 2: 接收上游 Message 输入
# 上游组件输出: Message(content="print('Hello')")
# python_code 自动接收上游的 Message.content
# 输出: {"result": "Hello"}
# 场景 3: 工具模式调用
# Agent 生成代码: "result = pandas.DataFrame({'a': [1,2,3]})"
# 执行并返回结果
五、使用案例
案例 1: 数学计算
配置:
Global Imports: math
Python Code:
import math
# 计算 PI 的值
print(f"π = {math.pi}")
# 三角函数计算
angle = math.radians(45)
print(f"sin(45°) = {math.sin(angle)}")
# 平方根计算
print(f"√16 = {math.sqrt(16)}")
输出:
{
"result": "π = 3.141592653589793\nsin(45°) = 0.7071067811865476\n√16 = 4.0"
}
案例 2: 数据处理 (Pandas)
配置:
Global Imports: pandas
Python Code:
import pandas as pd
# 创建 DataFrame
data = {
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35],
'city': ['NYC', 'LA', 'SF']
}
df = pd.DataFrame(data)
# 数据统计
print("=== 数据概览 ===")
print(df)
print("\n=== 平均年龄 ===")
print(df['age'].mean())
print("\n=== 城市统计 ===")
print(df['city'].value_counts())
输出:
{
"result": "=== 数据概览 ===\n name age city\n0 Alice 25 NYC\n1 Bob 30 LA\n2 Charlie 35 SF\n\n=== 平均年龄 ===\n30.0\n\n=== 城市统计 ===\nNYC 1\nLA 1\nSF 1\nName: city, dtype: int64"
}
案例 3: 数值计算 (NumPy)
配置:
Global Imports: numpy
Python Code:
import numpy as np
# 创建数组
arr = np.array([1, 2, 3, 4, 5])
print(f"数组: {arr}")
print(f"平均值: {np.mean(arr)}")
print(f"标准差: {np.std(arr)}")
print(f"总和: {np.sum(arr)}")
print(f"平方: {np.square(arr)}")
输出:
{
"result": "数组: [1 2 3 4 5]\n平均值: 3.0\n标准差: 1.4142135623730951\n总和: 15\n平方: [ 1 4 9 16 25]"
}
案例 4: JSON 数据处理
配置:
Global Imports: json
Python Code:
import json
# JSON 字符串
json_str = '{"name": "Alice", "age": 25, "skills": ["Python", "SQL"]}'
data = json.loads(json_str)
print("解析后的数据:")
print(data)
print(f"\n姓名: {data['name']}")
print(f"技能: {', '.join(data['skills'])}")
# 修改后转回 JSON
data['age'] = 26
new_json = json.dumps(data, indent=2)
print(f"\n修改后的 JSON:\n{new_json}")
输出:
{
"result": "解析后的数据:\n{'name': 'Alice', 'age': 25, 'skills': ['Python', 'SQL']}\n\n姓名: Alice\n技能: Python, SQL\n\n修改后的 JSON:\n{\n "name": "Alice",\n "age": 26,\n "skills": [\n "Python",\n "SQL"\n ]\n}"
}
案例 5: 文本处理
配置:
Global Imports: re
Python Code:
import re
text = "我的电话是 138-1234-5678,邮箱是 example@example.com"
# 提取手机号
phone = re.search(r'\d{3}-\d{4}-\d{4}', text)
print(f"手机号: {phone.group() if phone else '未找到'}")
# 提取邮箱
email = re.search(r'[\w.]+@[\w.]+', text)
print(f"邮箱: {email.group() if email else '未找到'}")
# 分割文本
parts = re.split(r'[,,]', text)
print(f"\n分割结果:")
for i, part in enumerate(parts, 1):
print(f"{i}. {part.strip()}")
输出:
{
"result": "手机号: 138-1234-5678\n邮箱: example@example.com\n\n分割结果:\n1. 我的电话是 138-1234-5678\n2. 邮箱是 example@example.com"
}
案例 6: 日期时间处理
配置:
Global Imports: datetime
Python Code:
from datetime import datetime, timedelta
# 当前时间
now = datetime.now()
print(f"当前时间: {now}")
print(f"格式化: {now.strftime('%Y-%m-%d %H:%M:%S')}")
# 时间计算
future = now + timedelta(days=7)
print(f"\n一周后: {future.strftime('%Y-%m-%d')}")
# 时间差
date1 = datetime(2024, 1, 1)
date2 = datetime(2024, 12, 31)
diff = date2 - date1
print(f"2024年天数: {diff.days}")
输出:
{
"result": "当前时间: 2024-01-19 15:40:23.456789\n格式化: 2024-01-19 15:40:23\n\n一周后: 2024-01-26\n\n2024年天数: 365"
}
六、错误处理
1. 错误类型
| 错误类型 | 触发条件 | 返回格式 |
|---|---|---|
| ImportError | 模块导入失败 | {"error": "Import Error: ..."} |
| SyntaxError | 代码语法错误 | {"error": "Syntax Error: ..."} |
| NameError | 变量/函数未定义 | {"error": "Error during execution: ..."} |
| TypeError | 类型错误 | {"error": "Error during execution: ..."} |
| ValueError | 值错误 | {"error": "Error during execution: ..."} |
2. 错误示例
ImportError 示例:
Global Imports: nonexistent_module
Python Code: print("test")
输出:
{
"error": "Import Error: Could not import module nonexistent_module: No module named 'nonexistent_module'"
}
SyntaxError 示例:
Global Imports: math
Python Code: print(math.sqrt(16 # 缺少右括号
输出:
{
"error": "Syntax Error: unexpected EOF while parsing (<string>, line 1)"
}
七、最佳实践
1. 推荐做法
# ✅ 使用 print() 输出结果
print(result)
print(f"计算结果: {value}")
# ✅ 明确导入所需模块
Global Imports: math,pandas,json
# ✅ 添加错误处理
try:
result = risky_operation()
print(result)
except Exception as e:
print(f"错误: {e}")
2. 避免的做法
# ❌ 不要尝试导入未在 Global Imports 中声明的模块
import os # 会失败,因为 os 不在 Global Imports 中
# ❌ 不要使用系统调用
import subprocess
subprocess.run(['ls']) # 安全风险
# ❌ 不要无限循环
while True:
pass # 会导致超时
3. 性能建议
| 建议 | 说明 |
|---|---|
| 使用向量化操作 | 使用 NumPy/Pandas 的向量化函数而非循环 |
| 限制数据量 | 避免处理超大文本或数据集 |
| 避免复杂计算 | 保持代码简洁高效 |
| 使用合适的数据结构 | 选择列表/字典/集合的最优类型 |
八、与其他组件对比
| 组件 | 用途 | 特点 |
|---|---|---|
| Python Interpreter | 执行 Python 代码 | 简单直接,支持常用库 |
| Python Script Executor | 执行 Python 脚本 | 支持参数注入,捕获 stdout/stderr |
| PythonCodeStructuredTool | 创建结构化工具 | 已废弃,使用 Python Interpreter 替代 |
九、总结
核心特性
- 安全性: 只能使用 Global Imports 中指定的模块
- 简洁性: 直接编写 Python 代码,无需复杂配置
- 灵活性: 支持多种数据处理场景
- 可扩展性: 可作为工具被 Agent 调用
适用场景
- ✅ 数学计算和数值分析
- ✅ 数据处理和转换
- ✅ 文本处理和正则表达式
- ✅ JSON/YAML 数据解析
- ✅ 日期时间处理
- ✅ 自定义逻辑实现
不适用场景
- ❌ 需要导入未预声明的模块
- ❌ 需要文件系统操作
- ❌ 需要网络请求
- ❌ 长时间运行的任务
- ❌ 需要调用外部 API
十、相关文件
- 源码:
langflow/components/processing/python_repl_core.py - 基类:
langflow/custom/custom_component/component.py - 数据类型:
langflow/schema/data.py - 输入定义:
langflow/io/