Python参数注解

函数定义的弊端

  • Python 是动态语言,变量随时可以被赋值,且能赋值为不同的类型
  • Python 不是静态编译型语言,变量类型是在运行期决定的
  • 动态语言很灵活,但是这种特性也是弊端
def add(x,y):
    return x + y
print(add(4,5))
print(add('hello','world'))
print(add(4,'hello')) 运行错误
  • 难发现:由于不做任何类型检查,直到运行期问题才显现出来,或者线上运行时才能暴露出问题
  • 难使用:函数的使用者看到函数的时候,并不知道你的函数的设计,并不知道应该传入什么类型的参数

  • 如何解决这种动态语言定义的弊端呢?
    • 增加文档 Documentation String
      • 这只是一个惯例,不是强制标准,不能要求程序员一定为函数提供说明文档
      • 函数定义更新了,文档未必同步更新
def add(x,y):
    '''
    :param x: int
    :param y: int
    :return: int
    '''
    return x + y
print(hlep(add))

函数注解 Function Annotations

  • 如何解决这种动态语言定义的弊端呢?
    • 函数注解
def add(x:int,y:int)->int:
    '''
    :param x: int
    :param y: int
    :return: int
    '''
    return x + y
print(help(add))
print(add(4,5))
print(add('mag','edu'))
  • 函数注解
    • Pyhton 3.5 引入
    • 对函数的参数进行类型注解
    • 对函数的返回值进行类型注解
    • 只对函数参数做一个辅助的说明,并不对函数参数进行类型检查
    • 提供给第三方工具,做代码分析,发现隐藏的BUG
    • 函数注解的信息,保存在__annotations__属性中
      在这里插入图片描述
  • 变量注解
    • Python 3.6 引入。注意它也只是一种对变量的说明,非强制 i : int = 3

业务应用

  • 函数参数类型检查
  • 思路
    • 函数参数的检查,一定是在函数外,如要把检查代码侵入到函数中,
    • 函数应该作为参数,传入到检查函数中
    • 检查函数拿到函数传入的实际参数,与形参声明对比
    • __annotations__属性是一个字典,其中包括返回值类型的声明。假设要做位置参数的判断,无法和字典中的声明对应。使用 inspect模块
  • inspect模块
    • 提供获取对象信息的函数,可以检查函数和类、类型检查

  • 有函数如下
def add(x:int,y:int)->int:
    reutrn x + y
  • 请检查用户输入是否符合参数注解的要求,符合的话就执行
import inspect

def check(fn):
    sig = inspect.signature(fn)
    param = sig.parameters
    def wrapper(*args,**kwargs):
        for x,(k,v) in zip(args,param.items()):
            if not isinstance(x,v.annotation) and v.annotation != inspect._empty:
                print('Wrong')
                break
        for k,v in kwargs.items():
            if not isinstance(v,param[k].annotation) and param[k].annotation != inspect._empty:
                print('Wrong')
                break
        ret = fn(*args,**kwargs)
        return ret
    return wrapper 

@check
def add(x:int,y:int):
    return x + y

print(add(4,5))

inspect 模块

  • signature(callable),获取签名(函数签名包含了一个函数的信息,包括函数名、它的函数类型、它所在的类和名称空间及其他信息)
import inspect
def add(x:int,y:int,*args,**kwargs)->int:
    return x + y 
sig = inspect.signature(add)
print(sig,type(sig))
print('params:',sig.parameters)
print('return:',sig.return_annotation)
print(sig.paramrters['y'],type(sig.parameters['y']))
print(sig.paramrters['x'].annotation)
print(sig.parameters['args'])
print(sig.parameters['args'].annotation)
print(sig.parameters['kwargs'])
print(sig.parameters['kwargs'].annotation)
  • inspect.isfunction(add),是否是函数
  • inspect.ismethod(add),是否是类的方法
  • inspect.isgeneratorfunction(add),是否是生成器函数
  • inspect.isclass(add),是否是类
  • inspect.ismodule(inspect),是否是模块
  • inspect.isbuiltin(print),是否是内建对象
  • 还有很多is函数,需要的时候查阅 inspect模块帮助

  • Parameter对象
    • 保存在元组中,是只读的
    • name,参数的名字
    • annotation,参数的注解,可能没有定义
    • default,参数的缺省值,可能没有定义
    • empty,特殊的类,用来标记default属性或者注释annotation属性的空值
    • kind,实参如何绑定到形参,就是形参的类型
      • POSITIONAL_ONLY,值必须是位置参数提供
      • POSITIONAL_OR_KEYWORD,值可以作为关键字或者位置参数提供
      • VAR_POSITIONAL,可变位置参数,对应*args
      • KEYWORD_ONLY,keyword-only参数,对应*或者 *args之后出现的非可变关键字参数
      • VAR_KEYWORD,可变关键字参数,对应**kwargs

  • 举例
import inspect

def add(x,y:int=7,*args,z,t=10,**kwargs)->int:
    return x + y

sig = inspect.signature(add)
print(sig)
print('params:',sig.parameters)
print('return:',sig.return_annotation)
print('~~~~~~~~~~')
for i,item in enumerate(sig.parameters.items()):
    name, param = item
    print(i+1, name, param.annotation, param.kind, param.default)
    print(param.default is param.empty,end='\n\n')
参数注解(Parameter Annotations)是 Python 3.0+ 引入的一项语法特性,用于为函数的参数和返回值添加**类型提示(Type Hints)**。它本身不会影响程序的运行,也不会进行类型检查,但可以被第三方工具(如 `mypy`、IDE、编辑器等)用来进行静态类型分析,提高代码可读性和可维护性。 --- ### ✅ 参数注解的基本语法: ```python def func(param: type) -> return_type: pass ``` - `param: type` 表示参数 `param` 的预期类型。 - `-> return_type` 表示函数的返回值类型。 --- ### 🧪 示例代码: ```python from typing import List, Dict, Optional, Union def greet(name: str) -> str: return f"Hello, {name}" def add_numbers(a: int, b: int) -> int: return a + b def process_items(items: List[str]) -> None: for item in items: print(item.upper()) def get_user_info(user_id: int) -> Optional[Dict[str, Union[str, int]]]: if user_id == 1: return {"name": "Alice", "age": 30} else: return None # 调用示例 print(greet("Bob")) process_items(["apple", "banana"]) print(get_user_info(1)) ``` --- ### 🔍 常见类型注解说明: | 类型 | 说明 | |------|------| | `int`, `str`, `float`, `bool` | 基本数据类型 | | `List[str]` | 字符串列表(需导入 `from typing import List`) | | `Dict[str, int]` | 键为 str,值为 int 的字典 | | `Optional[str]` | 等价于 `Union[str, None]`,表示可为 None | | `Union[int, str]` | 可以是整数或字符串 | | `Tuple[int, str]` | 固定长度元组 | | `Any` | 任意类型(不推荐,会失去类型检查意义) | > ⚠️ 注意:从 Python 3.9 开始,部分内置类型已支持泛型,例如可以直接使用 `list[str]` 而无需 `List[str]`(但仍需兼容旧版本时建议使用 `typing` 模块)。 --- ### 💡 参数注解的作用: 1. **增强代码可读性**:别人一看就知道函数需要什么类型的参数。 2. **支持静态类型检查**:配合 `mypy` 工具可以在运行前发现类型错误。 3. **IDE 智能提示**:PyCharm、VS Code 等能根据注解提供自动补全和错误提示。 4. **文档作用**:相当于一种结构化的注释。 --- ### ❗ 注意事项: - 参数注解**不会强制类型检查**,以下代码依然可以运行(但逻辑可能出错): ```python def add(a: int, b: int) -> int: return a + b add("hello", "world") # 不会报错,但逻辑错误 ``` 要真正实现类型检查,需使用 `mypy` 等工具: ```bash pip install mypy mypy your_script.py ``` --- ### ✅ 使用 `__annotations__` 查看注解: ```python def example(x: float, y: str) -> bool: return True print(example.__annotations__) # 输出: {'x': <class 'float'>, 'y': <class 'str'>, 'return': <class 'bool'>} ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值