You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
What's the problem with the example above? With more data types that can be passed into parameter `data`, the function definition
353
+
becomes unreadable. We have two solutions for this issue. The first one is to use `Any` type that is a wildcard type:
354
+
355
+
```python
356
+
from typing import Any
357
+
358
+
359
+
defprocess_data(data: Any) -> np.ndarray:
360
+
...
361
+
362
+
```
363
+
364
+
The second solution is to think what is a high level representation of passed data types. The examples are:
365
+
366
+
-`Sequence` – we can use it to describe a variable that is a sequence of elements. Sequential are `list`, `tuple`, `range` and `str`.
367
+
-`Iterable` – we can use it to describe a variable that is iterable. Iterables are `list`, `tuple`, `range`, `str`, `dict` and `set`.
368
+
-`Mapping` – we can use it to describe a variable that is a mapping. Mappings are `dict` and `defaultdict`.
369
+
-`Hashable` – we can use it to describe a variable that is hashable. Hashables are `int`, `float`, `str`, `tuple` and `frozenset`.
370
+
-`Collection` - we can use it to describe a variable that is a collection. Collections are `list`, `tuple`, `range`, `str`, `dict`, `set` and `frozenset`.
371
+
372
+
Thus, the function could look like:
373
+
374
+
```python
375
+
from typing import Iterable
376
+
377
+
378
+
defprocess_data(data: Iterable) -> np.ndarray:
379
+
...
380
+
381
+
```
382
+
383
+
### Type hints: special typing objects
384
+
385
+
The `typing` module provides us with more objects that we can use to describe our variables.
386
+
Interesting object is `Callable` that we can use to describe a variable that is a function. Usually,
387
+
when we write decorators or wrappers, we use `Callable` type. The example in the context of `pystiche` package:
388
+
389
+
```python
390
+
from typing import Callable
391
+
392
+
393
+
def_deprecate(fn: Callable) -> Callable:
394
+
...
395
+
396
+
397
+
```
398
+
399
+
The `Callable`can be used as a single word or as a word with square brackets that has two parameters: `Callable[[arg1, arg2], return_type]`.
400
+
The first parameter is a list of arguments, the second one is a return type.
401
+
402
+
There is one more important case around type hints. Sometimes we want to describe a variable that comes from within
403
+
our package. Usually we can do it without any problems:
404
+
405
+
```python
406
+
from my_package import my_data_class
407
+
408
+
409
+
defmy_function(data: my_data_class) -> None:
410
+
...
411
+
412
+
```
413
+
414
+
and it will work fine. But we may encounter *circual imports* that are a problem. What is a *circular import*?
415
+
It is a case when we want to import module B into module A but module A is already imported into module B.
416
+
It seems like we are importing the same module twice into itself. The issue is rare when we program without type
417
+
hinting. However, with type hints it could be tedious.
418
+
419
+
Thus, if you encounter this error:
420
+
421
+
```python
422
+
from my_package import my_data_class
423
+
424
+
425
+
defmy_function(data: my_data_class) -> None:
426
+
...
427
+
428
+
```
429
+
430
+
```shell
431
+
ImportError: cannot import name 'my_data_class' from partially initialized module 'my_package' (most likely due to a circular import) (/home/user/my_package/__init__.py)
432
+
```
433
+
434
+
Then you should use `typing.TYPE_CHECKING` clause to avoid circular imports. The example:
435
+
436
+
```python
437
+
from__future__import annotations
438
+
from typing importTYPE_CHECKING
439
+
440
+
ifTYPE_CHECKING:
441
+
from my_package import my_data_class
442
+
443
+
444
+
defmy_function(data: my_data_class) -> None:
445
+
...
446
+
447
+
```
448
+
449
+
Unfortunately, the solution is dirty because we have to
450
+
use `if TYPE_CHECKING` clause and `from __future__ import annotations` import to make it work! Type hinting
451
+
is not only roses and butterflies!
452
+
453
+
### Type hinting: final remarks and tools
454
+
455
+
There are few tools designed for static type checking. The most popular one is [`mypy`](https://mypy.readthedocs.io/en/stable/).
456
+
It's a good idea to add it to your Continuous Integration (CI) pipeline.
457
+
Other tools are integrated with popular IDEs like `PyCharm` or `VSCode`, most of them are based on `mypy` logic.
458
+
459
+
At this point, we have a good understanding of type hints and how to use them in our code. There is one last thing to
460
+
remember. **Type hints are not required in all our functions and we can introduce those gradually, it won't damage our code**.
461
+
It is very convenient way of using this extraordinary feature!
0 commit comments