查看原文
其他

typing库:让你的代码阅读者再也不用猜猜猜

大邓 大邓和他的Python 2019-04-26

Python以其简洁的代码而闻名于世。除了缩进之外,代码样式文档主要取决于编写应用程序的开发人员的习惯,这可能导致一些混乱,产生难以理解的代码。而这主要是因为Python是一种动态类型语言,请看以下代码。在Python中,这是完全可以接受的。

age = 21
print(age)  # 21
age = 'Twenty One'
print(age)  # Twenty One

在上面的代码中,age的值首先是一个int,但之后我们将它更改为str。每个变量都可以在程序中任何一点的表示任何值。这就是动态类型的力量!

让我们尝试用静态类型语言(如Java)做同样的事情。

int age = 21;
System.out.print(age);
age = "Twenty One";
System.out.print(age);

我们实际上最终得到以下错误,因为我们试图将“Twenty One”(一个字符串)分配给声明为int的变量age。

Error: incompatible types: String cannot be converted to int

为了使用静态类型语言,我们必须使用两个单独的变量。

int ageNum = 21;
System.out.print(ageNum);
String ageStr = ageNum.toString();
System.out.print(ageStr);

这很有效,但我更喜欢Python这种动态语言的灵活性,这不会使得我的代码更加复杂混乱。此外,我也喜欢静态类型语言的可读性,以便其他程序员知道特定变量应该是什么类型!为了充分利用这两个方面,Python 3.5引入了类型注释(Type Annotations)。

什么是类型注释?

类型注释是PEP 484中添加的新功能,允许向变量添加类型提示。 它们用于提醒代码阅读者知晓此处的变量应该什么类型。 这为动态类型的Python带来了静态类型的感觉。 这是通过在初始化/声明变量后添加:<type>来实现的。

下面显示了一个示例,当我们声明变量以显示age应该是int类型时,它会添加:int

age: int = 5
print(age)
5

值得注意的是,类型注释不会以任何方式影响程序的运行时。 解释器会忽略这些提示,仅用于提高其他程序员和您自己的可读性。

为什么以及如何使用类型注释?

静态类型语言的一个很有用特点是在代码中特定作用域内的变量的值的类型总是明确的。 例如,我们知道字符串变量只能是字符串,整数只能是整数,依此类推。 而使用动态类型语言,任何人对于代码中的变量都不是百分百明确或者立刻明确,都是需要理解加猜测才能知晓变量的类型。

在编写和调用函数时,我们可以使用预期的变量类型,以确保我们正确地传递和使用参数。 如果我们的函数期望传入int时反而传入str,那么它很可能不会按照我们预期的方式工作。

请考虑以下代码:

def mystery_combine(a, b, times):
    return (a + b) * times

我们可以看到该函数正在做什么,但我们知道a,b或times应该是什么吗? 查看下面的代码,特别是在我们用不同类型的参数调用mystery_combine的两行中。 观察每个版本的输出,该输出显示在每个块下面的注释中。

def mystery_combine(a, b, times):
    return (a + b) * times

print(mystery_combine(234))
# 20

print(mystery_combine('Hello ''World! '4))
# Hello World! Hello World! Hello World! Hello World!

根据上面两个调用函数的例子,我们得到两个完全不同的结果。 将整数传入函数我们得到数学,但是当我们将字符串传递给函数时,我们可以看到前两个参数是拼接字符串,并且结果字符串乘以倍数

事实证明,编写该函数的开发人员实际上预期的运行效果应该是拼接并乘以倍数,使用类型注释,我们可以清除这种混淆。

def mystery_combine(a: str, b: str, times: int) -> str:
    return (a + b) * times

我们在函数的参数中添加了:str,:str:int来显示它们应该是什么类型。 这有望使代码更清晰,并且能让代码阅读者快速理解函数的目的。

我们还添加了 -> str来表明这个函数将返回一个str。 使用 -> <type>,我们可以更轻松地显示任何函数或方法的返回值类型,以避免未来开发人员的混淆!

同样,我们仍然可以以第一种不正确的方式调用我们的代码,但希望通过良好的审查,程序员将看到他们正在以一种非预期的方式使用该函数。 类型注释和提示对团队和多开发人员Python应用程序非常有用。 它消除了阅读代码过程中大部分猜测,节约了码农的时间!

复杂类型Complex Type

上一节处理了许多类型注释的基本用例,但都是很基础的例子,接下来让我们分解一些更复杂的例子。

对于Python语言的typeing库。 可以描述任何变量的任何类型(类型注释)。 它预装了多种类型注释,如Dict,Tuple,List,Set等等! 然后,您可以将类型提示扩展为用例,如下例所示。

from typing import List

def print_names(names: List[str]) -> None:
    for student in names:
        print(student)

这将告诉代码阅读者names参数应该是字符串列表,返回None。

字典也以类似的方式工作。

from typing import Dict

def print_name_and_grade(grades: Dict[str, float]) -> None:
    for student, grade in grades.items():
        print(student, grade)

Dict[str,float]类型提示告诉我们,grades参数传入的应该是一个字典,其中键是字符串,值是浮点数。 其他复杂的示例依然可以使用typing模块。

起个别名

如果要使用自定义类型名称,可以使用类型别名(Type Aliases)。假设您正在使用一组[x,y]点作为元组,那么我们可以使用别名将Tuple类型映射到Point类型

from typing import List, Tuple

# 声明Point类型,该Point类实际上是[x, y]元组的别名
Point = Tuple[int, int]

# points参数是很多个Point类组成的列表
def print_points(points: List[Point]):
    for point in points:
        print("X:", point[0], "  Y:", point[1])

返回多个值

如果你的函数以元组类型返回多个值,那么只需将预期输出包装为输入Tuple [<type 1>,<type 2>,...]

from typing import Tuple

def get_api_response() -> Tuple[int, int]:
    successes, errors = ... # Some API call
    return successes, errors

上面的函数get_api_response代码返回API调用中成功错误数量的元组,其中两个值都是整数。 通过使用Tuple [int,int],我们向开发人员指出这个函数确实返回了多个int值。

多种可选类型

如果某个函数的参数可以是多种可选类型,则可以使用typing.Optionaltyping.Union类型。

如果该参数可以是 特定类型 ,也可以是 None ,则使用 Optional

from typing import Optional

def try_to_print(some_num: Optional[int]):
    if some_num:
        print(some_num)
    else:
        print('Value was None!')

上面的函数try_to_print函数中的some_num参数可以是int也可以是None

当参数采用 更具体的类型提示 时使用 Union

from typing import Union

def print_grade(grade: Union[int, str]):
    if isinstance(grade, str):
        print(grade + ' percent')
    else:
        print(str(grade) + '%')

上面的代码表明grade可以是int或str类型。 这对我们打印grade的示例很有帮助,因此我们可以打印98%或98%,没有其他意外的情况。

更多例子

有关更多示例,请查看typing模块的官方Python文档。

https://docs.python.org/3/library/typing.html

他们有很多不同的例子,你可以查看。 这篇文章仅仅是冰山一角,但希望本文的简单介绍能让大家设计的代码因为有类型注释而变得更加清晰,更易阅读。

往期文章

100G Python学习资料(免费下载)

100G 文本分析语料资源(免费下载)     

大邓强力推荐-jupyter notebook使用小技巧 

PySimpleGUI: 开发自己第一个软件

深度特征合成:自动生成机器学习中的特征

Python 3.7中dataclass的终极指南(一) 

Python 3.7中dataclass的终极指南(二) 

2017年度15个最好的数据科学领域Python库    

使用Pandas更好的做数据科学

[计算消费者的偏好]推荐系统与协同过滤、奇异值分解

机器学习: 识别图片中的数字

应用PCA降维加速模型训练

如何从文本中提取特征信息?

使用sklearn做自然语言处理-1 

使用sklearn做自然语言处理-2

机器学习|八大步骤解决90%的NLP问题    

Python圈中的符号计算库-Sympy

Python中处理日期时间库的使用方法 

【视频讲解】Scrapy递归抓取简书用户信息

美团商家信息采集神器 

用chardect库解决网页乱码问题 



    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存