W3

Vyper

0.4.x

EVM 系

为可审计性而生的 Python 风格语言,刻意砍掉了继承与修饰器

Vyper 的设计哲学是「让审计变简单」:没有继承、没有函数重载、没有修饰器、没有内联汇编,所有状态的读写边界都要显式声明。代价是表达能力弱、生态与工具链不如 Solidity 丰富,适合逻辑简单、安全性优先的合约(金库、Curve 类 AMM、简单代币)。

3 个语法章节5 段可复制代码含在线练习

从 Solidity 视角看差异

如果已经会 Solidity,这张表比从头读语法快得多。

差异点说明
缩进与注解用 Python 式缩进代替大括号;类型用 @decorator 声明(@external / @view / @payable)。
没有继承与修饰器用模块(import)与接口组合代替继承;重入保护有内置的 @nonreentrant("lock")。
溢出默认检查所有算术默认检查溢出,不需要 unchecked 块;想省 Gas 要用 unsafe_add 显式标注。
存储声明状态变量必须在模块级用 name: public(uint256) 声明,类型在后、名字在前。
1

模块级声明与函数

1 段代码

状态变量在文件顶部声明,函数用装饰器标注外部可见性与可变性。

  • @external 是唯一对外暴露的函数类型,@internal 只能内部调用
  • 返回值用 -> 声明,多返回值写成 -> (uint256, bool)
  • 常量用 constant(类型),不可变值用 immutable(类型) 在部署时确定
  • 没有构造函数关键字,用 @deploy def __init__() 代替
最小可部署合约
最小可部署合约Vyper

@view 与 @external 可叠加;顺序不影响语义,但社区惯例是 @view 在前。

2

映射、数组与结构体

2 段代码

HashMap 是唯一的内置映射,动态数组必须有长度上限。

  • HashMap[K, V] 不可遍历,必须自己维护索引数组或计数
  • DynArray[T, N] 需要在类型里写死最大长度,长度随合约一起上链
  • struct 不自动提供公开 getter,要么手写 @view 函数,要么用 public 变量
  • 不存在 mapping 的嵌套糖:HashMap[address, HashMap[address, uint256]] 要显式写出来
HashMap 与 DynArray
HashMap 与 DynArrayVyper
结构体与接口调用
结构体与接口调用Vyper

接口里每个函数都必须写可变性标注(view / nonpayable / payable),否则编译不过。

3

安全特性

2 段代码

Vyper 把重入锁、边界检查都做成了语言级能力,这是它最大的卖点。

  • @nonreentrant("key") 是内置重入锁,必须在所有相关函数上用同一个 key
  • raw_call 是唯一的外部调用方式之一,可以控制 revert_on_failure 与返回数据长度上限
  • assert 与 raise 都会 revert;raise 可带自定义错误对象,Gas 更省
  • send / raw_call 转账不会自动检查成功,必须看返回值
内置重入锁与安全转账
内置重入锁与安全转账Vyper
自定义错误与溢出控制
自定义错误与溢出控制Vyper

本章练习

这一段要让你看懂:Vyper 不是「另一种语法的 Solidity」:它砍掉了继承、修饰器、重载与内联汇编,把可变性与重入保护做成语言级装饰器,代价是表达能力更弱。迁移前先确认目标合约是否真的需要这些能力。

试一试 · Solidity ↔ Vyper 写法对照翻译

可直接改代码 · 在浏览器沙箱里真跑
playground.jsJavaScript
运行环境:iframe 沙箱(无 cookie 权限)。只支持纯 JS 片段,不支持 import / require;需要模块请用下方的完整示例复制到项目里。
检查点(跑完后逐条核对)
  • uint256 public total; 被翻译成 total: public(uint256)
  • mapping 被翻译成 HashMap[address, uint256]
  • require(...) 被翻译成 assert(注意 Vyper 的参数字符串反了位置)
  • 输出末尾列出三处必须手工重写的差异

切换其他语言