首页 > 其他分享 >Typing模块

Typing模块

时间:2024-08-27 22:16:07浏览次数:5  
标签:return name self 模块 str Typing print def

typing模块学习

Dict, Tuple, List, Optional, Union

新版本的python中,不用在使用typing模块中的Dict Tuple, List等对象了,直接使用原生的类型去做类型提示。

Optional, Union等都可以使用管道提示符来代替。 例如Optional[str] 相当于 str|None

使用mypy xxx.py命令来检查变量类型的使用是否符合声明的类型提示符

自定义class

自定义class,类型提示为基类时可传递子类

class Animal:
    name: str
    def speak(self) -> str:
        return "Some sound"

class Dog(Animal):
    def speak(self) -> str:
        return "Woof"

class Cat(Animal):
    def speak(self) -> str:
        return "Meow"

def talk_animal(animal_class: Animal) -> None:
    print(animal_class.speak())

talk_animal(Dog()) # 函数参数为基类,传子类ok

def talk_cat(animal_class: Cat) -> None:
    print(animal_class.speak())

talk_cat(Dog()) # 函数参数为一个子类,传另一个子类,类型提示会报错

def talk_dog(animal_class: Dog) -> None:
    print(animal_class.speak())

talk_dog(Animal()) # 函数参数为子类,传父类,类型提示会报错

Type

用法, 用于表示类对象的类型提示

from typing import Type
class Animal:
    def speak(self) -> str:
        return "Some sound"

class Dog(Animal):
    def speak(self) -> str:
        return "Woof"

class Cat(Animal):
    def speak(self) -> str:
        return "Meow"

# 这个函数接受一个 Animal 类或其子类的类型,并返回一个实例
def create_animal(animal_class: Type[Animal]) -> Animal:
    return animal_class()

dog = create_animal(Dog)
print(dog.speak())

Any

代表任何类型,等同于无类型提示

from typing import Any
# 但即便是等同于无类型提示,显示的提示总比没有提示要好
def process_data(data: Any) -> Any:
    if isinstance(data, str):
        return data.upper()
    elif isinstance(data, int):
        return data * 2
    else:
        return data

# Any可以用在其它容器类型中做类型提示
def get_first_element(data: list[Any]) -> Any:
    if data:
        return data[0]
    else:
        return None

Sequence

Sequence 是 Python typing 模块中的一个抽象基类,用于表示支持序列操作的类型。这包括所有的列表、元组、字符串等。这种抽象类型允许你编写更通用的代码,可以接受任何符合序列协议的对象,而不仅仅是特定的容器类型。

from typing import Sequence

def concatenate(elements: Sequence[str]) -> str:
    return ''.join(elements)

# 使用列表
print(concatenate(['a', 'b', 'c']))  # 输出: abc

# 使用元组
print(concatenate(('x', 'y', 'z')))  # 输出: xyz

Literal

Literal 是 Python typing 模块中的一个工具,用于指定特定的常量值。它允许你在类型提示中明确地指定某些值,从而增加代码的类型安全性和可读性。Literal 常用于函数参数、返回值和变量的类型注解中,以确保这些值只能是某些预定义的常量。

from typing import Literal

def set_mode(mode: Literal['auto', 'manual', 'off']) -> None:
    print(f'{mode} mode has been set.')

set_mode('off')
set_mode('auto')

# 下面这行代码在类型检查时会报错,因为 "on" 不是允许的值
# set_mode("on")
from typing import Literal

def process_items(items: list[Literal['apple', 'banana', 'cherry']]) -> None:
    for item in items:
        print(item)

process_items(['apple', 'cherry', 'banana'])

# 下面这行代码在类型检查时会报错,因为 "orange" 不是允许的值
# process_items(["apple", "orange"])

Callable

Callable用于类型提示中表示可调用对象(例如函数、方法或实现了__call__方法的对象)

简单函数
from typing import Callable

# 定义一个接受函数作为参数的函数
def apply_function(func: Callable[[int, int], int], x: int, y: int) -> int:
    return func(x, y)

# 定义符合类型提示的函数
def add(a: int, b: int) -> int:
    return a + b

def multiply(a: int, b: int) -> int:
    return a * b

# 调用 apply_function
print(apply_function(add, 2, 3))  # 输出: 5
print(apply_function(multiply, 2, 3))  # 输出: 6

带有任意参数的函数
from typing import Callable

# 定义一个接受带任意参数的函数
def call_with_args(func: Callable[..., int], *args, **kwargs) -> int:
    return func(*args, **kwargs)

# 定义一些不同的函数
def sum_all(*args: int) -> int:
    return sum(args)

def product_all(*args: int) -> int:
    result = 1
    for num in args:
        result *= num
    return result

# 调用 call_with_args
print(call_with_args(sum_all, 1, 2, 3, 4, 5))  # 输出: 15
print(call_with_args(product_all, 1, 2, 3, 4, 5))  # 输出: 120

类中的可调用对象

可以使用Callable来表示类中实现了__call__方法的对象:

使用class去实例化一个对象时,并不会触发__call__方法。实例化后的对象名加括号才会调用__call__方法

from typing import Callable

class Greeter:
    def __call__(self, name: str) -> str:
        return f"Hello, {name}!"

def greet(greeter: Callable[[str], str], name: str) -> str:
    return greeter(name)

# 创建 Greeter 实例
greeter = Greeter()

# 调用 greet 函数
print(greet(greeter, "Alice"))  # 输出: Hello, Alice!

NewType

用于创建简单的类型别名。它允许你定义一个新的类型,它在运行时与原始类型相同,但在类型检查时被视为不同的类型。

复杂的组合的类型提示

复杂的类型可以赋值给一个变量,相当于一个类型的别名

from typing import Literal

# 相当于用一个变量来代替一个复杂的类型
my_type = dict[str, list[Literal['apple','banana','cherry','orange','pair','tomato', 'liulian']]]

def print_dict(dic: my_type) -> None:
    for k, v in dic.items():
        print(k, v)

real_dic: my_type = {'roland': ['cherry', 'orange'], 'harry': ['banana', 'liulian'], 'cong': ['tomato', 'liulian']}

print_dict(real_dic)
类型别名的问题

不加类型控制,id和name传错时不会有任何提示

class Student:
    def __init__(self, id: str, name: str):
        self.user_id: str = id
        self.user_name: str = name

id: str = 'A0001'  # 这个是名字,却传给了id
name: str = 'harry'

stu = Student(name, id)
print(stu.user_id, stu.user_name)

直接将类型赋值给变量,则会将变量和相关的类型视为完全等价

uid = str
uname = str
class Student:
    def __init__(self, id: uid, name: uname):
        self.user_id: uid = id
        self.user_name: uname = name

id: uid = 'harry'
name: uname = 'A0001'

# name已经声明为uname类型了,但是传参时还是放在了应该为uid的位置,但mypy并不会提示错误。 因为现在uid, uname, str都是等价的了
stu = Student(name, id)
print(stu.user_id, stu.user_name)
# 直接传常量值并不会报错
stu = Student('harry', 'A0001')
print(stu.user_id, stu.user_name)
NewType 用法

为了显示区分同种类型,比如str,使用NewType

from typing import NewType

# uid和uname会被视为各自不同的新类型,且与str也完全不同
uid = NewType('uid', str)
uname = NewType('uname', str)

class Student:
    def __init__(self, id: uid, name: uname):
        self.user_id: uid = id
        self.user_name: uname = name

id: uid = uid('A0001')
name: uname = uname('harry')

# 这时参数传错,mypy就会提示错误
stu = Student(name, id)
print(stu.user_id, stu.user_name)

# 传常量值时mypy也会提示错误,因为mypy认为uid, uname, str是各不相同的类型
stu = Student('harry', 'A0001')
print(stu.user_id, stu.user_name)

# 若需要传常量, 则应使用如下写法,这样mypy不会提示类型错误
stu = Student(uid('A0001'), uname('harry'))
print(stu.user_id, stu.user_name)

泛型

泛型允许你定义数据类型的参数化类或函数,以提高代码的复用性和类型安全性。

泛型函数
from typing import TypeVar

T = TypeVar('T', int, str)
# T = TypeVar('T')  不对类型变量进行约束的话,mypy会对下面函数的定义有错误提示 error: Unsupported left operand type for + ("T")  [operator]

def a_plus_b(a: T, b: T) -> T:
    return a + b

ret = a_plus_b(1,2)
print(ret)

ret2 = a_plus_b('1','2')
print(ret)

def first_element(lst: list[T]) -> T:
    return lst[0]

# 调用泛型函数
print(first_element([1, 2, 3]))  # 输出: 1
print(first_element(["a", "b", "c"]))  # 输出: a
泛型类
from typing import TypeVar, Generic

# 定义一个类型变量T
T = TypeVar('T')

class Box(Generic[T]):
    def __init__(self, first_element: T, second_element: T):
        self.first_element = first_element
        self.second_element = second_element

    def get_first(self) -> T:
        return self.first_element

print(Box(1,2).get_first())

print(Box(1,'2').get_first())  # mypy虽然没提示有问题,但是pycharm编辑器却提示了问题

多个类型变量的用法

from typing import TypeVar, Generic

# 定义两个类型变量T和U
T = TypeVar('T')
U = TypeVar('U')

# 定义一个泛型类
class Pair(Generic[T, U]):
    def __init__(self, first: T, second: U):
        self.first = first
        self.second = second

    def get_first(self) -> T:
        return self.first

    def get_second(self) -> U:
        return self.second

# 创建Pair的实例
pair = Pair(123, "hello")

# 调用方法
print(pair.get_first())  # 输出: 123
print(pair.get_second())  # 输出: hello

Annotated

未完待续

标签:return,name,self,模块,str,Typing,print,def
From: https://www.cnblogs.com/rolandhe/p/18383650

相关文章

  • js 封装日志上传模块,实现异常日志的上报
    封装定义日志上传模块,实现异常日志的上报,包含触发方式:1、主动调取方法上报2、覆盖原生console.error实现,收集所有console.error打印的日志3、window注册绑定error事件,触发 window.addEventListener('error',/***客户端日志上传模块,实现异常日志的上报*使用时在HTML......
  • Ansible `iptables` 模块
    Ansibleiptables模块一、简介功能:iptables模块用于管理Linux系统上的防火墙规则。通过这个模块,可以添加、删除和修改iptables规则,以控制进出系统的网络流量。使用场景:适用于需要管理防火墙规则的场景,如限制特定端口的访问、允许特定IP的连接、配置NAT等。二、......
  • Ansible `replace` 模块
    Ansiblereplace模块一、简介功能:replace模块用于在远程主机上的文件中替换匹配的文本。它通过正则表达式查找文件中的特定模式,并将其替换为指定的内容。这对于修改配置文件、脚本或其他需要批量文本替换的场景非常有用。使用场景:适用于需要精确匹配和替换文件内容的情......
  • Ansible `firewalld` 模块
    Ansiblefirewalld模块一、简介功能:firewalld模块用于管理Linux系统上的firewalld防火墙服务。firewalld是一种动态管理防火墙的工具,它提供了对网络流量的更细粒度控制,支持区域(zones)和丰富的规则管理。使用场景:适用于需要动态管理防火墙规则的场景,如开放或关闭特定......
  • Python中configparser模块的基本用法
    configparser是Python标准库中的一个模块,用于处理配置文件。配置文件通常用于存储应用程序的配置信息,如数据库连接参数、日志级别设置等。configparser模块支持读取、写入和修改配置文件,这些文件通常采用类似INI格式的结构。配置文件格式配置文件一般以'.ini'作为扩展名......
  • 【python3.8安装报错】lmportError: DLL load failed while importing ft2font: 找不
    客户需求背景:安装python3.8无法运行,报错lmportError:DLLloadfailedwhileimportingft2font:找不到指定的模块 考虑兼容性问题这个问题首先需要考虑的是是否是python版本太高了,因为python3.9不支持win7,而python3.8版本对win7的兼容性也有一定的限制。解决:首先考......
  • 【Node】【6】模块系统
    Node.js的模块系统基于CommonJS规范,其中每个文件被视为一个独立的模块,可以通过require函数引入其他模块,也可以通过module.exports将模块的功能暴露给外部。CommonJS规范:使用require()函数来导入模块,使用module.exports或exports对象来导出模块。ESModules:使用i......
  • Node.Js基础——安装及模块
    一、什么是Node.Js?Node.js是一个开源和跨平台的JavaScript运行时环境。它让JavaScript可以脱离浏览器端,在服务器端运行,让javaScript可以开发后端程序,实现了大部分其他后端语言的功能。 Node.js建立在GoogleChromeV8JavaScript引擎之上,主要用于创建网络服务器-但......
  • 前端模块自动导入的插件
    前言开发中通常会有很多导入语句,如何确保一些通用的api和hook无需每次手动导入即可使用。<scriptsetuplang="ts">import{ref,reactive}from"vue"import{useRoute,useRouter}from"vue-router"import{login}from"./api/user"constcount=r......
  • 蓝桥杯单片机入门(6)—LED灯模块
    这回我们讲,蓝桥杯中LED模块1.点亮一颗LED灯    在写代码之前我们必须要先明确自己的目的,然后根据需求去写对应的代码功能。首先我们要实现点亮一颗LED灯,在此之前我们要先了解一下LED灯的工作原理,    首先我们看一下,LED灯的原理图,图中写LED1的地方就是LED灯,......