diff --git a/docs/en/docs/advanced/advanced-python-types.md b/docs/en/docs/advanced/advanced-python-types.md
new file mode 100644
index 0000000000..6495cbe443
--- /dev/null
+++ b/docs/en/docs/advanced/advanced-python-types.md
@@ -0,0 +1,61 @@
+# Advanced Python Types { #advanced-python-types }
+
+Here are some additional ideas that might be useful when working with Python types.
+
+## Using `Union` or `Optional` { #using-union-or-optional }
+
+If your code for some reason can't use `|`, for example if it's not in a type annotation but in something like `response_model=`, instead of using the vertical bar (`|`) you can use `Union` from `typing`.
+
+For example, you could declare that something could be a `str` or `None`:
+
+```python
+from typing import Union
+
+
+def say_hi(name: Union[str, None]):
+ print(f"Hi {name}!")
+```
+
+`typing` also has a shortcut to declare that something could be `None`, with `Optional`.
+
+Here's a tip from my very **subjective** point of view:
+
+* 🚨 Avoid using `Optional[SomeType]`
+* Instead ✨ **use `Union[SomeType, None]`** ✨.
+
+Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required.
+
+I think `Union[SomeType, None]` is more explicit about what it means.
+
+It's just about the words and names. But those words can affect how you and your teammates think about the code.
+
+As an example, let's take this function:
+
+```python
+from typing import Optional
+
+
+def say_hi(name: Optional[str]):
+ print(f"Hey {name}!")
+```
+
+The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:
+
+```Python
+say_hi() # Oh, no, this throws an error! 😱
+```
+
+The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value:
+
+```Python
+say_hi(name=None) # This works, None is valid 🎉
+```
+
+The good news is, in most cases, you will be able to simply use `|` to define unions of types:
+
+```python
+def say_hi(name: str | None):
+ print(f"Hey {name}!")
+```
+
+So, normally you don't have to worry about names like `Optional` and `Union`. 😎
diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md
index 6de170ada4..f2ad35d710 100644
--- a/docs/en/docs/python-types.md
+++ b/docs/en/docs/python-types.md
@@ -135,27 +135,30 @@ You can use, for example:
{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *}
-### Generic types with type parameters { #generic-types-with-type-parameters }
+### `typing` module { #typing-module }
-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.
+For some additional use cases, you might need to import some things from the standard library `typing` module, for example when you want to declare that something has "any type", you can use `Any` from `typing`:
-These types that have internal types are called "**generic**" types. And it's possible to declare them, even with their internal types.
+```python
+from typing import Any
-To declare those types and the internal types, you can use the standard Python module `typing`. It exists specifically to support these type hints.
-#### Newer versions of Python { #newer-versions-of-python }
-
-The syntax using `typing` is **compatible** with all versions, from Python 3.6 to the latest ones, including Python 3.9, Python 3.10, etc.
+def some_function(data: Any):
+ print(data)
+```
-As Python advances, **newer versions** come with improved support for these type annotations and in many cases you won't even need to import and use the `typing` module to declare the type annotations.
+### Generic types { #generic-types }
-If you can choose a more recent version of Python for your project, you will be able to take advantage of that extra simplicity.
+Some types can take "type parameters" in square brackets, to define their internal types, for example a "list of strings" would be declared `list[str]`.
-In all the docs there are examples compatible with each version of Python (when there's a difference).
+These types that can take type parameters are called **Generic types** or **Generics**.
-For example "**Python 3.6+**" means it's compatible with Python 3.6 or above (including 3.7, 3.8, 3.9, 3.10, etc). And "**Python 3.9+**" means it's compatible with Python 3.9 or above (including 3.10, etc).
+You can use the same builtin types as generics (with square brackets and types inside):
-If you can use the **latest versions of Python**, use the examples for the latest version, those will have the **best and simplest syntax**, for example, "**Python 3.10+**".
+* `list`
+* `tuple`
+* `set`
+* `dict`
#### List { #list }
@@ -220,44 +223,20 @@ This means:
You can declare that a variable can be any of **several types**, for example, an `int` or a `str`.
-In Python 3.6 and above (including Python 3.10) you can use the `Union` type from `typing` and put inside the square brackets the possible types to accept.
-
-In Python 3.10 there's also a **new syntax** where you can put the possible types separated by a vertical bar (`|`).
+To define it you use the vertical bar (`|`) to separate both types.
-//// tab | Python 3.10+
+This is called a "union", because the variable can be anything in the union of those two sets of types.
```Python hl_lines="1"
{!> ../../docs_src/python_types/tutorial008b_py310.py!}
```
-////
-
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial008b_py39.py!}
-```
-
-////
-
-In both cases this means that `item` could be an `int` or a `str`.
+This means that `item` could be an `int` or a `str`.
#### Possibly `None` { #possibly-none }
You can declare that a value could have a type, like `str`, but that it could also be `None`.
-In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module.
-
-```Python hl_lines="1 4"
-{!../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-Using `Optional[str]` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too.
-
-`Optional[Something]` is actually a shortcut for `Union[Something, None]`, they are equivalent.
-
-This also means that in Python 3.10, you can use `Something | None`:
-
//// tab | Python 3.10+
```Python hl_lines="1"
@@ -266,96 +245,7 @@ This also means that in Python 3.10, you can use `Something | None`:
////
-//// tab | Python 3.9+
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009_py39.py!}
-```
-
-////
-
-//// tab | Python 3.9+ alternative
-
-```Python hl_lines="1 4"
-{!> ../../docs_src/python_types/tutorial009b_py39.py!}
-```
-
-////
-
-#### Using `Union` or `Optional` { #using-union-or-optional }
-
-If you are using a Python version below 3.10, here's a tip from my very **subjective** point of view:
-
-* 🚨 Avoid using `Optional[SomeType]`
-* Instead ✨ **use `Union[SomeType, None]`** ✨.
-
-Both are equivalent and underneath they are the same, but I would recommend `Union` instead of `Optional` because the word "**optional**" would seem to imply that the value is optional, and it actually means "it can be `None`", even if it's not optional and is still required.
-
-I think `Union[SomeType, None]` is more explicit about what it means.
-
-It's just about the words and names. But those words can affect how you and your teammates think about the code.
-
-As an example, let's take this function:
-
-{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *}
-
-The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter:
-
-```Python
-say_hi() # Oh, no, this throws an error! 😱
-```
-
-The `name` parameter is **still required** (not *optional*) because it doesn't have a default value. Still, `name` accepts `None` as the value:
-
-```Python
-say_hi(name=None) # This works, None is valid 🎉
-```
-
-The good news is, once you are on Python 3.10 you won't have to worry about that, as you will be able to simply use `|` to define unions of types:
-
-{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *}
-
-And then you won't have to worry about names like `Optional` and `Union`. 😎
-
-#### Generic types { #generic-types }
-
-These types that take type parameters in square brackets are called **Generic types** or **Generics**, for example:
-
-//// tab | Python 3.10+
-
-You can use the same builtin types as generics (with square brackets and types inside):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-And the same as with previous Python versions, from the `typing` module:
-
-* `Union`
-* `Optional`
-* ...and others.
-
-In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the vertical bar (`|`) to declare unions of types, that's a lot better and simpler.
-
-////
-
-//// tab | Python 3.9+
-
-You can use the same builtin types as generics (with square brackets and types inside):
-
-* `list`
-* `tuple`
-* `set`
-* `dict`
-
-And generics from the `typing` module:
-
-* `Union`
-* `Optional`
-* ...and others.
-
-////
+Using `str | None` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too.
### Classes as types { #classes-as-types }
@@ -403,17 +293,11 @@ To learn more about Required Optional fields.
-
-///
-
## Type Hints with Metadata Annotations { #type-hints-with-metadata-annotations }
Python also has a feature that allows putting **additional metadata** in these type hints using `Annotated`.
-Since Python 3.9, `Annotated` is a part of the standard library, so you can import it from `typing`.
+You can import `Annotated` from `typing`.
{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *}
diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml
index 60d2f977e5..66ad67e9d0 100644
--- a/docs/en/mkdocs.yml
+++ b/docs/en/mkdocs.yml
@@ -191,6 +191,7 @@ nav:
- advanced/openapi-webhooks.md
- advanced/wsgi.md
- advanced/generate-clients.md
+ - advanced/advanced-python-types.md
- fastapi-cli.md
- Deployment:
- deployment/index.md