Files
2026-10-13 15:36:42 +08:00

27 KiB
Raw Permalink Blame History

06 - 面向对象与运算符重载

Viper 中的 class 有两种语义:数据布局(结构体/联合体/枚举,见 05-classes.md)和面向对象。OOP 能力由类内是否存在方法自动判定(StructEntry.IsOOP);多态用 virtual,非多态继承(C++ 风格,无 vtable 开销)用 novirtual。

@t.Object 装饰器默认不需要写、也尽量避免使用——OOP 由「类内是否有方法」自动判定,写与不写行为一致。这是本文唯一一次提及,新代码请直接省略。

类修饰符(virtual / novirtual)

virtual / novirtual 是前置软关键字,类级与方法级都可用:

virtual class Shape:            # 类级:默认该类所有方法都进虚表
    def area(self) -> float: ...
    novirtual def helper(self) -> int: ...   # 只有 helper 被排除出虚表

novirtual class Node:           # 类级:默认该类所有方法都非虚
    def plain(self) -> int: ...
    virtual def hooked(self) -> int: ...     # 只有 hooked 进虚表
  • virtual class / novirtual class:类级修饰符——默认该类所有方法都采用这个级别;
  • virtual def / novirtual def:方法级修饰符——只改变单个方法、覆盖类级默认,只能直接写在类体内;
  • 例:novirtual 类里某个方法想进虚表,写 novirtual class C: + virtual def m(self);反之 virtual 类里把某方法排除出虚表,写 virtual class C: + novirtual def m(self);
  • 非法形态(修饰符位置错误、virtual virtual 等)编译期 fail-fast。

面向对象(OOP)

类内定义成员方法即拥有面向对象支持(成员方法、运算符重载、属性装饰器等);编译器根据「结构体内是否有函数定义」自动判定 OOP 行为。

基本定义

class ViperKernel:
    BootInfo: bootinfo*
    VGA: vga._VGAScreenDriver*
    VGA_drv: vga._VGAScreenDriver

    def __init__(self):
        self.BootInfo = BootInfo
        serial.init()
        serial.puts("ViperOS VKernel Test\n")

避免在 __init__ 中使用 return,虽然不会报错,但是你永远无法获得 return 的结果,如果需要提前结束代码流,return 也不失为一种办法。

成员方法

class Sheet:
    id: int
    x: int
    y: int
    w: int
    h: int

    def __init__(self, x: int, y: int, w: int, h: int):
        self.x = x
        self.y = y
        self.w = w
        self.h = h

    def MoveTo(self, nx: int, ny: int):
        self.x = nx
        self.y = ny

    def Resize(self, nw: int, nh: int):
        self.w = nw
        self.h = nh

方法调用

sheet: Sheet = Sheet(0, 0, 640, 480)
sheet.MoveTo(100, 100)
sheet.Resize(800, 600)

属性装饰器

支持 Python 的 @property 和 @xxx.setter 装饰器:

@xxx.setter 和自定义装饰器正在试验阶段,尽可能不要使用

class MyObj:
    _value: int

    @property
    def value(self) -> int:
        return self._value

    @value.setter
    def value(self, v: int):
        self._value = v

静态方法

@staticmethod
def _yield():
    pass

对象指针与解引用

对象类实例通常通过指针操作:

obj_ptr: MyClass* = &MyClass()
obj: MyClass = *obj_ptr

成员访问

通过 self 访问成员变量和方法:

def method(self) -> void:
    self.x = 10
    y: int = self.y
    self.DoSomething()

内嵌对象

对象类可以包含其他对象实例(非指针):

class Sheet:
    _surf_obj: gfx.Surface
    _renderer_obj: gfx.Renderer
    surf: gfx.Surface*
    renderer: gfx.Renderer*

    def __init__(self, fb: uint32*, zb: float*, w: int, h: int):
        self._surf_obj = gfx.Surface(fb, zb, w, h)
        self.surf = &self._surf_obj
        self._renderer_obj = gfx.Renderer(self.surf)
        self.renderer = &self._renderer_obj

__before_init__ 方法

仅当类内含方法或继承虚方法时才生成 __before_init__ 方法(纯数据 class 不生成)。它在 __init__ 之前自动填充成员默认值,并对 virtual 类初始化 vtable:

define void @"<SHA1>.ClassName.__before_init__"(%"<SHA1>.ClassName"* %self) {
entry:
  ; 对 virtual 类:存储 vtable 指针到 slot 0
  ; 遍历所有成员:若有默认值则 store 默认值,否则 store 零值
  ret void
}

职责:

  • 填充类定义中声明的成员默认值(如 x: int = 0 中的 0)
  • 对无默认值的成员填充类型零值
  • 对 virtual 类额外初始化 vtable 指针

调用时机(由编译器在构造时自动插入):

  1. 不存在 __new__ 时:在 alloca 分配之后调用一次,随后进入 __init__
  2. 存在 __new__ 时:在 __new__ 之后对最终存储指针调用一次,随后进入 __init__

关于 __new__:

  • __new__ 返回 self 时使用默认的 alloca 存储
  • __new__ 的签名可与 __init__ 不同
  • __new__ 与 virtual 兼容
  • __new__ 本身不入虚表

就地构造:用户也可手动调用 __before_init__ 实现就地构造(placement new 语义),典型用法见 mpool.alloc_buf:

buf: Buf* = pool.alloc(Buf.__sizeof__())
buf.__before_init__()          # 填充默认值
buf.__init__(args)             # 用户初始化逻辑

跨模块导入类时,导入侧也会声明 __before_init__,保证跨模块构造行为一致。

novirtual 非多态继承

novirtual 启用 C++ 风格的非多态继承(对应 struct A : B {} 无 virtual)。与 virtual 的区别:

特性 novirtual virtual
vtable 指针 ❌ 无 ✅ 自动插入 slot 0
虚派发 ❌ 无 ✅ 支持
方法继承 ✅ 调用点解析直调父类 ✅ 通过 vtable
字段展平 ✅ 父类字段前置嵌入 ✅ 父类字段前置嵌入(vtable 之后)
运行时开销 零 每次虚调用一次间接跳转

基本定义

novirtual class LinkedNode:
    next: LinkedNode*
    prev: LinkedNode*
    def append(self, node: LinkedNode*): ...

novirtual class GNode(LinkedNode):    # 非多态继承
    value: int

子类 GNode 的结构体布局为 {next, prev, value}(父类字段前置,无 vtable 指针)。

方法继承机制

子类调用父类方法时,实际机制为调用点解析:编译器沿 MRO(方法解析顺序)定位到定义该方法的父类,按字节偏移调整 this 指针后 bitcast,在调用点直接调用父类实现(无 wrapper 生成、无尾调用)。

这里的 MRO 为「深度优先 + 声明顺序 + 去重」(含自身),不是 Python 的 C3 线性化;详见 14-multiple-inheritance.md。

跨模块继承

跨模块父类(如 linkedlist.LinkedNode)的 novirtual 标记会在导入时被检测并记录,子类继承时同样跳过 vtable 插入。

向下转型

父类指针→子类指针需显式转型(生成 bitcast IR):

root: Node = Node()                    # Node 继承 LinkedNode
child: LinkedNode* = root.child
# child 是 LinkedNode*,需要转回 Node*:
node: Node* = (Node*)(child)

隐式转型仅向上(子→父)。

virtual 虚函数表与多态

规划:将引入 T1 & T2(TypeIntersection)表达 object(尤其是带 vtable 的 object)的交集类型,作为多态对象组合的静态类型手段(详见 02-type-system.md 类型组合规划演进,尚未实现)。

尽可能避免使用 self[0] 来获取结构体成员,其不稳定,也不要手动操作虚表。

用 virtual(类级)启用虚函数表支持。启用后,结构体第一个成员自动插入 i8* 类型的 vtable 指针。类内需有方法(OOP 行为由「结构体内是否有函数」自动判定)。

基本定义

virtual class Base:
    def __init__(self):
        pass
    def method(self) -> int:
        return 0

在 LLVM IR 中,virtual 类的结构体类型自动插入 vtable 指针:

%"<SHA1>.Base" = type { i8*, i32 }

同时,编译器会生成全局 vtable 变量。vtable 实为 internal constant struct{ n x i8* }——即含 n 个 i8* 函数指针成员的结构体常量(成员为带 bitcast 的初始化文本),变量名为 <sha1>.Class.vtable,并非 [1 x i8*] zeroinitializer:

@"<sha1>.Base.vtable" = internal constant { i8* } {
  i8* bitcast (i32 (%"<sha1>.Base"*)* @"<sha1>.Base.method" to i8*)
}

继承与多态

虚表可以帮你使用继承语法实现多态:

virtual class Base:
    def __init__(self):
        pass
    def method(self) -> int:
        return 0

virtual class M1(Base):
    def method(self) -> int:
        return 1

当 M1 被初始化时,VTable 会自动修改,这点和 C++ 相同,尽可能避免直接操作 VTable。

继承时,子类会自动继承父类的成员变量和方法。子类重写父类方法时,vtable 中对应位置的函数指针被子类方法替换,实现多态。

VTable 运行时修改

如果需要临时构造一个额外的 Base 结构体,还可以使用:

virtual class Base:
    def __init__(self):
        pass
    def method(self) -> int:
        return 0

def __method1(self) -> int:
    return 1

export def main() -> int:
    b: Base = Base()
    b.method = __method1

启用 VTable 的表中,允许直接修改内部函数为函数指针,在底层,此操作将修改 VTable 来达成目的。编译器会检测当前 vtable 是否与类 vtable 相同,如果相同则创建 vtable 的副本(memcpy),避免修改影响所有实例。

虚方法调度机制

虚方法调用的核心流程:

  1. 从对象指针 GEP 获取第 0 个 slot(vtable 指针)
  2. 加载 vtable 指针
  3. bitcast 为 [N x i8*]* 类型
  4. GEP 获取方法索引处的函数指针
  5. 加载函数指针
  6. bitcast 为正确的函数指针类型
  7. 间接调用

方法级虚表开关

类级 virtual / novirtual 决定该类所有方法的默认级别;要单独改变某一个方法,就在该方法上加相反的方法级修饰符:

  • novirtual 类中单独标注 virtual def 的方法进入虚表;
  • virtual 类中单独标注 novirtual def 的方法被排除在虚表之外。
novirtual class Node:                     # 默认:所有方法都非虚
    def plain(self) -> int: ...               # 跟随类级 → 非虚
    virtual def hooked(self) -> int: ...      # 仅 hooked 进虚表

virtual class Shape:                      # 默认:所有方法都进虚表
    def area(self) -> float: ...              # 跟随类级 → 虚
    novirtual def helper(self) -> int: ...    # 仅 helper 排除出虚表

以上行为由 func_vtable_test 实证。

super()

super().method(...) 形态被编译为静态父类方法调用(仅该形态被支持),不经过 vtable 动态派发:

virtual class Base:
    def method(self) -> void:
        pass

virtual class Derived(Base):
    def method(self) -> void:
        super().method()   # 静态调用父类实现

继承

结构体成员继承

当子类继承父类(父类在 Gen.class_members 中存在)时:

  • 父类的成员变量被继承到子类(排在子类成员之前)
  • 父类的默认值也被继承
  • 父类的方法被继承(重命名为 子类名.方法名)
class Animal:
    name: [32]char
    age: int

    def __init__(self, age: int):
        self.age = age

    def Speak(self) -> void:
        serial.puts("...\n")

class Dog(Animal):
    breed: int

    def Speak(self) -> void:
        serial.puts("Woof!\n")

异常类继承

Viper 支持异常类的继承,用于 try/except 的异常匹配:

class MyError(Exception):
    pass

class SpecificError(MyError):
    pass

详见 09-exceptions.md。

运算符重载

对象类支持运算符重载。编译器在遇到运算符时,先尝试左操作数的 dunder 方法;左操作数无对应方法时,回退右操作数的反向 dunder(a + b → 先 a.__add__(b),缺失再 b.__radd__(a))。TPC 与 VPC 两端行为一致。

算术运算符重载

运算符 Dunder 方法 示例
+ __add__ a + b → a.__add__(b)
- __sub__ a - b → a.__sub__(b)
* __mul__ a * b → a.__mul__(b)
/ __truediv__ a / b → a.__truediv__(b)
// __floordiv__ a // b → a.__floordiv__(b)
% __mod__ a % b → a.__mod__(b)
** __pow__ a ** b → a.__pow__(b)
& __and__ a & b → a.__and__(b)
| __or__ a | b → a.__or__(b)
^ __xor__ a ^ b → a.__xor__(b)
<< __lshift__ a << b → a.__lshift__(b)
>> __rshift__ a >> b → a.__rshift__(b)

基础类型(整数/浮点)的 ** 由编译器直接 lower 为 llvm.pow:整数结果在指数为非负整数常量时回写为左操作数类型,其余为浮点结果。自定义类型的 ** 走 __pow__ 重载。

示例:

class Vec2:
    x: float
    y: float

    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def __add__(self, other: Vec2) -> Vec2:
        result: Vec2 = Vec2(0.0, 0.0)
        result.x = self.x + other.x
        result.y = self.y + other.y
        return result

    def __mul__(self, scalar: float) -> Vec2:
        result: Vec2 = Vec2(0.0, 0.0)
        result.x = self.x * scalar
        result.y = self.y * scalar
        return result

增量赋值运算符重载

增量赋值先调度对象的增量 dunder(+= → __iadd__),该类无增量 dunder 时回退对应普通 dunder(__add__);基础类型走原生运算。两端支持:

运算符 增量 Dunder 回退 Dunder
+= __iadd__ __add__
-= __isub__ __sub__
*= __imul__ __mul__
/= __itruediv__ __truediv__
//= __ifloordiv__ __floordiv__
%= __imod__ __mod__
**= __ipow__ __pow__
&= __iand__ __and__
|= __ior__ __or__
^= __ixor__ __xor__
<<= __ilshift__ __lshift__
>>= __irshift__ __rshift__

调度范围与 TPC 一致:仅局部变量目标调度增量 dunder(全局 / nonlocal 目标不调度)。重载返回值须与目标变量类型兼容(VPC 侧不兼容时编译期 fail-fast)。

比较运算符重载

__eq__/__ne__/__lt__/__le__/__gt__/__ge__ 已自动调度(映射与调用点自动调度,opovl_test 覆盖);未定义 __eq__ 时比较回退为默认身份比较。

运算符 Dunder 方法 状态
== __eq__ 已自动调度
!= __ne__ 已自动调度
< __lt__ 已自动调度
<= __le__ 已自动调度
> __gt__ 已自动调度
>= __ge__ 已自动调度

反向运算符重载

左操作数无对应普通 dunder 时,自动调度右操作数的反向 dunder(a + b → b.__radd__(a))。两端支持:

Dunder 方法 语义
__radd__ 右操作数加法
__rsub__ 右操作数减法
__rmul__ 右操作数乘法
__rtruediv__ 右操作数真除法
__rfloordiv__ 右操作数整除
__rmod__ 右操作数取模
__rpow__ 右操作数幂运算
__rand__ 右操作数按位与
__ror__ 右操作数按位或
__rxor__ 右操作数按位异或
__rlshift__ 右操作数左移
__rrshift__ 右操作数右移

一元运算符重载

__neg__/__pos__/__invert__ 已自动调度。

运算符 Dunder 方法 状态
-a __neg__ 已自动调度
+a __pos__ 已自动调度
~a __invert__ 已自动调度

可调用对象 __call__

对象类定义了 __call__ 时,obj(args) 自动分发到 obj.__call__(args)(两端已调度)。

class Counter:
    value: int

    def __init__(self):
        self.value = 0

    def __call__(self) -> int:
        self.value += 1
        return self.value

c: Counter = Counter()
x: int = c()   # x = 1
y: int = c()   # y = 2

下标访问重载

__getitem__ — 读取

def __getitem__(self, key: int) -> int:
    return self.data[key]

__setitem__ — 赋值

def __setitem__(self, key: int, value: int):
    self.data[key] = value

__delitem__ — 删除

def __delitem__(self, key: int):
    pass

布尔转换 __bool__

对象类定义了 __bool__ 时,条件位置自动调度(两端已调度):if/elif/while 条件、and/or/not 操作数、三元表达式条件。

class Buffer:
    size: int
    data: [1024]char

    def __bool__(self) -> bool:
        return self.size > 0

buf: Buffer = Buffer()
if buf:
    serial.puts("buffer is not empty\n")

长度 __len__

class Buffer:
    size: int

    def __len__(self) -> int:
        return self.size

buf: Buffer = Buffer()
n: int = len(buf)

字符串转换 __str__

对象类定义了 __str__ 时,str(obj)、print(obj) 与 f-string(f"{obj}",未指定格式说明符)自动调度该方法,取其返回的字符串(const char*)输出(两端已调度)。

class Point:
    x: int
    y: int

    def __str__(self) -> const char*:
        return "Point"

p: Point = Point(1, 2)
print(p)          # 调用 p.__str__() → 输出 "Point"

绝对值 __abs__

对象类定义了 __abs__ 时,abs(obj) 自动调度该方法(两端已调度);基础类型仍走内建/C 库 abs(labs),见 11-builtins.md。

class SignedValue:
    val: int

    def __abs__(self) -> int:
        if self.val < 0:
            return -self.val
        return self.val

sv: SignedValue = SignedValue()
sv.val = -42
a: int = abs(sv)   # a = 42

迭代器协议

Viper 的迭代器协议与 Python 相同。__next__ 带编译器注入的隐藏 i1* 参数 __stop_iter_flag__:方法内 raise StopIteration 会将该参数置位并返回默认值以结束迭代。

__iter__ 和 __next__

class IntRange:
    start: int
    end: int
    current: int

    def __init__(self, start: int, end: int):
        self.start = start
        self.end = end
        self.current = start

    def __iter__(self):
        return self

    def __next__(self, __stop_iter_flag__) -> int:  # 编译器注入的隐藏 i1* 参数
        if self.current >= self.end:
            raise StopIteration
        val: int = self.current
        self.current += 1
        return val

for 循环使用

r: IntRange = IntRange(0, 10)
for i in r:
    print(i)

编译器生成的等价逻辑:

IntRange r = IntRange_init(0, 10);
IntRange iter = IntRange___iter__(&r);
while (1) {
    i1 __stop_iter_flag__ = 0;   /* 编译器注入的隐藏 i1* 参数 */
    int i = IntRange___next__(&iter, &__stop_iter_flag__);
    if (__stop_iter_flag__ == 1) break;
    print_int(i);
}

上下文管理器

with 语句要求对象实现 __enter__ 和 __exit__ 方法:

class File:
    fd: int
    path: const char*

    def __init__(self, path: const char*, flags: int):
        self.path = path
        self.fd = -1

    def __enter__(self):
        self.fd = fat32.open(self.path, self.flags)
        return self

    def __exit__(self):
        fat32.close(self.fd)

    def read(self) -> int:
        return fat32.read(self.fd)

使用方式:

with File("/test.txt", FA_READ) as f:
    data: int = f.read()

编译器会自动保证 __exit__ 在 with 块结束时被调用。

析构 __del__ / __delete__

del 的目标形态决定调度的 dunder(两端一致):

语句 调度
del obj obj.__delete__()(类未定义则静默无操作)
del obj.attr property deleter(@attr.deleter);无 deleter 时回退属性值对象的 __del__()
del obj[key] obj.__delitem__(key)
del obj        # 调用 obj.__delete__()
del arr[idx]   # 调用 arr.__delitem__(idx)

isinstance

isinstance(obj, Cls) 不是关键字,而是编译器在调用点按函数名识别的内建(返回 i1)。

if isinstance(obj, Base):
    ...

if isinstance(obj, (A, B)):     # 元组:任一命中即为真
    ...

语义:

  • virtual 类(带 vtable):运行时读对象头部 vtable 指针,与「目标类及其全部已知子类的 vtable 地址集合」逐一比较,相等即真 ⇒ 正确覆盖多态子类(这也是运行期唯一能拿到实际类的途径);
  • novirtual 类 / 未知类(无 vtable):回退编译期静态 MRO 判定(据 obj 的静态类型)——可能保守判假。

第二参数支持:裸类名 / 跨模块 mod.Cls(只取短名)/ 元组 (A, B)。不支持 REnum 变体、t.CEnum 等。

限制:已知子类集合上限 64、元组上限 15;Viper 侧类型推断失败即 fail-fast(TypeError: isinstance() 参数类型推断失败)。

注意:胖节点 AST 的节点分派用的是虚方法 kind()(返回 ASTKind),不是 isinstance;文档中提到的 vtype 字段目前不存在(属迁移规划)。

FakeDuck(伪鸭子类型)

FakeDuck 让内建类型 str(LLVM 层就是 i8*)也能像对象一样调用方法、读写字段——通过扩展类实现,不是关键字 / 装饰器 / 基类。

启用方式(命名约定 + import)

  • 扩展类必须命名为 _str(字符串扩展方法)或 _Type(通用基类),定义在被 import 的模块中;
  • 使用者 import _fakeduck(提供 _str / _Type);with 自动注入还需 import _withcontent。

内置扩展类见 includes/_fakeduck.vp:_Type.type_id();_str 提供 upper / lower / capitalize / swapcase / title / casefold / isupper / islower / isalpha / isdigit / isalnum / isspace / isascii / istitle / split 等。

扩展方法调用

import _fakeduck

a: str = "Hello"
tid: int = a.type_id()      # 解析到扩展类 _Type.type_id
u: str = a.upper()          # 解析到扩展类 _str.upper

分派是回退:先走普通结构体方法,全部落空后才尝试 FakeDuck;接收者注解是 list[...] 时跳过。方法名在 _Type / _str 中查找。

影子字段与 with 自动注入

编译期为每个裸 str 变量额外开一个影子结构体 <变量名>__meta__,用来存 per-instance 字段(__data__、__mbuddy__):

a.__mbuddy__ = bd           # 语法糖,等价 a.set_mbuddy(bd)
d: str = a.__data__         # 读影子字段

with 上下文可自动注入字段:提供方类用类体注解 __provides__ = ['字段名'] 声明,消费方扩展类用 __requires__ = ['字段名'] 声明:

with memhub.MemBuddy(arena, 65536) as bd:
    s: str = "WithTest"     # __mbuddy__ 自动注入,无需手动赋值
    u2: str = s.upper()

另有 __require_must__:表示该字段必须由某个外层 with 提供,否则编译期 fail-fast。

限制

  • 影子结构体只对裸 str 注解创建(bytes / char* 不创建);_bytes 扩展类未实现。
  • len() / 下标 [] / for 迭代等不走 FakeDuck,而是 list[T] 的 dunder / 内建分派。
  • with 注入依赖运行时 provider 栈(includes/_withcontent.vp),未 import _withcontent 时跳过注入。

真实用例:Test/FakeDuckTest。

Dunder 方法完整参考

已实现自动调度的 Dunder 方法

Dunder 方法 触发语法 说明
__init__ ClassName(args) 构造函数
__before_init__ 自动生成 填充成员默认值并初始化 vtable(类内含方法或继承虚方法时才生成),在 __init__ 之前执行
__add__ a + b 加法
__sub__ a - b 减法
__mul__ a * b 乘法
__truediv__ a / b 真除法
__floordiv__ a // b 整除
__mod__ a % b 取模
__and__ a & b 按位与
__or__ a | b 按位或
__xor__ a ^ b 按位异或
__lshift__ a << b 左移
__rshift__ a >> b 右移
__eq__ a == b 等于(未定义 __eq__ 时默认身份比较)
__ne__ a != b 不等于
__lt__ a < b 小于
__le__ a <= b 小于等于
__gt__ a > b 大于
__ge__ a >= b 大于等于
__neg__ -a 一元负号
__pos__ +a 一元正号
__invert__ ~a 按位取反
__getitem__ obj[key] 下标读取
__setitem__ obj[key] = value 下标赋值
__delitem__ del obj[key] 下标删除
__len__ len(obj) 长度
__iter__ for x in obj: 获取迭代器
__next__ for x in obj: 取下一个值(隐藏 i1* 参数 __stop_iter_flag__,raise StopIteration 置位后返回默认值结束迭代)
__enter__ with obj as x: 上下文管理器进入
__exit__ with obj as x: 上下文管理器退出

声明支持但未实现自动调度的 Dunder 方法

Dunder 方法 预期触发语法 当前状态
__pow__ a ** b 期望实现:binop ** 未调度(基础类型 ** 编译失败;自定义类型走 __pow__ 重载亦属期望)
__iadd__ a += b 期望实现:AugAssign 一律按原生运算符展开(+=→add、//=→sdiv …),不调用 __iadd__,也无 __add__ 回退
__isub__ a -= b 同上
__imul__ a *= b 同上
__itruediv__ a /= b 同上
__ifloordiv__ a //= b 同上
__imod__ a %= b 同上
__ipow__ a **= b 同上
__str__ str(obj) / print(obj) 期望实现:print 为类型感知格式化(str/%s、int、float、struct 输出占位符),不调度 __str__
__call__ obj(args) 期望实现:当前未调度
__bool__ if obj: 期望实现:当前未调度
__abs__ abs(obj) 期望实现:当前未调度
__del__ del obj 期望实现:当前未调度
__delete__ del obj 期望实现:当前未调度
__radd__ 右操作数加法 尚未调度
__rsub__ 右操作数减法 尚未调度
__rmul__ 右操作数乘法 尚未调度
__rtruediv__ 右操作数真除法 尚未调度
__rfloordiv__ 右操作数整除 尚未调度
__rmod__ 右操作数取模 尚未调度
__rpow__ 右操作数幂运算 尚未调度