检查python模块_Python输入模块–有效使用类型检查器

检查python模块

Introduced since Python 3.5, Python’s typing module attempts to provide a way of hinting types to help static type checkers and linters accurately predict errors.

从Python 3.5开始引入,Python的键入 模块尝试提供一种提示类型的方法,以帮助静态类型检查器和linters准确地预测错误。

Due to Python having to determine the type of objects during run-time, it sometimes gets very hard for developers to find out what exactly is going on in the code.

由于Python必须在运行时确定对象的类型,因此开发人员有时很难找出代码中到底发生了什么。

Even external type checkers like PyCharm IDE do not produce the best results; on average only predicting errors correctly about 50% of the time, according to this answer on StackOverflow.

即使像PyCharm IDE这样的外部类型检查器也无法产生最佳结果。 平均只有正确预测约50%的时间误差,根据这个答案在计算器上。

Python attempts to mitigate this problem by introducing what is known as type hinting (type annotation) to help external type checkers identify any errors. This is a good way for the programmer to hint the type of the object(s) being used, during compilation time itself and ensure that the type checkers work correctly.

Python尝试通过引入所谓的类型提示 (类型注释)来缓解这种问题,以帮助外部类型检查器识别任何错误。 对于程序员来说,这是在编译期间暗示所使用对象类型的好方法,并确保类型检查器正常工作。

This makes Python code much more readable and robust as well, to other readers!

对于其他读者来说,这也使得Python代码更具可读性和鲁棒性!

NOTE: This does not do actual type checking at compile time. If the actual object returned was not of the same type as hinted, there will be no compilation error. This is why we use external type checkers, such as mypy to identify any type errors.

:此并不做实际的类型在编译时检查。 如果作为暗示返回的实际对象是同一类型的没有, 也不会有编译错误。 这就是为什么我们使用外部类型检查器(例如mypy)来识别任何类型错误的原因。



建议的先决条件 (Recommended Prerequisites)

For using the typing module effectively, it is recommended that you use an external type checker/linter to check for static type matching. One of the most widely used type checkers in use for Python is mypy, so I recommend that you install it before reading the rest of the article.

为了有效使用typing模块,建议您使用外部类型检查器/衬纸检查静态类型匹配。 用于Python的最广泛使用的类型检查器之一是mypy ,因此建议您在阅读本文其余部分之前先安装它。

We have already covered the basics of type checking in Python. You can go through this article first.

我们已经介绍了Python类型检查的基础。 您可以先阅读本文。

We will be using mypy as the static type checker in this article, which can be installed by:

我们将在本文mypy用作静态类型检查器,可以通过以下方式安装它:


pip3 install mypy

You can run mypy to any Python file to check if the types match. This is as if you are ‘compiling’ Python code.

您可以将mypy运行到任何Python文件中,以检查类型是否匹配。 就像您正在“编译” Python代码一样。


mypy program.py

After debugging errors, you can run the program normally using:

调试错误后,可以使用以下命令正常运行该程序:


python program.py

Now that we have our prerequisites covered, let’s try to use some of the module’s features.

现在我们已经满足了先决条件,让我们尝试使用该模块的某些功能。



类型提示/类型注释 (Type Hints / Type Annotations)

关于功能 (On functions)

We can annotate a function to specify its return type and the types of its parameters.

我们可以注释一个函数以指定其返回类型及其参数的类型。


def print_list(a: list) -> None:
    print(a)

This informs the type checker (mypy in my case) that we have a function print_list(), that will take a list as an argument and return None.

这将通知类型检查器(在我的情况下为mypy )我们有一个函数print_list() ,该函数将list作为参数并返回None


def print_list(a: list) -> None:
    print(a)

print_list([1, 2, 3])
print_list(1)

Let’s run this on our type checker mypy first:

首先让我们在类型检查器mypy上运行它:


vijay@JournalDev:~ $ mypy printlist.py 
printlist.py:5: error: Argument 1 to "print_list" has incompatible type "int"; expected "List[Any]"
Found 1 error in 1 file (checked 1 source file)

As expected, we get an error; since the line #5 has the argument as an int, rather than a list.

不出所料,我们得到一个错误; 因为第5行的参数为int而不是list

关于变量 (On Variables)

Since Python 3.6, we can also annotate the types of variables, mentioning the type. But this is not compulsory if you want the type of a variable to change before the function returns.

从Python 3.6开始,我们还可以注释变量的类型,并提及类型。 但这不是强制性的,如果您希望在函数返回之前更改变量的类型。


# Annotates 'radius' to be a float
radius: float = 1.5

# We can annotate a variable without assigning a value!
sample: int

# Annotates 'area' to return a float
def area(r: float) -> float:
    return 3.1415 * r * r


print(area(radius))

# Print all annotations of the function using
# the '__annotations__' dictionary
print('Dictionary of Annotations for area():', area.__annotations__)

Output of mypy:

mypy的输出


vijay@JournalDev: ~ $ mypy find_area.py && python find_area.py
Success: no issues found in 1 source file
7.068375
Dictionary of Annotations for area(): {'r': <class 'float'>, 'return': <class 'float'>}

This is the recommended way to use mypy, first providing type annotations, before using the type checker.

建议使用mypy ,首先使用类型注释,然后再使用类型检查器。



类型别名 (Type Aliases)

The typing module provides us with Type Aliases, which is defined by assigning a type to the alias.

typing模块为我们提供了Type Aliases ,它是通过为别名分配类型来定义的。


from typing import List

# Vector is a list of float values
Vector = List[float]

def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]

a = scale(scalar=2.0, vector=[1.0, 2.0, 3.0])
print(a)

Output

输出量


vijay@JournalDev: ~ $ mypy vector_scale.py && python vector_scale.py
Success: no issues found in 1 source file
[2.0, 4.0, 6.0]

In the above snippet, Vector is an alias, which stands for a list of floating point values. We can type hint at an alias, which is what the above program is doing.

在上面的代码段中, Vector是一个别名,代表浮点值的列表。 我们可以在别名上键入提示,这就是上面程序的作用。

The complete list of acceptable aliases is given here.

此处提供可接受别名的完整列表。

Let’s look at one more example, which checks every key:value pair in a dictionary and check if they match the name:email format.

让我们再看一个示例,该示例检查字典中的每个key:value对,并检查它们是否与name:email格式匹配。


from typing import Dict
import re

# Create an alias called 'ContactDict'
ContactDict = Dict[str, str]

def check_if_valid(contacts: ContactDict) -> bool:
    for name, email in contacts.items():
        # Check if name and email are strings
        if (not isinstance(name, str)) or (not isinstance(email, str)):
            return False
        # Check for email xxx@yyy.zzz
        if not re.match(r"[a-zA-Z0-9\._\+-]+@[a-zA-Z0-9\._-]+\.[a-zA-Z]+$", email):
            return False
    return True


print(check_if_valid({'vijay': 'vijay@sample.com'}))
print(check_if_valid({'vijay': 'vijay@sample.com', 123: 'wrong@name.com'}))

Output from mypy

mypy的输出


vijay@JournalDev:~ $ mypy validcontacts.py 
validcontacts.py:19: error: Dict entry 1 has incompatible type "int": "str"; expected "str": "str"
Found 1 error in 1 file (checked 1 source file)

Here, we get a static compile time error in mypy, since the name parameter on our second dictionary is an integer (123). Thus, aliases are another way to enforce accurate type checking from mypy.

在这里,由于第二个字典上的name参数是一个整数( 123 ),因此mypy出现了静态编译时错误。 因此,别名是从mypy强制进行准确类型检查的另一种方法。



使用NewType()创建用户定义的数据类型 (Create user defined datatypes using NewType())

We can use the NewType() function to create new user defined types.

我们可以使用NewType()函数来创建新的用户定义类型。


from typing import NewType

# Create a new user type called 'StudentID' that consists of
# an integer
StudentID = NewType('StudentID', int)
sample_id = StudentID(100)

The static type checker will treat the new type as if it were a subclass of the original type. This is useful in helping catch logical errors.

静态类型检查器会将新类型视为原始类型的子类。 这有助于帮助捕获逻辑错误。


from typing import NewType

# Create a new user type called 'StudentID'
StudentID = NewType('StudentID', int)

def get_student_name(stud_id: StudentID) -> str:
    return str(input(f'Enter username for ID #{stud_id}:\n'))

stud_a = get_student_name(StudentID(100))
print(stud_a)

# This is incorrect!!
stud_b = get_student_name(-1)
print(stud_b)

Output from mypy

mypy的 输出


vijay@JournalDev:~ $ mypy studentnames.py  
studentnames.py:13: error: Argument 1 to "get_student_name" has incompatible type "int"; expected "StudentID"
Found 1 error in 1 file (checked 1 source file)


任何类型 (The Any type)

This is a special type, informing the static type checker (mypy in my case) that every type is compatible with this keyword.

这是一种特殊类型,通知静态类型检查器(在我的情况下为mypy )每个类型都与此关键字兼容。

Consider our old print_list() function, now accepting arguments of any type.

考虑我们以前的print_list()函数,现在接受任何类型的参数。


from typing import Any

def print_list(a: Any) -> None:
    print(a)

print_list([1, 2, 3])
print_list(1)

Now, there will be no errors when we run mypy.

现在,运行mypy不会有任何错误。


vijay@JournalDev:~ $ mypy printlist.py && python printlist.py
Success: no issues found in 1 source file
[1, 2, 3]
1

All functions without a return type or parameter types will implicitly default to using Any.

所有没有返回类型或参数类型的函数都将默认使用Any


def foo(bar):
    return bar

# A static type checker will treat the above
# as having the same signature as:
def foo(bar: Any) -> Any:
    return bar

You can thus use Any to mix up statically and dynamically typed code.

因此,您可以使用Any混合静态和动态类型的代码。



结论 (Conclusion)

In this article, we have learned about the Python typing module, which is very useful in the context of type checking, allowing external type checkers like mypy to accurately report any errors.

在本文中,我们了解了Python 类型模块,该模块在类型检查的上下文中非常有用,它允许像mypy这样的外部类型检查器准确报告任何错误。

This provides us with a way to write statically typed code in Python, which is a dynamically typed language by design!

这为我们提供了一种使用Python编写静态类型代码的方法,这是一种设计成动态类型的语言!



参考资料 (References)



翻译自: https://www.journaldev.com/34519/python-typing-module

检查python模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值