Boss < It looks like this function may return 3 types... Isn't that too much?
You < I see. That could be a bad design. Let me fix it.
Boss < Sure, please.
defneed_new_post() -> None | False | str:if ...: retrun Noneelif ...: retrun Falseelse: return post_id # this is str
Let's start with function definitions
After the arguments, write colon and type
Before the colon at the end of the function definition, write an arrow and type
Using built-in types
bool, bytes, float, int, str
you don't need to do anything to use them.
None: used for functions that return nothing.
Escaping from type puzzles
Any Can hold instances of any type.
It's better not to use it.
Import and use from typing when necessary.
from typing importAny
unknown_variable: Any
Since 3.9: Generics in standard Collections
dict, frozenset, list, set, tuple
Collections can be written with [] for the type inside.
3.9 and later only
3.7, 3.8 write from __future__ import annotaions (see below)
3.6: import annotations starting with uppercase letters from typing (next section)
It's better to use a collection with a few methods to increase portability.
The following figure shows the relationship.
The further to the left you go, the fewer methods it has.
To the right, the more methods it has.
It's a good idea to look at the methods used in your functions.
Choose the types on the left side of this diagram as much as possible.
Great method inheritance tree
The difference between tuple and others Sequences
Tuples are fixed up to the length information
Specify the type for the number of elements
Or you can mix types, such as tuple[int, str, float].
A sequence, such as a list, has the same constraint for all elements in the element
Can be used regardless of the length of the sequence by setting only one element.
A little more advanced: Generics type
Union (Mager type)
Union: merged type, can be represented by | since 3.10
You've probably seen it on Haskell or TypeScript
from __future__ import annotations
defsquare(number: int | float) -> int | float:return number ** 2
Union objects can be tested for equality with other union objects.
(int | str) | float == int | str | float# Unions of unions are flattenedint | str | int == int | str# Redundant types are removedint | str == str | int# the order is ignoredint | str == typing.Union[int, str] # Compatible with typing.Union
Optional type
Shorthand, Optional[T] is equivalent to Union with None.
Behaves just like Union: T | None
If you use it in a function return value or something, it will propagate, so be careful how you use it.
from typing importOptional
age: Optional[int]
age = 17
age = None# This is also valid
Avoid using Optional as much as possible
Optional is useful but causes code bloat.
defget_content() -> str | None:
r = request.get("https://example.com")
if r.status_code != 200: # This is the guard (early return)
logging.warning("HTTP response is %d!", r.status_code)
returnNonereturn r.text
When you use the up function, you might write another guard and return None.
As a result, we need to write a guard to the previous method, which reduces readability.
In this case
It would be cleaner to raise a raise RuntimeError.
The cost of raising exceptions in Python is (relatively) low
The performance would be satisfactory.
The lack of null-safe methods in Python is also a factor
But if there were such methods, they would be abused.
Null-safe means a method that does not raise an exception when passed None.
Callable (callable object)
It can be used when writing functions that take a function as an argument, such as decorator functions.
We consider global variables without type hints to be type aliases.
This tends to cause problems with forwarding references, scoping, etc.
So, we're going to make it possible to explicitly define type aliases.
You can still define type aliases implicitly.
Approach
Add a new typing.TypeAlias
Write a variable of type alias type like T: TypeAlias = int
Variables defined at the global level are considered type aliases.
Using ForwardReference, you can write T: TypeAlias = "int".
Example
x = 1# untyped global expression
x: int = 1# typed global expression
x = int# untyped global expression
x: Type[int] = int# typed global expression
x: TypeAlias = int# type alias
x: TypeAlias = “MyClass” # type alias
PEP 647: User-Defined Type Guards
Motivation
Type checker tools use a technique called type narrowing to determine the type of information.
In this example, the if statement and is None are used to automatically narrow down the type.
deffunc(val: Optional[str]):# "is None" type guardif val isnotNone: # Type of val is narrowed to strpasselse: # Type of val is narrowed to Nonepass
However, that will not work as intended if the user function is used.
defis_str_list(val: List[object]) -> bool:"""Determines whether all objects in the list are strings"""returnall(isinstance(x, str) for x in val)
deffunc1(val: List[object]):if is_str_list(val): print(" ".join(val)) # Error: invalid type
TypeGuard allows you to define user-defined type guards via the new typing.
By using user-defined type guards, it is easier to get support for type narrowing.
from typing import TypeGuard
defis_str_list(val: List[object]) -> TypeGuard[List[str]]:returnall(isinstance(x, str) for x in val) # this is vaild!
We look forward to seeing you again at PyCon JP 2021!
Hi, let's start. my talk title is ...
If you have any questions or comments, please write here. I'd love to hear from you during the talk.
Nice to meet you. Hello EuroPython!
let me introduce myself.
In addition to my work, I'm also involved at the PyCon JP Association
this is today's topic.
My motivation for talking is to get the word out in a coherent way.
It's been five years (Python 3.5, at 2015) since typing appeared
OK, Let's take a look at how to actually start Typing!
First, let's look at what typing can do for you.
this is a minimal example.
we don't know the type of return value...
if try to pass int to the function, it'll occur an error
How about this case? It looks like s is str, a return value is also str.
and, the editor can tell the argument is wrong
and more, there are advantages to code review.
w/o type hint, reviewer, can't know the return type from reading the definition.
As a result, many people may have had this experience.
However, Type hint may make the review process more smooth.
now, Let's take a look at the types that can be used in practice.
If you want to escape from complex type puzzles, you can use any. this is the final resort.
because of the way of writing described before.
There are many types in `collections.abc.`
Although it's unlikely that you will use these in a fine-grained way, It's better to choose a collection with as few methods as possible to increase portability.
The following figure shows the relationship between `collections.abc` and a sequence of built-in types defined by method inclusion rather than implementation inheritance.
It is a good idea to look at the methods used in your functions and choose the types on the left side of this diagram as much as possible.
The further to the left you go, the fewer methods it has.
To the right, the more methods it has.
For example, if you just want to loop over a sequence of arguments in a function, you can use collections.abc.Iterable. Iterable. If you need random access, use Sequence. If you need to change the value, use a type with Mutable.
Or, if you simply specify list as the argument type, you will not be able to pass set or dict. In particular, it is better not to set concrete types (list, tuple, dictionary, set) just because you are familiar with them. However, I think it is easier to understand using these concrete types, so you may want to first apply these concrete types. After you confirm that you can use fewer operators and methods, you may want to gradually move to the left side of the types.
Next, there are few advanced types.
at first is union, merged type. top half code is an Example A function that accepts both integers and floats bottom one is Union objects can be tested for equality with other union objects.
A generic type is typically declared by inheriting from an instantiation of this class with one or more type variables.
A generic type is typically declared by inheriting from an instantiation of this class with one or more type variables.
Let me give you one more promotion about PyCon JP 2021
PyCon JP 2020 was held online. The photo is from the toast of the party.
there are Website, blog, and Twitter links.
The date of the conference is Oct. 15,16.
We haven't decided what we will do for sprints and training yet.
Now, CfP is over. We are currently in the process of review and adoption.
The venue could be both online or hybrid.
this is an updated overview recently.
Let's talk about dunder future, which has come up many times before.
Modules and methods with two underscores at either end are pronounced dunder.
next topic is new features in python3.10, will be released Nov. this year there is a difficult feature. I'm not sure I can explain it well, either.
The type checker assumes that the first argument matches the type specified in TypeGuard, if the function returns True. In the above example, data that passes is_str_list() will be treated as List[str].
Note that if this function returns False, type narrowing will not be performed.
In the following example, if is_two_element_tuple(...) block, the type is narrowed to Tuple[str, str] as a result of type narrowing, while in the else block, the type remains unchanged.