Python学习之-typing详解

前言:

Python的typing模块自Python 3.5开始引入,提供了类型系统的扩展,能够帮助程序员定义变量、函数的参数和返回值类型等。这使得代码更易于理解和检查,也方便了IDE和一些工具进行类型检查,提升了代码的质量。

typing 模块概述

typing 模块是 Python 标准库中用于支持类型提示的模块。它提供了一系列的类型和类型相关的工具,帮助开发者在代码中添加类型提示,以提高代码的可读性和可靠性。

1 类型提示的基本使用

1.1 变量类型注解:

age: int = 25
name: str = "Alice"

1.2函数参数和返回值类型注解:

def greet(name: str) -> str:
    return "Hello, " + name

1.3列表、字典等复杂类型注解:

from typing import List, Dict

numbers: List[int] = [1, 2, 3]
user_info: Dict[str, str] = {"name": "Alice", "age": "25"}

2 常见的typing模块类型

List[T],Set[T],Dict[K, V]等:用于注解容器类型,T、K、V分别代表容器内元素类型,字典的键和值类型。

2.1 Tuple[T, …]:用于定长元组。

from typing import Tuple

coordinate: Tuple[int, int, int] = (10, 20, 30)

2.2 Optional[T]:用于表示某个类型或None。

from typing import Optional

def get_age(name: str) -> Optional[int]:
    if name == "Alice":
        return 25
    return None

2.3 Union[T, U, …]:当一个参数可能是多种类型之一时使用。

from typing import Union

def log_message(message: Union[str, int]) -> None:
    print(message)

2.4 Callable[[Arg1Type, Arg2Type], ReturnType]:用于表示可调用对象(如函数)的类型签名。

from typing import Callable

def add(a: int, b: int) -> int:
    return a + b

calculator: Callable[[int, int], int] = add

3 Type Hints的高级应用

3.1 泛型:在定义类或函数时,允许使用类型参数。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/17
# @Author  : Summer
# @File    :
# @describe:
"""
from typing import TypeVar, Generic, List

T = TypeVar('T')


class Stack(Generic[T]):
    def __init__(self) -> None:
        self._container: List[T] = []

    def push(self, item: T) -> None:
        self._container.append(item)

    def pop(self) -> T:
        return self._container.pop()


stack = Stack[int]()
stack.push(1)
print(stack.pop())  # 输出1

上述代码的解析:首先从typing模块导入TypeVar、Generic和List。这些是实现自定义泛型类型的核心组件。
T = TypeVar(‘T’):使用TypeVar创建一个类型变量T。这个变量将用于表示Stack类可以接受的元素的类型。TypeVar是定义泛型类和函数时的占位符,表示可以是任意类型。
class Stack(Generic[T]):定义了一个名为Stack的类,这个类是泛型的,可以存储类型为T的元素。这里的T是在之前用TypeVar定义的类型变量。Generic[T]表示Stack是一个泛型类,它的行为可以基于不同的类型T进行参数化。
在__init__方法中,初始化了一个名为_container的列表,这个列表是用于存储栈中元素的容器。List[T]表示_container是一个列表,其中可以存储任意类型为T的元素。
stack = Stackint创建了一个Stack的实例stack,指定T为int类型。这意味着这个stack实例是一个整型的栈,只能存储整数。
通过push方法向栈中压入一个整数1。
通过pop方法从栈中弹出最后一个元素,也就是之前压入的整数1。
这段代码展示了如何使用Python的typing模块创建泛型数据结构,使得这个数据结构变得更加通用和灵活。它可以在保持类型安全的同时,被用于存储任何指定类型的数据。

3.2 NewType:

用于定义新类型,以帮助区分具有相同基础类型但应用场景不同的场合。

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/17
# @Author  : Summer
# @File    :
# @describe:
"""
from typing import NewType

UserId = NewType('UserId', int)


def get_user_name(user_id: UserId) -> str:
    return "User#" + str(user_id)

user_id = UserId(524313)
print(get_user_name(user_id))  # User#524313

user_id = UserId(524313):使用UserId类型创建一个新的用户ID实例。注意,尽管UserId是基于int的一个新类型,但是这一步看起来和直接对整数进行类型转换(如int(x))相似。然而,UserId(524313)在类型检查时被视为一个与int不同的独立类型。
print(get_user_name(user_id))调用get_user_name函数,并传入之前创建的user_id。然后打印函数的返回值,预期输出为"User#524313"。

4 类型检查工具

typing 模块还提供了一些用于类型检查的工具,如 isinstance()、issubclass() 等。

from typing import List


def is_valid_input(data: List) -> bool:
    return isinstance(data, List)


print(is_valid_input(data=1))  # False
print(is_valid_input(data=[1, 2, 3]))  # True

5 结构化类型和协议

Python 的 typing 模块还支持结构化类型和协议,用于表示对象的形状或接口。可以使用 Protocol 类来定义一个协议,并在参数类型注解中使用。
举个例子,如果我们想定义一个Writable的协议,所有满足这个协议的对象都应该有一个write方法。这里是如何使用Protocol来做这件事的:

#!/usr/bin/env python
# coding=utf-8
"""
# @Time    : 2024/4/17
# @Author  : Summer
# @File    :
# @describe:
"""
from typing import Protocol

class Writable(Protocol):
    def write(self, data: str) -> int:
        ...

# 实现了 Writable 接口的类
class FileWriter:
    def write(self, data: str) -> int:
        print(f"Writing {data} to file.")
        return len(data)  # 假设返回写入的字节数

# 实现了 Writable 接口的类
class StringWriter:
    def write(self, data: str) -> int:
        print(f"Writing {data} to string buffer.")
        return len(data)  # 假设返回写入的字节数


# 函数接受任何实现了Writable接口的对象
def write_data(writer: Writable, data: str):
    num_bytes_written = writer.write(data)
    print(f"Wrote {num_bytes_written} bytes.")
    return

# FileWriter和StringWriter没有从Writable显式继承,但它们实现了Writable协议
file_writer = FileWriter()
string_writer = StringWriter()

# 可以传递给write_data函数,因为它们符合Writable协议
write_data(file_writer, "Hello, World!")
write_data(string_writer, "Hello, Python!")

Writable(Protocol)定义了一个需要有write方法的协议,该方法接受一个字符串data并返回一个整数。
类FileWriter和StringWriter都有一个write方法,这意味着它们“符合”Writable协议。注意,我们没有明确地让FileWriter或StringWriter类继承Writable协议。
函数write_data接受Writable类型的参数writer。这意味着任何实现了write方法的对象都可以传递给这个函数。
最后,创建了FileWriter和StringWriter的实例,然后将它们传递给write_data函数,展示了如何在不使用继承的情况下通过协议来实现接口兼容性。
这种方式的好处是可以让你的代码更加灵活,并且它鼓励更好的分离关注点。另外,由于它基于鸭子类型,所以它对于一些动态编程模式也非常有用,例如在mocking或依赖注入中。

小结:

Python的typing模块为静态类型检查提供了强大的支持,通过在代码中添加类型注解,不仅可以提高代码的可读性,还可以利用静态类型检查工具(如mypy)来发现潜在的错误。随着Python生态的发展,类型提示已经成为Python编程的一个重要部分。
如果你觉得文章还不错,请大家 点赞、分享、留言 ,因为这将是我持续输出更多优质文章的最强动力!当然如果有小伙伴需要python、java、性能等等相关的学习资料的也可以私聊我获取哈,都是本人之前收集的一些学习资料,都可以免费提供给大家学习,希望能对大家有帮助。
在这里插入图片描述

  • 28
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python是一个强大的编程语言,拥有丰富的库和工具集,但是有时候在一个项目中需要使用多个版本的Python或者在不同的项目之间切换,这时候就需要virtualenv(虚拟环境)了。virtualenv是一个可以在同一台机器上创建多个独立的Python环境的工具,每个虚拟环境都有自己的Python解释器和库。 typing-extensions是Python的一个库,它提供了高级类型提示(setupclass, ParamSpec, TypedDict等),使代码更具可读性和可靠性。在Python 3.5中,typing-extensions被认为是标准库一部分,2020年被添加到Python 3.8的标准库中。如果你正在使用Python 3.5及以上版本,你可以使用typing-extensions。 在虚拟环境中使用typing-extensions非常方便。为了在虚拟环境中使用typing-extensions,首先需要安装所需的库和工具,然后在虚拟环境中安装typing-extensions。可以使用以下命令完成这些工作: ```bash pip install virtualenv virtualenv env_name source env_name/bin/activate pip install typing-extensions ``` 以上命令会安装virtualenv和typing-extensions库,并创建一个名为env_name的虚拟环境。使用source命令激活虚拟环境,进入虚拟环境后可以使用typing-extensions。 总的来说,虚拟环境和typing-extensions是Python编程中必不可少的工具,虚拟环境可以隔离不同的项目和Python版本,而typing-extensions提供高级类型提示,提高代码可读性和可靠性。使用虚拟环境和typing-extensions可以使Python编程更加方便和高效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏天Aileft

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值