Python >> Tutoriel Python >  >> Python

Quoi de neuf dans Python 3.9

Chaque année, des bénévoles du monde entier travaillent à l'amélioration du langage Python. Le Python 3.9 officiel version est sortie le 5 octobre 2020. Cette version est une amélioration apportée à Python 3.8 . L'explication officielle et détaillée de ces améliorations est disponible sur le site Web de Python. Cet article de blog tente d'expliquer ces améliorations à un débutant Python .

Plongeons-nous dans les nouvelles fonctionnalités ajoutées à Python 3.9 .

Remarque :Tous les exemples Python de cet article sont Python 3.9.0b5 vérifié.

Fonctionnalité 1 : Opérateurs syndicaux pour simplifier les mises à jour de Dict (PEP 584)

Le dictionnaire est une structure de données de base intégrée au langage Python. C'est un ensemble de paires clé-valeur. C'est une règle que la clé soit une valeur hachable et donc unique, dans un dictionnaire.

Le lecteur connaît probablement plusieurs méthodes pour fusionner des dictionnaires. Deux méthodes couramment utilisées sont présentées ci-dessous.

$ python
Python 3.9.0b5 (default, Oct 19 2020, 11:11:59) 
>>> 
>>> ## Company1 and Company2 are going to be merged. Payroll has to
>>> ## merge the employee salary data.
>>> company1 = {
...     "Alice" : 200,
...     "Bob" : 110,
...     "Ryan" : 100,
...     "Dup" : 60
... }
>>> company2 = {
...     "Alex" : 80,
...     "John" : 90,
...     "Steve" : 102,
...     "Dup" : 40
... }   
>>> 
>>> ## Note, duplicate entries of company2 will override those of company1.
>>> merged1 = {**company1, **company2}
>>> merged1
{'Alice': 200, 'Bob': 110, 'Ryan': 100, 'Dup': 40, 'Alex': 80, 'John': 90, 'Steve': 102}
>>> 
>>> ## Note, duplicate entries of company1 will override those of company2.
>>> merged2 = {**company2, **company1}
>>> merged2
{'Alex': 80, 'John': 90, 'Steve': 102, 'Dup': 60, 'Alice': 200, 'Bob': 110, 'Ryan': 100}
>>> 
>>> ## Note, duplicate entries of company2 will override those of company1.
>>> ## Here the merged3 dictionary is operated in-place.
>>> merged3 = company1.copy()
>>> for key, value in company2.items():
...     merged3[key] = value
... 
>>> merged3
{'Alice': 200, 'Bob': 110, 'Ryan': 100, 'Dup': 40, 'Alex': 80, 'John': 90, 'Steve': 102}
>>>
>>> ## Note, duplicate entries of company1 will override those of company2.
>>> ## Here the merged4 dictionary is operated in-place. 
>>> merged4 = company2.copy()
>>> for key, value in company1.items():
...     merged4[key] = value
... 
>>> merged4
{'Alex': 80, 'John': 90, 'Steve': 102, 'Dup': 60, 'Alice': 200, 'Bob': 110, 'Ryan': 100}

Python 3.9 (PEP 584) introduit deux nouvelles façons élégantes de fusionner des dictionnaires. Le syndicat (| ) L'opérateur fusionne deux dictionnaires. Alors que l'union en place (|= ) mettra à jour le dictionnaire en place.

Considérez les exemples suivants qui utilisent les mêmes dictionnaires que ceux indiqués ci-dessus.

$ python
Python 3.9.0b5 (default, Oct 19 2020, 11:11:59) 
>>> 
>>> ## Company1 and Company2 are going to be merged. Payroll has to
>>> ## merge the employee salary data.
>>> company1 = {
...     "Alice" : 200,
...     "Bob" : 110,
...     "Ryan" : 100,
...     "Dup" : 60
... }
>>> company2 = {
...     "Alex" : 80,
...     "John" : 90,
...     "Steve" : 102,
...     "Dup" : 40
... }   
>>> 
>>> ## Note, duplicate entries of company2 will override those of company1.
>>> ## Note the use of the union(|) Dictionary operator.
>>> merged1 = company1 | company2
>>> merged1
{'Alice': 200, 'Bob': 110, 'Ryan': 100, 'Dup': 40, 'Alex': 80, 'John': 90, 'Steve': 102}
>>> 
>>> ## Note, duplicate entries of company1 will override those of company2.
>>> merged2 = company2 | company1
>>> merged2
{'Alex': 80, 'John': 90, 'Steve': 102, 'Dup': 60, 'Alice': 200, 'Bob': 110, 'Ryan': 100}
>>> 
>>> ## Note, duplicate entries of company2 will override those of company1.
>>> ## Note the use of the in-place union(|=) Dictionary operator. Here the
>>> ## merged3 dictionary is operated in-place.
>>> merged3 = company1.copy()
>>> merged3 |= company2
>>> merged3
{'Alice': 200, 'Bob': 110, 'Ryan': 100, 'Dup': 40, 'Alex': 80, 'John': 90, 'Steve': 102}
>>> 
>>> ## Note, duplicate entries of company1 will override those of company2.
>>> ## Here the merged4 dictionary is operated in-place.
>>> merged4 = company2.copy()
>>> merged4 |= company1
>>> merged4
{'Alex': 80, 'John': 90, 'Steve': 102, 'Dup': 60, 'Alice': 200, 'Bob': 110, 'Ryan': 100}
>>> 

Fonctionnalité 2 :Conseils de type intuitifs pour les génériques (PEP 585)

En pré-Python 3.9, il était un peu fastidieux d'ajouter des indications de type pour les types génériques comme les listes ou les dictionnaires. De tels types génériques nécessitaient une hiérarchie parallèle d'indications de type. Il fallait utiliser la dactylographie module comme indiqué dans les exemples suivants. C'était un moyen détourné de fournir des indications de type.

## typehints.py
from typing import List, Dict

## numbers1 is appropriately a list of float values as is specified
## in the type hint 'List[float]' 
numbers1: List[float] = [2.9, 3.9, 4.9]

## dict1 is a dictionary with keys specified by strings and values
## specified by integers. This is specified by the type hint
## 'Dict[str, int]
dict1: Dict[str, int] = {"one": 1, "two": 2}

print(__annotations__)
$ python -V
Python 3.8.5
$ python typehints.py
{'numbers1': typing.List[float], 'dict1': typing.Dict[str, int]}

Python 3.9 (PEP 585) a rendu plus simple et directe la spécification d'indications de type pour les types génériques. L'exemple suivant montre comment !

## typehints.py

## numbers1 is appropriately a list of float values as is specified
## in the type hint 'list[float]' 
numbers1: list[float] = [2.9, 3.9, 4.9]

## dict1 is a dictionary with keys specified by strings and values
## specified by integers. This is specified by the type hint
## 'dict[str, int]
dict1: dict[str, int] = {"one": 1, "two": 2}

print(__annotations__)

Notez l'utilisation de list[] au lieu de List[] ou dict[] au lieu de Dict[] . Il n'est pas nécessaire de se souvenir d'inclure la dactylographie module plus. Il n'y a plus de hiérarchie parallèle non plus. Les conseils de type eux-mêmes sont plus propres et intuitifs.

$ python typehints.py 
{'numbers1': list[float], 'dict1': dict[str, int]}

Fonctionnalité 3 :Flexibilité du décorateur (PEP 614)

Pré-Python 3.9 , exigeait qu'un décorateur soit un objet nommé et appelable, tel que des objets de fonction ou de classe. La PEP 614 assouplit cette grammaire ou syntaxe pour permettre à un décorateur d'être n'importe quelle expression appelable. L'ancienne syntaxe de décorateur n'était généralement pas considérée comme limitative dans la communauté Python. Le principal cas d'utilisation motivant pour l'amélioration de la PEP 614 concerne les rappels dans les cadres GUI. L'exemple suivant montre la limitation et la solution de contournement pour Pre-Python 3.9 .

## deco.py
from functools import wraps as func_wrap

"""
  Imagine that the user wants to apply 3 different decorators to a
  specified function(such as decorate_this_func(), below). Each 
  decorator is chosen based on the user's input. Pre-Python3.9, the
  user would have to do the following...
"""

## This is the first decorator. It prints the strings "prefix1" and
## "suffix1", before and after the user provided string, respectively.
## This user provided string is returned by the decorated function i.e.
## decorate_this_func().
def decorator1(func):
    ## Note here that the decorator func_wrap() is used when one needs
    ## to use the arguments which have been originally provided to the
    ## decorated function (aka decorate_this_func()) 
    @func_wrap(func)
    def decorator1_does_this(*args, **kwargs):
        ## The following 3 lines are turned into a one-liner, below.
        ## val1 = 'prefix {0} suffix'
        ## val2 = func(*args, **kwargs)
        ## val3 = val1.format(val2)
        ## return val3
        return 'prefix1 {0} suffix1'.format(func(*args, **kwargs))
    return decorator1_does_this

## This is the second decorator. It prints the strings "prefix2" and
## "suffix2", before and after the user provided string, respectively.
## This user provided string is returned by the decorated function i.e.
## decorate_this_func().
def decorator2(func):
    @func_wrap(func)
    def decorator2_does_this(*args, **kwargs):
        return 'prefix2 {0} suffix2'.format(func(*args, **kwargs))
    return decorator2_does_this

## This is the third decorator. It prints the strings "prefix3" and
## "suffix3", before and after the user provided string, respectively.
## This user provided string is returned by the decorated function i.e.
## decorate_this_func().
def decorator3(func):
    @func_wrap(func)
    def decorator3_does_this(*args, **kwargs):
        return 'prefix3 {0} suffix3'.format(func(*args, **kwargs))
    return decorator3_does_this

## The DECORATOR_DICT associates a string key with a decorator function.
DECORATOR_DICT = {"dec1": decorator1, "dec2": decorator2, "dec3": decorator3}

## The user is asked for input. This allows them to choose the
## appropriate decorator. Note the user provides a string key.
chosen_decorator_key = input(f"Choose your decorator key ({', '.join(DECORATOR_DICT)}): ")

## Pre-Python3.9, one could only use function or class objects to specify
## decorators for a function(i.e. the decoratee aka function to be
## decorated). To have the ability to choose multiple decorators, the
## user would have to apply the following workaround, to get a handle
## for the decorator function or class object.
HANDLE_TO_CHOSEN_DECORATOR = DECORATOR_DICT[chosen_decorator_key]
@HANDLE_TO_CHOSEN_DECORATOR
def decorate_this_func(str_arg):
    return 'Use {0} to decorate this sentence'.format(str_arg)

## key_string is simply used to show how arguments can be passed thru 
## decorators.
key_string = chosen_decorator_key
print(decorate_this_func(key_string))

"""
The result is as follows...
$ python -V
Python 3.8.5 
$ python deco.py
Choose your decorator key (dec1, dec2, dec3): dec1
prefix1 Use dec1 to decorate this sentence suffix1
$ python deco.py
Choose your decorator key (dec1, dec2, dec3): dec2
prefix2 Use dec2 to decorate this sentence suffix2
$ python deco.py
Choose your decorator key (dec1, dec2, dec3): dec3
prefix3 Use dec3 to decorate this sentence suffix3
$ 
"""

La solution de contournement présentée ci-dessus est fastidieuse mais pas vraiment douloureuse. L'utilisateur doit extraire et fournir indirectement la poignée du décorateur. Cependant, l'amélioration PEP 614 rend la solution très simple et élégante. L'utilisateur utilise maintenant un handle vers le dictionnaire décorateur lui-même. L'utilisateur fournit une clé de décorateur depuis la console, en entrée. Cette clé extrait le handle de fonction spécifique du décorateur, à partir du dictionnaire du décorateur. L'exemple suivant montre l'utilisation de l'amélioration.

## deco.py
from functools import wraps as func_wrap

"""
  Imagine again that the user wants to apply 3 different decorators to a
  specified function(such as decorate_this_func(), below). Each 
  decorator is chosen based on the user's input. In Python3.9, the
  user does the following...
"""

## This is the first decorator. It prints the strings "prefix1" and
## "suffix1", before and after the user provided string, respectively.
## This user provided string is returned by the decorated function i.e.
## decorate_this_func().
def decorator1(func):
    ## Note here that the decorator func_wrap() is used when one needs
    ## to use the arguments which have been originally provided to the
    ## decorated function (aka decorate_this_func()) 
    @func_wrap(func)
    def decorator1_does_this(*args, **kwargs):
        return 'prefix1 {0} suffix1'.format(func(*args, **kwargs))
    return decorator1_does_this

## This is the second decorator. It prints the strings "prefix2" and
## "suffix2", before and after the user provided string, respectively.
## This user provided string is returned by the decorated function i.e.
## decorate_this_func().
def decorator2(func):
    @func_wrap(func)
    def decorator2_does_this(*args, **kwargs):
        return 'prefix2 {0} suffix2'.format(func(*args, **kwargs))
    return decorator2_does_this

## This is the third decorator. It prints the strings "prefix3" and
## "suffix3", before and after the user provided string, respectively.
## This user provided string is returned by the decorated function i.e.
## decorate_this_func().
def decorator3(func):
    @func_wrap(func)
    def decorator3_does_this(*args, **kwargs):
        return 'prefix3 {0} suffix3'.format(func(*args, **kwargs))
    return decorator3_does_this

## The DECORATOR_DICT associates a string key with a decorator function.
DECORATOR_DICT = {"dec1": decorator1, "dec2": decorator2, "dec3": decorator3}

## The user is asked for input. This allows them to choose the
## appropriate decorator. Note the user provides a string key.
chosen_decorator_key = input(f"Choose your decorator key ({', '.join(DECORATOR_DICT)}): ")

## In Python3.9(PEP-614), the decorator syntax has been loosened up
## to mean any function or class objects or expression can be used
## to specify decorators for a function(i.e. the decoratee,
## aka function to be decorated). This is shown below. Note how the
## user can now use the result of the dictionary search directly,
## as a decorator.
@DECORATOR_DICT[chosen_decorator_key]
def decorate_this_func(str_arg):
    return 'Use {0} to decorate this sentence'.format(str_arg)

## key_string is simply used to show how arguments can be passed thru 
## decorators.
key_string = chosen_decorator_key
print(decorate_this_func(key_string))

"""
The result is as follows...

$ python -V
Python 3.9.0b5
$ python deco.py
Choose your decorator key (dec1, dec2, dec3): dec1
prefix1 Use dec1 to decorate this sentence suffix1
$ python deco.py
Choose your decorator key (dec1, dec2, dec3): dec2
prefix2 Use dec2 to decorate this sentence suffix2
$ python deco.py
Choose your decorator key (dec1, dec2, dec3): dec3
prefix3 Use dec3 to decorate this sentence suffix3
$
“””

Fonctionnalité 4 :Suppression des préfixes et des suffixes pour les objets chaîne (PEP-616)

PEP-616  a ajouté le removeprefix() et removesuffix() méthodes aux divers objets de chaîne. Il s'agit d'une amélioration par rapport au lstrip() et rstrip() méthodes. Le removeprefix() la méthode supprime la sous-chaîne spécifiée du préfixe de l'objet chaîne. Le removesuffix() la méthode supprime la sous-chaîne spécifiée du suffixe de l'objet chaîne. Prenons les exemples suivants :

$ python
Python 3.9.0b5 (default, Oct 19 2020, 11:11:59) 
>>> 
>>> ## This example shows how to remove a Prefix from a string object.
>>> the_bigger_string1 = "Remove this Prefix. Keep this side1."
>>> print(the_bigger_string1)
Remove this Prefix. Keep this side1.
>>> 
>>> ## Now Remove the Prefix
>>> remove_prefix = the_bigger_string1.removeprefix("Remove this Prefix. ")
>>> print(remove_prefix)
Keep this side1.
>>>
>>>
>>> ## This example shows how to remove a Prefix from a string object.
>>> the_bigger_string2 = "Keep this side2. Remove the Suffix."
>>> print(the_bigger_string2)
Keep this side2. Remove the Suffix.
>>>
>>> 
>>> ## Now Remove the Suffix
>>> remove_suffix = the_bigger_string2.removesuffix(" Remove the Suffix.")
>>> print(remove_suffix)
Keep this side2.
>>> 

Fonctionnalité 5 :Conseils de type annotés pour les fonctions et les variables (PEP-593)

Le concept de fonction et variables annotations ont été introduits dans Python 3.0. Au début, ces annotations servaient de documentation et d'indices au lecteur.

$ python
Python 3.8.5
>>> 
>>> def heartrate(beats: "Total Heart-Beats as int", time: "Total time in seconds as int") -> "Beats per minute as int":
...     """Calculate and return the Heart-Rate as beats-per-minute(bpm)."""
...     mins = time/60 
...     hr = beats/mins 
...     return hr
... 
>>> 
>>> heartrate.__annotations__
{'beats': 'Total Heart-Beats as int', 'time': 'Total time in seconds as int', 'return': 'Beats per minute as int'}
>>> 
>>> heartrate(20,20)
60.0
>>> heartrate(140,120)
70.0
>>> 

Remarque :La méthode heartrate() renvoie un nombre flottant. L'utilisateur avait l'intention d'obtenir un int. Python a joyeusement suivi et imprimé les résultats. Une erreur de type n'a jamais été signalée.

Puis PEP-484 est arrivé dans Python 3.5 et a proposé d'utiliser des annotations pour Type Hints . Cela a permis des outils tels que mypy pour taper les variables de vérification et les arguments de la fonction. Cependant, cette amélioration s'est révélée limitante. Les utilisateurs peuvent soit utiliser general-string-documentation ou type-hints et pas les deux.

Voici un rendu du code ci-dessus avec Type Hints au lieu de general-string-documentation.

>>> def heartrate(beats: int, time: int) -> int:
...     """Calculate and return the Heart-Rate as beats-per-minute(bpm)."""
...     mins = time/60
...     hr = beats/mins
...     return hr
... 
>>> 
>>> heartrate.__annotations__
{'beats': <class 'int'>, 'time': <class 'int'>, 'return': <class 'int'>}
>>> 
>>> heartrate(20,20)
60.0
>>> heartrate(140,120)
70.0
>>> 

Remarque :Encore une fois, la méthode heartrate() renvoie toujours un Flottant Numéro. L'utilisateur avait toujours l'intention d'obtenir un int. Python a joyeusement suivi et imprimé les résultats. Une erreur de type n'a jamais été signalée.

Voici ce que mypy a à dire sur le code ci-dessus :

$ cat annotate.py
# annotate.py
 
def heartrate(beats: int, time: int) -> int:
    """Calculate and return the Heart-Rate as beats-per-minute(bpm)."""
    mins = time/60
    hr = beats/mins
    return hr

$ mypy annotate.py
annotate.py:7: error: Incompatible return value type (got "float", expected "int")
Found 1 error in 1 file (checked 1 source file)

Oui, mypy utilise les conseils de type pour signaler une erreur pour la valeur de retour.

Remarque :monpy marquera la documentation de chaîne générale comme des erreurs. Ceci est illustré ci-dessous.

$ cat annotate1.py
# annotate1.py
 
def heartrate(beats: "Total Heart-Beats", time: "Total time in seconds") -> "Beats per minute":
    """Calculate and return the Heart-Rate as beats-per-minute(bpm)."""
    mins = time/60
    hr = beats/mins
    return hr

$ mypy annotate1.py
annotate1.py:3: error: Invalid type comment or annotation
Found 1 error in 1 file (checked 1 source file)

Donc pour Python 3.9 , PEP-593 a proposé la notion d'indications de type annotées (typing.Annotated). Cela permettait aux annotations de fonction et de variable de contenir à la fois des indications de type et une documentation de chaîne générale. En d'autres termes, il combinait les utilisations d'exécution (type-hints) et statique (general-string-documentation) des annotations. Un vérificateur de type tel que mypy ne se soucie que du premier argument de Annotated. L'interprétation du reste des métadonnées est laissée au lecteur (utilisateur).

Voici le code combiné ci-dessus - notez que mypy est maintenant satisfait de cela. Bien sûr, tout cela fonctionne maintenant dans le Python 3.9 environnement.

$ cat annotate.py
## annotate.py
from typing import Annotated

def heartrate(beats: Annotated[int, "Total Heart-Beats"], time: Annotated[int, "Total time in seconds"]) -> Annotated[int, "Beats per minute"]:
    """Calculate and return the Heart-Rate as beats-per-minute(bpm)."""
    mins = time/60
    hr = beats/mins
    return int(hr)

$ mypy annotate.py 
Success: no issues found in 1 source file

Remarque :La valeur de retour du heartrate() la méthode a été corrigée (c'est-à-dire return int(hr) ). La méthode renvoie correctement un int maintenant.

Voici comment le code s'exécute…

$ python
Python 3.9.0b5 
>>> 
>>> from typing import Annotated
>>> 
>>> def heartrate(beats: Annotated[int, "Total Heart-Beats"], time: Annotated[int, "Total time in seconds"]) -> Annotated[int, "Beats per minute"]:
...     """Calculate and return the Heart-Rate as beats-per-minute(bpm)."""
...     mins = time/60
...     hr = beats/mins
...     return int(hr)
... 
>>> 
>>> heartrate.__annotations__
{'beats': typing.Annotated[int, 'Total Heart-Beats'], 'time': typing.Annotated[int, 'Total time in seconds'], 'return': typing.Annotated[int, 'Beats per minute']}
>>> 
>>> from typing import get_type_hints
>>> 
>>> get_type_hints(heartrate)
{'beats': <class 'int'>, 'time': <class 'int'>, 'return': <class 'int'>}
>>> 
>>> get_type_hints(heartrate, include_extras=True)
{'beats': typing.Annotated[int, 'Total Heart-Beats'], 'time': typing.Annotated[int, 'Total time in seconds'], 'return': typing.Annotated[int, 'Beats per minute']}
>>> 
>>> heartrate(20,20)
60
>>> heartrate(140,120)
70
>>> 

Fonctionnalité 6 :Puissant analyseur Python (PEP-617)

Python 3.9 a réimplémenté l'analyseur python. L'analyseur PEG (Parsing Expression Grammar) remplace l'analyseur LL(1). C'est la fonctionnalité la plus cool que le lecteur ne remarquera pas dans sa vie quotidienne de codage. Guido Van Rossum, le créateur de Python, a trouvé que l'analyseur PEG était plus puissant que l'analyseur LL(1). Les analyseurs PEG n'avaient pas besoin de hacks spéciaux pour les cas difficiles. Les recherches de Guido ont conduit à l'implémentation de l'analyseur PEG (PEP-617) dans Python 3.9 .

Fonctionnalité 7 :Prise en charge améliorée du fuseau horaire (PEP-615)

La dateheure Le module de la bibliothèque standard de Python fournit un support étendu pour travailler avec les dates et les heures. Cependant, ce module ne prend en charge que l'UTC fuseau horaire. Tout autre fuseau horaire doit être dérivé et implémenté au-dessus de la classe de base abstraite tzinfo. La bibliothèque tierce dateutil est l'une de ces implémentations de fuseaux horaires. Python 3.9 ajoute une nouvelle bibliothèque standard zoneinfo (PEP-615). Cela rend le travail avec les fuseaux horaires très pratique. zoneinfo donne accès à la base de données des fuseaux horaires gérée par l'IANA (Internet Assigned Numbers Authority). On peut maintenant obtenir un objet décrivant n'importe quel fuseau horaire dans la base de données IANA en utilisant zoneinfo.
Considérez l'exemple suivant qui illustre une façon d'utiliser l'objet zoneinfo.

$ python
Python 3.9.0b5 (default, Oct 19 2020, 11:11:59) 
>>> 
>>> ## One can now make timezone–aware timestamps by passing 
>>> ## the  tzinfo or tz arguments to datetime functions:
>>> ## Note that the datetime object includes the timezone
>>> ## information. This is very useful to convert between timezones.
>>> 
>>> from datetime import datetime
>>> from zoneinfo import ZoneInfo
>>> ## Imagine that there are four friends and they want to setup a 
>>> ## meeting at a mutually reasonable time. Each of these four
>>> ## friends lives in different timezones. The US friend
>>> ## takes up the task of setting up this meeting. The following
>>> ## code illustrates how the ZoneInfo library is used to setup
>>> ## such a meeting.
>>> 
>>> ## The US friend uses the ZoneInfo library to find the
>>> ## Current time in each of the timezones. This gives the US
>>> ## friend a rough idea of the time differences in different 
>>> ## timezones.
>>> 
>>> ## Current time in the Vancouver(Canada) timezone.
>>> ca_friend = datetime.now(tz=ZoneInfo("America/Vancouver"))
>>> ca_friend
datetime.datetime(2020, 10, 21, 8, 10, 23, 212154, tzinfo=zoneinfo.ZoneInfo(key='America/Vancouver'))
>>> print(ca_friend)
2020-10-21 08:10:23.212154-07:00
>>> 
>>> ## Current time in the New York(USA) timezone.
>>> us_friend = datetime.now(tz=ZoneInfo("America/New_York"))
>>> us_friend
datetime.datetime(2020, 10, 21, 11, 10, 23, 215533, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))
>>> print(us_friend)
2020-10-21 11:10:23.215533-04:00
>>> 
>>> ## Current time in the Berlin(Germany) timezone.
>>> eu_friend = datetime.now(tz=ZoneInfo("Europe/Berlin"))
>>> eu_friend
datetime.datetime(2020, 10, 21, 17, 10, 23, 221999, tzinfo=zoneinfo.ZoneInfo(key='Europe/Berlin'))
>>> print(eu_friend)
2020-10-21 17:10:23.221999+02:00
>>> 
>>>
>>> ## The US friend wants to meet at a mutually reasonable
>>> ## time for all the friends. So the US friend creates
>>> ## a datetime object with a proposed time in the future.
>>> ## They use their own US time as reference. This reference
>>> ## is obtained from the ZoneInfo object.
>>> lets_meet_at = datetime(2020, 10, 22, 10, 0, tzinfo=ZoneInfo("America/New_York"))
>>> lets_meet_at
datetime.datetime(2020, 10, 22, 10, 0, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))
>>> print(lets_meet_at)
2020-10-22 10:00:00-04:00
>>> 
>>> ## This allows the US friend to find corresponding time
>>> ## for the Canadian friend(specified as the Canadian local time).
>>> ## Note, the Canadian friend is an early riser :).
>>> lets_meet_at_ca = lets_meet_at.astimezone(ZoneInfo("America/Vancouver"))
>>> lets_meet_at_ca
datetime.datetime(2020, 10, 22, 7, 0, tzinfo=zoneinfo.ZoneInfo(key='America/Vancouver'))
>>> print(lets_meet_at_ca)
2020-10-22 07:00:00-07:00
>>> 
>>> ## Similarly, the US friend finds the corresponding time
>>> ## for the German friend(specified as the German local time).
>>> ## The German friend works all day and is available after work :) 
>>> lets_meet_at_eu = lets_meet_at.astimezone(ZoneInfo("Europe/Berlin"))
>>> lets_meet_at_eu
datetime.datetime(2020, 10, 22, 16, 0, tzinfo=zoneinfo.ZoneInfo(key='Europe/Berlin'))
>>> print(lets_meet_at_eu)
2020-10-22 16:00:00+02:00
>>> 

Pour le lecteur curieux, la liste des fuseaux horaires IANA se trouve comme suit…. Notez que cela crée une sortie énorme.

>>> import zoneinfo
>>> zoneinfo.available_timezones()

Fonctionnalité 8 :Nouveau module Graphlib avec implémentation de tri topologique

Le nouveau module graphlib a maintenant une implémentation d'un tri topologique d'un graphe. Prenons l'exemple suivant.

$ python
Python 3.9.0b5
>>> 
>>> from graphlib import TopologicalSorter
>>> 
>>> ## my_graph has two edges A->C->D and A->B. In other words
>>> ## one could say A depends-on C, which depends-on D. As well
>>> ## as A also depends-on B.
>>> my_graph = {"A": {"B", "C"}, "C": {"D"}}
>>> mg = TopologicalSorter(my_graph)
>>> list(mg.static_order())
['B', 'D', 'C', 'A']
>>> 

Notez que la commande totale suggérée ['B', 'D', 'C', 'A'] est une interprétation de l'ordre. Ce n'est pas nécessairement unique.

Académie Finxter

Ce blog vous a été présenté par Girish , un étudiant de Finxter Academy. Vous pouvez trouver son profil Upwork ici.

Référence

Toutes les recherches pour cet article de blog ont été effectuées à l'aide de documents Python, du moteur de recherche Google et de la base de connaissances partagée de la Finxter Academy et des communautés Stack Overflow. Des concepts et des idées ont également été recherchés sur les sites Web suivants :

  • Vrai Python
  • TasdikRahman
  • Jarrod C Taylor

Post précédent