提交 68f1b5d3 编写于 作者: J jamesyangget

update python types

上级 d6012cc7
**Python 3.6+** has support for optional "type hints".
**Python 3.6+**支持可选的“类型提示”。
These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
这些**“类型提示”**是一种新语法(自Python 3.6+起),允许声明变量的类型(例如:str,int,float,bool)。
By declaring types for your variables, editors and tools can give you better support.
通过声明变量的类型,编辑器和工具可以为你提供更好的支持。
This is just a **quick tutorial / refresher** about Python type hints. It covers only the minimum necessary to use them with **FastAPI**... which is actually very little.
这只是关于Python类型提示的**快速教程/复习**。 它仅涵盖将它们与**FastAPI**一起使用所需的最低要求……实际上很少。
**FastAPI** is all based on these type hints, they give it many advantages and benefits.
**FastAPI**都是基于这些类型提示的,它们具有许多优点和好处。
But even if you never use **FastAPI**, you would benefit from learning a bit about them.
但是,即使你从未使用过**FastAPI**,也可以从中学习到一些好处。
!!! note
If you are a Python expert, and you already know everything about type hints, skip to the next chapter.
> 注意:
> 如果你是Python专家,并且已经了解有关类型提示的所有知识,请跳到下一章。
## Motivation
## 动手做
Let's start with a simple example:
让我们从一个简单的例子开始(源码在`./src/python_types/tutorial001.py`):
```Python
{!./src/python_types/tutorial001.py!}
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
```
Calling this program outputs:
调用该程序输出:
```
John Doe
```
The function does the following:
该函数执行以下操作:
* Takes a `first_name` and `last_name`.
* Converts the first letter of each one to upper case with `title()`.
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
* 获取一个`first_name`和一个`last_name`.
* 使用`title()`将每个字母的首字母转换为大写。
* 在它们中间用一个空格连接(将它们放在一起,作为一个整体。 一个内容接另一个。)。
```Python hl_lines="2"
{!./src/python_types/tutorial001.py!}
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
```
### Edit it
### 编辑它
It's a very simple program.
这是一个非常简单的程序。
But now imagine that you were writing it from scratch.
但是现在想象一下,你是从头开始编写的。
At some point you would have started the definition of the function, you had the parameters ready...
在某个时候,你将开始定义函数,已经准备好参数...
But then you have to call "that method that converts the first letter to upper case".
但是然后你必须调用“将第一个字母转换为大写字母的方法”。
Was it `upper`? Was it `uppercase`? `first_uppercase`? `capitalize`?
`上(upper)`吗? 是`大写(uppercase)`吗? `首字母大写(first_uppercase)``大写(capitalize)`
Then, you try with the old programmer's friend, editor autocompletion.
然后,你尝试与老程序员的朋友:编辑器自动补全。
You type the first parameter of the function, `first_name`, then a dot (`.`) and then hit `Ctrl+Space` to trigger the completion.
键入函数的第一个参数`first_name`,然后输入点(`。`),然后按`Ctrl+Space`以触发补全。
But, sadly, you get nothing useful:
但是,可悲的是,你没有得到任何有用的信息(然并卵):
<img src="/img/python-types/image01.png">
### Add types
### 添加类型
Let's modify a single line from the previous version.
让我们从以前的版本中修改一行。
We will change exactly this fragment, the parameters of the function, from:
我们将从以下位置精确更改此片段(函数的参数):
```Python
first_name, last_name
```
to:
改为:
```Python
first_name: str, last_name: str
```
That's it.
就这样。
Those are the "type hints":
这些是“类型提示”(源码在`./src/python_types/tutorial002.py`):
```Python hl_lines="1"
{!./src/python_types/tutorial002.py!}
def get_full_name(first_name: str, last_name: str):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
```
That is not the same as declaring default values like would be with:
这与声明默认值不同,例如:
```Python
first_name="john", last_name="doe"
```
It's a different thing.
这是另一回事。
We are using colons (`:`), not equals (`=`).
我们使用冒号(`:`),而不是等于号(`=`)。
And adding type hints normally doesn't change what happens from what would happen without them.
添加类型提示通常不会改变没有它们的情况。
But now, imagine you are again in the middle of creating that function, but with type hints.
但是现在,假设你再次处于创建该函数的过程中,但是带有类型提示。
At the same point, you try to trigger the autocomplete with `Ctrl+Space` and you see:
同时,你尝试使用`Ctrl+Space`触发自动补全,您会看到:
<img src="/img/python-types/image02.png">
With that, you can scroll, seeing the options, until you find the one that "rings a bell":
这样,你可以滚动查看选项,直到找到“rings a bell”的选项:
<img src="/img/python-types/image03.png">
## More motivation
## 更多的动手操作
Check this function, it already has type hints:
检查此函数,它已经具有类型提示(源码在`./src/python_types/tutorial003.py`):
```Python hl_lines="1"
{!./src/python_types/tutorial003.py!}
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + age
return name_with_age
```
Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
因为编辑器知道变量的类型,所以你不仅可以完成补全操作,还可以进行错误检查:
<img src="/img/python-types/image04.png">
Now you know that you have to fix it, convert `age` to a string with `str(age)`:
现在你知道必须修复它,将`age`转换为带有`str(age)`的字符串(源码在`./src/python_types/tutorial004.py`):
```Python hl_lines="2"
{!./src/python_types/tutorial004.py!}
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + str(age)
return name_with_age
```
## Declaring types
## 声明类型
You just saw the main place to declare type hints. As function parameters.
你刚刚看到了声明类型提示的主要地方。作为函数参数。
This is also the main place you would use them with **FastAPI**.
这也是将它们与**FastAPI**一起使用的主要位置。
### Simple types
### 简单类型
You can declare all the standard Python types, not only `str`.
你可以声明所有标准的Python类型,不仅限于`str`
You can use, for example:
你可以使用,例如:
* `int`
* `float`
* `bool`
* `bytes`
(源码在`./src/python_types/tutorial005.py`):
```Python hl_lines="1"
{!./src/python_types/tutorial005.py!}
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
return item_a, item_b, item_c, item_d, item_d, item_e
```
### Types with subtypes
### 带有子类型的类型
There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too.
有些数据结构可以包含其他值,例如`dict``list``set``tuple`。 内部的值也可以具有自己的类型。
To declare those types and the subtypes, you can use the standard Python module `typing`.
要声明这些类型和子类型,可以使用标准的Python模块`typing`
It exists specifically to support these type hints.
它专门存在以支持这些类型提示。
#### Lists
#### 列表
For example, let's define a variable to be a `list` of `str`.
例如,让我们将变量定义为`字符串(str)``列表(list)`
From `typing`, import `List` (with a capital `L`):
`typing`里,导入`List`(大写字母`L`)(源码在`./src/python_types/tutorial006.py`):
```Python hl_lines="1"
{!./src/python_types/tutorial006.py!}
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)
```
Declare the variable, with the same colon (`:`) syntax.
用相同的冒号(`:`)语法声明变量。
As the type, put the `List`.
作为类型,输入`List`
As the list is a type that takes a "subtype", you put the subtype in square brackets:
由于列表是带有“子类型”的类型,因此请将子类型放在方括号中(源码在`./src/python_types/tutorial006.py`):
```Python hl_lines="4"
{!./src/python_types/tutorial006.py!}
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)
```
That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
那意味着:“变量`items`是一个`列表list`,在这个列表中的每一项是一个`字符串str`”。
By doing that, your editor can provide support even while processing items from the list.
这样,即使在处理列表中每项时,你的编辑器也可以提供支持。
Without types, that's almost impossible to achieve:
没有类型,几乎是不可能实现的:
<img src="/img/python-types/image05.png">
Notice that the variable `item` is one of the elements in the list `items`.
注意,变量`item`是列表`items`中的元素之一。
And still, the editor knows it is a `str`, and provides support for that.
而且,编辑器仍然知道它是一个`str`,并为此提供了支持。
#### Tuples and Sets
#### 元组和集合
You would do the same to declare `tuple`s and `set`s:
声明`元组tuple``集合set`的方法相同(源码在`./src/python_types/tutorial007.py`):
```Python hl_lines="1 4"
{!./src/python_types/tutorial007.py!}
from typing import Set, Tuple
def process_items(items_t: Tuple[int], items_s: Set[bytes]):
return items_t, items_s
```
This means:
这意味着:
* The variable `items_t` is a `tuple`, and each of its items is an `int`.
* The variable `items_s` is a `set`, and each of its items is of type `bytes`.
* 变量`items_t`是一个`元组tuple`,它的每一项是一个`整型int`.
* 变量`items_s`是一个`集合set`,它的每一项是`字节bytes`类型.
#### Dicts
#### 字典
To define a `dict`, you pass 2 subtypes, separated by commas.
要定义`字典dict`,你可以传递2个子类型,以逗号分隔。
The first subtype is for the keys of the `dict`.
第一个子类型用于`字典dict`的键。
The second subtype is for the values of the `dict`:
第二个子类型用于`字典dict`的值(源码在`./src/python_types/tutorial008.py`):
```Python hl_lines="1 4"
{!./src/python_types/tutorial008.py!}
from typing import Dict
def process_items(prices: Dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)
```
This means:
这意味着:
* The variable `prices` is a `dict`:
* The keys of this `dict` are of type `str` (let's say, the name of each item).
* The values of this `dict` are of type `float` (let's say, the price of each item).
* 变量`prices`是一个`字典dict`:
* 这个`字典dict`的键是`字符串str`类型(假设每项的名称)。
* 这个`字典dict`的值是`浮点数float`类型(假设每项的价格)。
### Classes as types
### 类作为类型
You can also declare a class as the type of a variable.
你也可以将类声明为变量的类型。
Let's say you have a class `Person`, with a name:
假设你有一个名为`Person`的类,其名称为(源码在`./src/python_types/tutorial009.py`):
```Python hl_lines="1 2 3"
{!./src/python_types/tutorial009.py!}
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
```
Then you can declare a variable to be of type `Person`:
然后,你可以将变量声明为`Person`类型(源码在`./src/python_types/tutorial009.py`):
```Python hl_lines="6"
{!./src/python_types/tutorial009.py!}
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
```
And then, again, you get all the editor support:
然后,再次获得所有编辑器支持:
<img src="/img/python-types/image06.png">
## Pydantic models
## Pydantic模型
<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> is a Python library to perform data validation.
<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>是用于执行数据验证的Python库。
You declare the "shape" of the data as classes with attributes.
你将数据的“形状shape”声明为具有属性的类。
And each attribute has a type.
每个属性都有一个类型。
Then you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that's the case) and give you an object with all the data.
然后,创建带有某些值的该类的实例,它将验证这些值,将它们转换为适当的类型(如果是这种情况),并为你提供一个包含所有数据的对象。
And you get all the editor support with that resulting object.
然后,你将得到该对象的所有编辑器支持。
Taken from the official Pydantic docs:
取自Pydantic官方文档(源码在`./src/python_types/tutorial010.py`):
```Python
{!./src/python_types/tutorial010.py!}
from datetime import datetime
from typing import List
from pydantic import BaseModel
class User(BaseModel):
id: int
name = "John Doe"
signup_ts: datetime = None
friends: List[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
```
!!! info
To learn more about <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic, check its docs</a>.
> 信息:
> 要了解有关<a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic的更多信息,请检查其文档</a>。
**FastAPI** is all based on Pydantic.
**FastAPI**全部基于Pydantic。
You will see a lot more of all this in practice in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
[教程-用户指南](tutorial/README.md)中,你会在实践中看到更多的相关信息。
## Type hints in **FastAPI**
## **FastAPI**中的类型提示
**FastAPI** takes advantage of these type hints to do several things.
**FastAPI**利用这些类型提示来做几件事。
With **FastAPI** you declare parameters with type hints and you get:
使用**FastAPI**,您可以使用类型提示来声明参数,并得到:
* **Editor support**.
* **Type checks**.
* **编辑器支持**
* **类型检查**
...and **FastAPI** uses the same declarations to:
...**FastAPI**使用相同的声明来:
* **Define requirements**: from request path parameters, query parameters, headers, bodies, dependencies, etc.
* **Convert data**: from the request to the required type.
* **Validate data**: coming from each request:
* Generating **automatic errors** returned to the client when the data is invalid.
* **Document** the API using OpenAPI:
* which is then used by the automatic interactive documentation user interfaces.
* **定义请求**:来自请求路径参数,查询参数,标头,正文,依赖项等。
* **转换数据**:从请求到所需的类型。
* **验证数据**:来自每个请求:
* 当数据无效时,生成**自动错误**返回给客户端。
* **文档** 使用OpenAPI记录API:
* 然后由自动交互式文档用户界面使用。
This might all sound abstract. Don't worry. You'll see all this in action in the [Tutorial - User Guide](tutorial/index.md){.internal-link target=_blank}.
这听起来可能很抽象。 不用担心 你会在[教程-用户指南](tutorial/README.md)中看到所有这些操作。
The important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.
重要的是,通过使用标准的Python类型,在一个地方(而不是添加更多的类,装饰器等),**FastAPI**将为你完成很多工作。
!!! info
If you already went through all the tutorial and came back to see more about types, a good resource is <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">the "cheat sheet" from `mypy`</a>.
> 信息:
> 如果您已经遍历了所有教程并回来查看有关类型的更多信息,那么一个很好的资源是<a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">来自`mypy`的“备忘单”</a>。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册