Python中使用Type hinting 和 annotations

Type hints最大的好处就是易于代码维护。当新成员加入,想要贡献代码时,能减少很多时间。
也方便我们在调用汉书时提供了错误的类型传递导致运行时错误的检测。

第一个类型注解示例

我们使用一个简单例子,两个整数相加。

def add(a, b):
    return a + b

上面的例子,可工作于任意可以进行+操作符的对象。如果我们仅让该函数只能对整型作为参数,然后也只是返回整型结果呢?

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

我们注意到,返回类型是在函数定义末尾使用 -> 符号来指明。

使用mypi及更多例子

Mypy是为Python构建的静态类型检查器。如果我们使用上面的类型注解,mypy可以在代码中
帮我们找到一些错误。你可以使用在开发流程中任意阶段使用它,比如是在CI中作适当的测试。

安装mypy

我们在虚拟环境中安装mypy

$ pip install mypy

我们的示例

我们会进行如下示例描述,虽然代码作用不大,但是我们可以通过它来学习类型注解以及mypy.

class Student:

    def __init__(self, name, batch, branch, roll):
        self.name = name
        self.batch = batch
        self.branch = branch
        self.roll = roll
        self.semester = None
        self.papers = {}

    def is_passed(self):
        "To find if the student has pass the exam in the current semester"
        for k, v in self.papers.items():
            if v < 34:
                return False

        return True

    def total_score(self):
        "Returns the total score of the student"
        total = 0
        for k, v in self.papers.items():
            total += v

        return total

std1 = Student("Kushal", 2005, "cse", "123")
std2 = Student("Sayan", 2005, "cse", 121)
std3 = Student("Anwesha", 2005, "law", 122)

std1.papers = {"english": 78, "math": 82, "science": 77}
std2.papers = {"english": 80, "math": 92, "science": "78"}
std3.papers = {"english": 82, "math": 87, "science": 77}

for std in [std1, std2, std3]:
    print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score()))

你可能发现了代码中其实有错误,但是在实际开发过程我们经常会发生,并且除了在运行时发现,我们并没有其他更好的机制。

使用 mypy

我们通过mypy来执行我们的代码,我们把文件取名为students2.py

加入一些类型注解

我们将会在__init__方法中加入一些类型注解。为减少代码长度,修改如下:

class Student:

    def __init__(self, name: str, batch: int, branch: str, roll: int) -> None:
        self.name = name
        self.batch = batch
        self.branch = branch
        self.roll = roll
        self.semester = None
        self.papers = {}

$ mypy students2.py
students2.py:9: error: Need type annotation for 'papers'
students2.py:29: error: Argument 4 to "Student" has incompatible type "str"; expected "int"

可以看到mypy有提示哪些变量没有类型注解,还有在29行,参数我们期望的是整型,但在调用时传递了字符串类型,现在让我们来修正他。

from typing import Dict

class Student:

    def __init__(self, name: str, batch: int, branch: str, roll: int) -> None:
        self.name = name
        self.batch = batch
        self.branch = branch
        self.roll = roll
        self.semester = None
        self.papers: Dict[str, int] = {}

    def is_passed(self):
        "To find if the student has pass the exam in the current semester"
        for k, v in self.papers.items():
            if v < 34:
                return False

        return True

    def total_score(self):
        "Returns the total score of the student"
        total = 0
        for k, v in self.papers.items():
            total += v

        return total

std1: Student = Student("Kushal", 2005, "cse", 123)
std2: Student = Student("Sayan", 2005, "cse", 121)
std3: Student = Student("Anwesha", 2005, "law", 122)

std1.papers = {"english": 78, "math": 82, "science": 77}
std2.papers = {"english": 80, "math": 92, "science": 78}
std3.papers = {"english": 82, "math": 87, "science": 77}

for std in [std1, std2, std3]:
    print("Passed: {0}. The toral score of {1} is {2}".format(std.is_passed(), std.name, std.total_score()))

现在,没有任何错误了。在第一行我们还从typing包引入了Dcit。并作为了self.paper的类型注解,这里的意思就是该变量是字典类型,使用字符串作为键,整型作为值。我们设置std1, std2和std3变量注解为Student类。

现在,我们给papers变量赋一些错误类型的值。

std1.papers = ["English", "Math"]

或者错误的字典键值对

std2.papers = {1: "Engish", 2: "Math"}

我们能看到类似如下错误

$ mypy students2.py
students2.py:35: error: Incompatible types in assignment (expression has type List[str], variable has type Dict[str, int])
students2.py:36: error: Dict entry 0 has incompatible type "int": "str"
students2.py:36: error: Dict entry 1 has incompatible type "int": "str"

更多类型注解示例

from typing import List, Tuple, Sequence, Optional

values: List[int] = []
city: int = 350 # The city code, not a name

# This function returns a Tuple of two values, a str and an int
def get_details() -> Tuple[str, int]:
    return "Python", 5

# The following is an example of Tuple unpacking
name: str
marks: int
name, marks = get_details()

def print_all(values: Sequence) -> None:
    for v in values:
        print(v)

print_all([1,2,3])
print_all({"name": "kushal", "class": 5})
# alltypes.py:23: error: Argument 1 to "print_all" has incompatible type Dict[str, object]; expected Sequence[Any]
# But running the code will give us no error with wrong output

def add_ten(number: Optional[int] = None) -> int:
    if number:
        return number + 10
    else:
        return 42

print(add_ten())
print(add_ten(12))

你可以从PEP 484了解更多类型。typing模块进行更多例子解释如何在代码中使用类型注解。

原文地址:https://www.cnblogs.com/erhuabushuo/p/10180789.html

时间: 2024-11-10 01:12:13

Python中使用Type hinting 和 annotations的相关文章

python中的type

我们常用type()来查看类型,使用方法如下: 1 a = "zzzq" 2 b = 1 3 c = (1, "zzq123") 4 d = [2, "dlrb"] 5 e = {} 6 a1 = type(a) 7 b1 = type(b) 8 c1 = type(c) 9 d1 = type(d) 10 e1 = type(e) 11 print a1, b1, c1, d1, e1 我们可以看到我们提供了五种类型的变量,使用type()来获

使用C语言为python编写动态模块(1)--从底层深度解析python中的对象以及变量

楔子 我们知道可以通过使用C语言编写动态链接库的方式来给python加速,但是方式是通过ctypes来加载,通过类CDLL将动态链接库加载进来得到一个对象之后,通过这个对象来调用动态链接库里面的函数.那么问题来了,我们可不可以使用C语言为python编写模块呢?然后在使用的时候不使用ctypes加载动态库的方式,而是通过python的关键字import进行加载. 答案是可以的,我们知道可以通过编写py文件的方式来得到一个模块,那么也可以使用C语言来编写C源文件,然后再通过python解释器进行编

使用C语言为python编写动态模块(3)--在C中实现python中的类

楔子 这次我们来介绍python中的类型在C中是如何实现的,我们在C中创建python的int对象,可以使用PyLong_FromLong.创建python的list对象可以使用PyList_New,那么如何在C中构建一个python中的类呢? 对于构建一个类,我们肯定需要以下步骤: 创建一个类扩展 添加类的参数 添加类的方法 添加类的属性,比如可以设置.获取属性 添加类的继承 解决类的循环引用导致的内存泄露问题和自定义垃圾回收 前面几个步骤是必须的,但是容易把最后一个问题给忽略掉.我们在pyt

python中super出现的TypeError: must be type, not classobj 原因及解决

执行一下代码,出现错误,TypeError: must be type, not classobj class A():    def __init__(self):        print("Enter A")        print("Leave A") class B(A):    def __init__(self):        print("Enter B")        super(B, self).__init__()  

Python中type与Object的区别

Python中type与Object的区别 在查看了Python的API后,总算明白了.现在总结如下: 先来看object的说明: Python中关于object的说明很少,甚至只有一句话: class object The most base type 从介绍上看这也是Python对类型统一做出的努力.所以这里的object与Java的Object类有着异曲同工之妙,而且可以推测这个object很可能就是一个定义了一个类型的"空类" 再来看type的说明: class type(ob

python中通过元类(TYPE)简单实现对象关系映射(ORM)

ORM是创建一个实例对象,用创建他的类名当做数据表名,用创建他的类属性对应数据表的字段,不需要在自己写复杂的sql语句,而是通过对实例对象的操作时,能让代码自动帮我们整理为对应的sql语句. class User(父类): uid = ("uid", "int unsigned") name = ("username", "varchar(20)") password = ("password", &quo

Python中字符串格式化如何实现?

Python开发中字符串格式化有两种方式: 百分号方式.format方式 百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存. This PEP proposes a new system for built-in string formatting operations, intended as a replacement for the existing '%' string formatting operator. 1.百分号方式 %[(na

Python中time模块详解

在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. 在开始之前,首先要说明这几点: 在Python中,通常有这几种方式来表示时间:1)时间戳 2)格式化的时间字符串 3)元组(struct_time)共九个元素.由于Python的time模块实现主要调用C库,所以各个平台可能有所不同. UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间.在中国为UTC+8.DST

【Python中if __name__ == &#39;__main__&#39;: 的解析】

在很多Python代码中,在代码的最下方会看到  if __name__ == '__main__':,这段代码到底有什么用呢? 在理解这个语句的作用前,需要知道的是,一般的Python文件后缀为.py,其可以拿来执行,也可以用来作为模块使用import导入.当Python解析器读取一个源文件时它会执行所有的代码.在执行代码前会定义一些特殊的变量.如果解析器运行的模块(源文件)作为主程序,它将会把__name__变量设置成"__main__".如果只是引入其他的模块,__name__变