📜 ⬆️ ⬇️

Python 3 features worthy of being used

Many programmers have begun to move from the second version of Python to the third due to the fact that very soon support for Python 2 will be discontinued . The author of the article, the translation of which we publish, notes that the main volume of Python 3 code that he has ever seen looks like code with brackets written in Python 2. According to him, he himself sins with something similar . Here he gives examples of some great features available only to those using Python 3. He hopes that these features will make life easier for those who know about them.



All the examples in this material are written using Python 3.7. In the description of each opportunity there is information about the minimum version of Python necessary for its use.

Format Strings (3.6+)


Without strings, it is difficult to write something useful in any programming language. But for effective work with strings the developer needs convenient tools. Such tools that allow you to operate with complex structures, without losing mental equilibrium. Most Python developers use the format method:
')
 user = "Jane Doe" action = "buy" log_message = 'User {} has logged in and did an action {}.'.format( user, action ) print(log_message) # User Jane Doe has logged in and did an action buy. 

Python 3, along with the format method, supports format strings ( f-strings , f-strings). They are a flexible tool for performing various string manipulations. Here is what the previous example looks like, rewritten using format strings:

 user = "Jane Doe" action = "buy" log_message = f'User {user} has logged in and did an action {action}.' print(log_message) # User Jane Doe has logged in and did an action buy. 

Pathlib module (3.4+)


Format strings are a great technology, but special tools have been created to work with some strings, like file paths, which greatly simplify manipulations with them. Python 3 has a pathlib module, which is a handy abstraction for working with file paths. If you are not yet sure of the usefulness of this module for solving your problems, take a look at this material.

 from pathlib import Path root = Path('post_sub_folder') print(root) # post_sub_folder path = root / 'happy_user' #    print(path.resolve()) # /home/weenkus/Workspace/Projects/DataWhatNow-Codes/how_your_python3_should_look_like/post_sub_folder/happy_user 

Type annotations (3.5+)


What is better - static or dynamic typing? Perhaps, almost every programmer has his own answer to this difficult question. I leave it to the readers to decide exactly how they typify their programs. But I think it would be useful for everyone to at least know that Python 3 supports type annotations .

 def sentence_has_animal(sentence: str) -> bool: return "animal" in sentence sentence_has_animal("Donald had a farm without animals") # True 

Enumerations (3.4+)


Python 3 supports, thanks to the Enum class, a simple mechanism for working with enumerations . Enumerations are useful for storing lists of constants. Constants, otherwise, are randomly scattered in the code.

 from enum import Enum, auto class Monster(Enum):   ZOMBIE = auto()   WARRIOR = auto()   BEAR = auto()  print(Monster.ZOMBIE) # Monster.ZOMBIE 

From the Python 3 documentation , you can learn that an enumeration is a set of symbolic names (members) associated with unique, immutable values. Members of one enumeration can be compared for identity. Enumerations can be bypassed.

 for monster in Monster:   print(monster) # Monster.ZOMBIE # Monster.WARRIOR # Monster.BEAR 

Built-in LRU cache (3.2+)


Nowadays, caching mechanisms are used in almost all software and hardware systems. Python 3 greatly simplifies caching thanks to the lru_cache decorator, which implements the LRU caching algorithm ( Least Recently Used ).

Below is a function that calculates Fibonacci numbers. This function is forced to perform the same operations many times during recursive calls. As a result, it turns out that its performance can be improved by caching.

 import time def fib(number: int) -> int:   if number == 0: return 0   if number == 1: return 1     return fib(number-1) + fib(number-2) start = time.time() fib(40) print(f'Duration: {time.time() - start}s') # Duration: 30.684099674224854s 

Now we use lru_cache to optimize this function (this optimization technique is called memoization ). As a result, the execution time of the function, which was previously measured in seconds, is now measured in nanoseconds.

 from functools import lru_cache @lru_cache(maxsize=512) def fib_memoization(number: int) -> int:   if number == 0: return 0   if number == 1: return 1     return fib_memoization(number-1) + fib_memoization(number-2) start = time.time() fib_memoization(40) print(f'Duration: {time.time() - start}s') # Duration: 6.866455078125e-05s 

Unpacking Iterated Objects (3.0+)


When unpacking the objects to be iterated, you can use variables with an asterisk in front of their names. All that does not fall into other variables falls into such variables. So, in the following example, the first and last values ​​from the list formed by the range(5) command fall into the variables head and tail . Everything that is between the first and the last value falls into the body variable.

 head, *body, tail = range(5) print(head, body, tail) # 0 [1, 2, 3] 4 py, filename, *cmds = "python3.7 script.py -n 5 -l 15".split() print(py) print(filename) print(cmds) # python3.7 # script.py # ['-n', '5', '-l', '15'] first, _, third, *_ = range(10) print(first, third) # 0 2 

Data Classes (3.7+)


In Python 3, data classes have appeared. They give the programmer a great deal of freedom. They can be used to reduce the amount of template code. The fact is that the dataclass decorator automatically generates special methods such as __init__() and __repr__() . In the official text of the corresponding sentence, they are described as “mutable named tuples with default values”. Here is an example of creating a class without using the dataclass decorator:

 class Armor:     def __init__(self, armor: float, description: str, level: int = 1):       self.armor = armor       self.level = level       self.description = description                  def power(self) -> float:       return self.armor * self.level  armor = Armor(5.2, "Common armor.", 2) armor.power() # 10.4 print(armor) # <__main__.Armor object at 0x7fc4800e2cf8> 

Here is the same, but already written using dataclass :

 from dataclasses import dataclass @dataclass class Armor:   armor: float   description: str   level: int = 1     def power(self) -> float:       return self.armor * self.level  armor = Armor(5.2, "Common armor.", 2) armor.power() # 10.4 print(armor) # Armor(armor=5.2, description='Common armor.', level=2) 

Support for package folders without __init__.py (3.3+)


One way of structuring Python code is to use packages (packages are placed in folders that have a __init__.py file). Here is an example from the official documentation:

 sound/                                 __init__.py                 sound     formats/                                   __init__.py             wavread.py             wavwrite.py             aiffread.py             aiffwrite.py             auread.py             auwrite.py             ...     effects/                                  __init__.py             echo.py             surround.py             reverse.py             ...     filters/                                 __init__.py             equalizer.py             vocoder.py             karaoke.py             ... 

When using Python 2, each of the folders mentioned in the example should have the file __init__.py . Thanks to this file, the folder is perceived as a Python package. In Python 3, with the advent of the Implicit Namespace Packages feature, the presence of such files in folders is no longer mandatory.

 sound/                                 __init__.py                 sound     formats/                                   wavread.py             wavwrite.py             aiffread.py             aiffwrite.py             auread.py             auwrite.py             ...     effects/                                  echo.py             surround.py             reverse.py             ...     filters/                                 equalizer.py             vocoder.py             karaoke.py             ... 

It should be noted that in fact everything is not so simple. Namely, in accordance with this official specification, the __init__.py file is still needed for regular packages. If you remove it from the folder, the package becomes a so-called namespace package , to which additional restrictions apply.

Results


Not all interesting features of Python 3 are considered in this material, but we hope that you have found something useful here. Code examples can be found in this repository.

Dear readers! What features of Python 3 would you add to the list here?

Source: https://habr.com/ru/post/452564/


All Articles