使用类型提示进行类型转换

1 投票
1 回答
36 浏览
提问于 2025-04-13 16:38

假设我有一个函数,它需要做一些内部处理,并显示提供的文本:

def display_text(text: str):
  ...
  print(text)

还有一个类里面有一个叫 convert() 的方法:

class String:
  def __init__(self, string: str):
    self.string = string
  
  def convert(self):
    return self.string

现在,你能不能在 display_text 函数的 text 参数上加上类型提示,说明它应该是 String 类型?但是如果传入的参数是 str 类型,就调用 convert 方法,并把返回的值赋给 text?像这样:

def display_text(text: String):
  ...
  print(text)

这个操作应该在 display_text 函数里不需要额外的代码,只用类型提示就可以。我在一些库里见过这种用法,但我还是搞不明白它是怎么工作的。

我试着查了一些库的代码(比如 discord.py 的转换器),也在 StackOverflow 上找了类似的问题,只发现了 typing.Protocol,但还是不明白这个转换是怎么实现的。

1 个回答

1

你能在 display_text 函数中给 text 参数加上 String 的类型提示吗?但是如果传入的参数是 str,就调用 convert 函数,并把返回的值赋给 text,而不需要在 display_text 函数里写其他代码,只用类型提示来实现。

不行,单靠类型提示是做不到的,因为类型注解在程序运行时是完全无效的,根本不会起作用(而且如果使用了 from __future__ import annotations,它们甚至不会被计算)。如果这是个技巧性的问题,而“在 display_text 函数里”是关键点,那么你可以通过装饰器来处理你的函数(或者装饰一个包含这些函数的类,或者使用一个元类),这样就可以在需要的时候用类型注解来转换参数。

下面是一个这样的装饰器的例子:

import dataclasses
import inspect
from functools import wraps
from typing import Any


def convert_args(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        sig = inspect.signature(fn)
        bound_args = sig.bind(*args, **kwargs)
        bound_args.apply_defaults()
        for name, val in bound_args.arguments.items():
            param = sig.parameters[name]
            if hasattr(param.annotation, "convert"):
                bound_args.arguments[name] = param.annotation.convert(val)
        return fn(*bound_args.args, **bound_args.kwargs)

    return wrapper


@dataclasses.dataclass
class Shouty:
    val: str

    @classmethod
    def convert(cls, val: Any):
        return Shouty(val=str(val).upper())


@dataclasses.dataclass
class Shorten:
    val: str

    @classmethod
    def convert(cls, val: Any):
        return Shorten(val=str(val)[::2])


@convert_args
def display_text(arg1: Shouty, arg2: Shorten):
    print(locals())


display_text("hello", "world, this is an example")

这段代码的输出是:

{'arg1': Shouty(val='HELLO'), 'arg2': Shorten(val='wrd hsi neape')}

撰写回答