Update chapters
Updated chapters 2, 6, 8, 9 and 11.
This commit is contained in:
@ -296,6 +296,8 @@ c = {} # ou dict(), ceci est un dictionnaire vide
|
|||||||
print(a["server1"]) # affiche "192.168.1.2"
|
print(a["server1"]) # affiche "192.168.1.2"
|
||||||
print(b[10]) # affiche "M. Dubois"
|
print(b[10]) # affiche "M. Dubois"
|
||||||
print(b[9]) # provoque une erreur
|
print(b[9]) # provoque une erreur
|
||||||
|
print(9 in b) # Vérifier que 9 fait partie des clés de b
|
||||||
|
print(9 in b.values()) # Vérifier que 9 fait partie des valeurs de b
|
||||||
```
|
```
|
||||||
|
|
||||||
Les dictionnaires ont les mêmes contraintes que les ensembles uniquement au niveau de leurs clés; vous
|
Les dictionnaires ont les mêmes contraintes que les ensembles uniquement au niveau de leurs clés; vous
|
||||||
|
@ -7,189 +7,213 @@ author: Steve Kossouho
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Un type pour les dates et heures
|
## `datetime` : Des moments dans le temps
|
||||||
|
|
||||||
La bibliothèque standard nous offre plusieurs types de données pour gérer des moments dans le temps, avec le module `datetime`. Dans ce module, le type pour les dates avec heure s'appelle aussi `datetime`.
|
La bibliothèque standard nous offre plusieurs types de données pour gérer des moments dans le temps,
|
||||||
|
avec le module `datetime`. Dans ce module, un type pour stocker des moments dans le temps, nommé `datetime`,
|
||||||
```{.python .numberLines}
|
est fourni.
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
now = datetime.now()
|
|
||||||
then = datetime(2021, 1, 31) # arguments positionnels
|
|
||||||
then2 = datetime(2021, 1, 31, hour=12) # arguments par défaut
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Les objets de ce type offrent un accès à plusieurs attributs, pour récupérer le jour, le mois, l'heure etc.
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
now = datetime.now()
|
|
||||||
print(now.day, now.date()) # affiche le jour du mois, et la date sans l'heure
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Opérations arithmétiques entre dates et intervalles de temps
|
|
||||||
|
|
||||||
Le module `datetime` propose un type qui représente un intervalle de temps, nommé `timedelta`.
|
|
||||||
C'est ce que l'on obtient quand on soustrait deux dates (le temps écoulé entre les deux).
|
|
||||||
Mais on peut aussi créer des objets `timedelta`{.python} et les ajouter (ou soustraire) à des dates.
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
from datetime import timedelta, datetime
|
|
||||||
|
|
||||||
interval = timedelta(hours=15)
|
|
||||||
now = datetime.now()
|
|
||||||
then = datetime(2000, 1, 1)
|
|
||||||
interval2 = now - then
|
|
||||||
the_future = now + interval # dans 15 heures
|
|
||||||
print(interval2, the_future)
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Les objets d'intervalle de temps donnent accès à peu d'attributs. Nous avons uniquement accès aux jours, secondes et microsecondes.
|
|
||||||
On préférera utiliser le résultats renvoyés par la méthode `total_seconds()` comme base pour nos propres conversions d'ordres de grandeur.
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
interval = timedelta(hours=14, minutes=31, seconds=53)
|
|
||||||
print(interval.days, interval.seconds, interval.microseconds)
|
|
||||||
print(interval.total_seconds())
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Récupérer une date depuis un timestamp
|
|
||||||
|
|
||||||
Un [timestamp]{.naming} est une date exprimée sous la forme d'un nombre entier (ou flottant).
|
|
||||||
En général, un timestamp en programmation est le nombre de secondes depuis le
|
|
||||||
1er janvier 1970 à 00:00:00 UTC. On appelle ce moment l'epoch Unix.
|
|
||||||
|
|
||||||
On peut calculer un objet `datetime`{.python} depuis un timestamp, ou un timestamp depuis un objet `datetime`{.python}.
|
|
||||||
|
|
||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
timestamp = 1577836800
|
now = datetime.now() # l'instant actuel
|
||||||
as_datetime = datetime.fromtimestamp(timestamp)
|
midnight = datetime(2021, 1, 31) # 31 janvier 2021 à minuit
|
||||||
print(as_datetime)
|
noon = datetime(2021, 1, 31, hour=12) # 31 janvier 2021 à 12h00
|
||||||
|
|
||||||
|
print(now)
|
||||||
|
print(midnight)
|
||||||
|
print(noon)
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Les objets de type `datetime`{.python} sont exploitables grâce à plusieurs
|
||||||
|
méthodes et attributs :
|
||||||
|
|
||||||
## Convertir une date en chaîne
|
```python {.numberLines}
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
Pour convertir une date vers une chaîne, ou convertir une chaîne vers un objet de date, consultez toujours la même ressource :
|
now = datetime.now()
|
||||||
|
print(now.year) # Année
|
||||||
|
print(now.month) # Mois (int)
|
||||||
|
print(now.day) # Jour (int)
|
||||||
|
print(now.hour) # Heure (int)
|
||||||
|
print(now.weekday()) # Jour de la semaine (int)
|
||||||
|
print(now.date()) # objet qui représente une journée
|
||||||
|
print(now.timestamp()) # Timestamp Unix (float)
|
||||||
|
```
|
||||||
|
|
||||||
[Table de référence pour le format de dates](https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes)
|
----
|
||||||
|
|
||||||
|
## `date` : Une journée
|
||||||
|
|
||||||
|
Le type `date` du module `datetime` permet de représenter des jours,
|
||||||
|
sans notion d'heure.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
event_1 = date(1944, 6, 6) # 6 juin 1944
|
||||||
|
event_2 = date(1986, 4, 26) # 26 avril 1986
|
||||||
|
|
||||||
|
print(event_1.year)
|
||||||
|
print(event_1.month)
|
||||||
|
print(event_1.day)
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## `timedelta` : Intervalles de temps
|
||||||
|
|
||||||
|
Un troisième type de données, `timedelta`, permet de représenter des durées.
|
||||||
|
Vous pouvez obtenir des objets de ce type de deux façons :
|
||||||
|
|
||||||
|
- Soit en calculant la différence entre deux `datetime` ou `date`;
|
||||||
|
- Soit en créant explicitement un objet de ce type;
|
||||||
|
- Soit en ajoutant des objets de ce type.
|
||||||
|
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
from datetime import timedelta, datetime, date
|
||||||
|
|
||||||
|
event_1 = date(2003, 6, 11) # 11 juin 2003
|
||||||
|
event_2 = date(2003, 9, 27) # 27 septembre 2003
|
||||||
|
elapsed = event_2 - event_1 # 108 jours
|
||||||
|
|
||||||
|
custom_duration = timedelta(weeks=4, days=2, hours=5, minutes=10)
|
||||||
|
double_duration = custom_duration * 2.0
|
||||||
|
event_end = event_1 + custom_duration
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
Les objets `timedelta` possèdent peu d'attributs et de méthodes.
|
||||||
|
Nous pouvons récupérer d'un tel objet les informations suivantes :
|
||||||
|
|
||||||
|
- `timedelta.days`
|
||||||
|
- `timedelta.seconds`
|
||||||
|
- `timedelta.microseconds`.
|
||||||
|
|
||||||
|
Ces informations additionnées donnent la durée complète.
|
||||||
|
|
||||||
|
Cette dernière peut être obtenue en secondes grâce à la méthode `total_seconds()` :
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
interval = timedelta(weeks=4.3, hours=14, minutes=31, seconds=53.234_567)
|
||||||
|
print(f"Nombre de jours : {interval.days}")
|
||||||
|
print(f"Secondes restantes : {interval.seconds}")
|
||||||
|
print(f"Microsecondes restantes : {interval.microseconds}")
|
||||||
|
print(f"Durée totale (s) : {interval.total_seconds():.3f}")
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Récupérer un `datetime` depuis un [timestamp]{.naming}
|
||||||
|
|
||||||
|
Un [timestamp]{.naming} est un instant exprimé sous la forme d'un nombre entier (ou flottant).
|
||||||
|
Dans la plupart des environnements de programmation, un timestamp s'exprime en nombre de secondes
|
||||||
|
écoulées depuis le `1er janvier 1970 à 00:00:00 UTC`. On appelle ce moment l'[epoch Unix]{.naming}.
|
||||||
|
|
||||||
|
On peut calculer un objet `datetime`{.python} depuis un timestamp, ou inversément, un timestamp depuis un objet `datetime`{.python}.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
stamp_1 = 1577836800.24 # 1 janvier 2020 à 01h00
|
||||||
|
event_1 = datetime.fromtimestamp(stamp_1) # 1 janvier 2020 à 01h00
|
||||||
|
event_2 = datetime(1996, 4, 1) # I Got the Vibration
|
||||||
|
stamp_2 = event_2.timestamp() # 828309600
|
||||||
|
print(f"La date du timestamp 1 est : {event_1}")
|
||||||
|
print(f"Le timestamp de la date 2 est : {stamp_2}")
|
||||||
|
```
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
## Générer une chaîne depuis une date
|
||||||
|
|
||||||
|
Pour convertir des informations d'un objet `date` ou `datetime` et générer une chaîne (ou vice-versa)
|
||||||
|
vous devez vous référer en premier lieu à une ressource de référence :
|
||||||
|
|
||||||
|
[Table de référence pour le formatage de dates](https://docs.python.org/fr/3/library/datetime.html#strftime-and-strptime-format-codes)
|
||||||
|
|
||||||
|
Ce tableau de référence reprend les spécifications des mêmes fonctionnalités telles que fournies par la
|
||||||
|
bibliothèque standard du C.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
event = datetime.now()
|
||||||
|
print(event.strftime("%d/%m/%Y %H:%M et %S secondes."))
|
||||||
|
print(f"{event:%d/%m/%Y %H:%M et %S secondes}") # via des f-strings
|
||||||
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Éléments de date localisés dans la langue système
|
### Éléments de date localisés dans la langue système
|
||||||
|
|
||||||
Pour une raison inconnue, probablement un bug sous certaines distributions Linux, Python n'utilise pas la langue configurée sur votre système,
|
Par défaut, Python n'utilise pas la langue configurée sur votre système d'exploitation,
|
||||||
et vous voyez un formatage tel que `Sunday` s'afficher au lieu de `Dimanche`.
|
mais l'anglais pour générer des chaînes de caractères depuis vos objets `datetime`;
|
||||||
Pas de panique, il existe une solution pour forcer Python à utiliser la langue que vous désirez.
|
|
||||||
|
|
||||||
|
Pour demander à Python d'utiliser votre configuration système, utilisez une chaîne vide
|
||||||
|
pour définir le code de langue à utiliser.
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
|
from datetime import datetime
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
locale.setlocale(locale.LC_ALL, "") # utilise les paramètres de langue de l'utilisateur
|
locale.setlocale(locale.LC_ALL, "") # utilise les paramètres de langue de l'utilisateur
|
||||||
|
event_1 = datetime.now()
|
||||||
|
print(f"{event_1:%A %d %B %Y}")
|
||||||
```
|
```
|
||||||
|
|
||||||
[Documentation sur setlocale](https://docs.python.org/fr/3/library/locale.html)
|
[Documentation sur setlocale](https://docs.python.org/fr/3/library/locale.html)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Pour convertir un objet `datetime` vers une chaîne, grâce à la table de référence, c'est simple :
|
## Obtenir un objet `datetime` depuis une chaîne
|
||||||
|
|
||||||
```{.python .numberLines}
|
Ici, il s'agit de comprendre la structure d'une chaîne de caractères contenant
|
||||||
|
une date et en déduire un objet `datetime`.
|
||||||
|
|
||||||
|
```python {.numberLines}
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
now = datetime.now()
|
text = "31/10/1991 15:17"
|
||||||
text = now.strftime("%d/%m/%Y %H:%M et %S secondes.")
|
# La méthode `strptime` est utilisée (string parse time)
|
||||||
other = f"{now:%d/%m/%Y %H:%M et %S secondes}" # via des f-strings
|
moment = datetime.strptime(text, "%d/%m/%Y %H:%M")
|
||||||
print(text, other)
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Convertir une chaîne en date
|
|
||||||
|
|
||||||
Dans l'autre sens, c'est à peine plus compliqué :
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
text = "24 12 2003 15:17"
|
|
||||||
moment = datetime.strptime(text, "%d %m %Y %H:%M")
|
|
||||||
print(moment)
|
print(moment)
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Bonus : Fuseaux horaires
|
## Extra : Fuseaux horaires
|
||||||
|
|
||||||
Par défaut, les objets de date que vous confectionnez sont dits naïfs, car ils ne contiennent pas d'information de fuseau
|
Par défaut, les objets de date que vous confectionnez sont dits [naïfs]{.naming}, car ils ne contiennent
|
||||||
horaire. Vous pouvez créer ou modifier des objets pour porter ces informations si vous en avez besoin.
|
pas d'information de fuseau horaire.
|
||||||
|
Vous pouvez créer ou modifier des objets pour porter ces informations si vous en avez besoin.
|
||||||
La façon de s'en servir changera selon que vous utilisez Python 3.9 ou une version antérieure.
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
### Fuseaux horaires avant Python 3.9
|
|
||||||
|
|
||||||
Avant Python 3.9, il est conseillé d'installer `pytz` et `tzlocal` avec `pip`, puis de définir vos dates ainsi :
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
import pytz
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
moment = datetime(2013, 4, 16, tzinfo=pytz.timezone("Europe/Paris"))
|
|
||||||
moment2 = datetime(2010, 1, 1)
|
|
||||||
moment2 = moment2.replace(tzinfo=pytz.UTC)
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Vous pouvez convertir votre date de façon à la représenter dans un autre fuseau horaire :
|
|
||||||
|
|
||||||
```{.python .numberLines}
|
|
||||||
import pytz, tzlocal
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
moment = datetime(2013, 4, 16, tzinfo=pytz.timezone("America/Chihuahua"))
|
|
||||||
moment2 = moment.astimezone(tzlocal.get_localzone())
|
|
||||||
```
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
### Fuseaux horaires avec Python 3.9+
|
### Fuseaux horaires avec Python 3.9+
|
||||||
|
|
||||||
Python 3.9 ajoute enfin `zoneinfo`, qui couvre presque totalement les larges lacunes de `tzinfo`. (il demeure impossible
|
Depuis la version 3.9, Python propose un module `zoneinfo`, qui offre un type `ZoneInfo`
|
||||||
de connaître le fuseau horaire local)
|
applicable à des objets `datetime` :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
from datetime import datetime
|
from datetime import datetime, UTC
|
||||||
from zoneinfo import ZoneInfo
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
moment = datetime(1975, 3, 1, hour=13, tzinfo=ZoneInfo("Europe/Madrid"))
|
moment_madrid = datetime(1975, 3, 1, hour=13, tzinfo=ZoneInfo("Europe/Madrid"))
|
||||||
|
moment_utc = datetime(1966, 10, 5, tzinfo=UTC)
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Bonus : Bibliothèques tierces pour les dates
|
## Bonus : Bibliothèques tierces pour les dates
|
||||||
|
|
||||||
L'écosystème Python propose de temps en temps des alternatives plus abordables que les
|
L'écosystème Python propose des bibliothèques simplifiant l'usage des dates :
|
||||||
outils présents dans la bibliothèque standard. La gestion de dates n'y échappe pas et je peux proposer
|
|
||||||
deux bibliothèques élégantes et simples à comprendre pour Python :
|
|
||||||
|
|
||||||
- [Arrow](https://arrow.readthedocs.io/en/latest/) : Better dates and times for Python
|
- [Arrow](https://arrow.readthedocs.io/en/latest/) : Better dates and times for Python
|
||||||
- [Pendulum](https://pendulum.eustace.io/) : Python datetimes made easy
|
- [Pendulum](https://pendulum.eustace.io/) : Python datetimes made easy
|
||||||
|
@ -51,8 +51,8 @@ système de références en XML).
|
|||||||
|
|
||||||
Parmi les autres bibliothèques, la plus utilisée dans l'écosystème Python semble être [LXML](https://lxml.de)
|
Parmi les autres bibliothèques, la plus utilisée dans l'écosystème Python semble être [LXML](https://lxml.de)
|
||||||
|
|
||||||
```{.bash .numberLines}
|
```bash {.numberLines}
|
||||||
pip install lxml # pour installer la bibliothèque externe
|
pip install lxml types-lxml # pour installer la bibliothèque externe
|
||||||
```
|
```
|
||||||
|
|
||||||
----
|
----
|
||||||
@ -62,16 +62,17 @@ pip install lxml # pour installer la bibliothèque externe
|
|||||||
Pour naviguer dans un document XML, il existe plusieurs façons de faire :
|
Pour naviguer dans un document XML, il existe plusieurs façons de faire :
|
||||||
|
|
||||||
- Méthode récursive, où l'on récupère un élément pour parcourir ses enfants
|
- Méthode récursive, où l'on récupère un élément pour parcourir ses enfants
|
||||||
- Méthode XPATH, où l'on référence des éléments par rapport à leur "chemin" dans le document
|
- Méthode [XPath]{.naming}, où l'on référence des éléments par rapport à leur "chemin" dans le document
|
||||||
|
- Méthode [ElementPath]{.naming}, proposée par LXML via les méthodes `find` et `findall`
|
||||||
|
|
||||||
La plus simple des méthodes disponibles consiste à se baser sur le XPATH pour trouver des éléments :
|
La plus simple des méthodes disponibles consiste à se baser sur le XPATH pour trouver des éléments :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
tree = etree.parse(r"source.xml") # récupère l'élément racine
|
root = etree.parse(r"source.xml") # récupère l'élément racine
|
||||||
# Récupérer les éléments de la racine CATALOG qui ont le nom CD
|
# Récupérer les éléments de la racine CATALOG qui ont le nom CD
|
||||||
items = tree.xpath("/CATALOG/CD")
|
items = root.xpath("/CATALOG/CD")
|
||||||
```
|
```
|
||||||
|
|
||||||
- [Guide complet sur le XPath](https://www.ionos.com/digitalguide/websites/web-development/xpath-tutorial/)
|
- [Guide complet sur le XPath](https://www.ionos.com/digitalguide/websites/web-development/xpath-tutorial/)
|
||||||
@ -85,12 +86,12 @@ items = tree.xpath("/CATALOG/CD")
|
|||||||
Dans l'exemple précédent, nous avons pu récupérer, via une "requête" XPATH, un possible ensemble d'éléments.
|
Dans l'exemple précédent, nous avons pu récupérer, via une "requête" XPATH, un possible ensemble d'éléments.
|
||||||
Ces éléments peuvent être parcourus avec une simple boucle `for`{.python} :
|
Ces éléments peuvent être parcourus avec une simple boucle `for`{.python} :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
tree = etree.parse(r"source.xml") # récupère l'élément racine
|
root = etree.parse(r"source.xml") # récupère l'élément racine
|
||||||
# Récupérer les éléments de la racine CATALOG qui ont le nom CD
|
# Récupérer les éléments de la racine CATALOG qui ont le nom CD
|
||||||
items = tree.xpath("/CATALOG/CD")
|
items = root.xpath("/CATALOG/CD")
|
||||||
|
|
||||||
for cd in items:
|
for cd in items:
|
||||||
for attribute in cd:
|
for attribute in cd:
|
||||||
|
@ -46,7 +46,7 @@ Cette table ne possède pas de contrainte particulière et autorise à enregistr
|
|||||||
```python {.numberLines}
|
```python {.numberLines}
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
connection = sqlite3.connect("intro.sqlite3", isolation_level=None)
|
connection = sqlite3.connect("intro.sqlite3", autocommit=True)
|
||||||
cursor = connection.cursor() # cet objet est utilisé pour envoyer des requêtes
|
cursor = connection.cursor() # cet objet est utilisé pour envoyer des requêtes
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS person (
|
CREATE TABLE IF NOT EXISTS person (
|
||||||
@ -126,7 +126,7 @@ Les objets de type `sqlite3.Row`{.python} sont utilisables comme des dictionnair
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Hors-programme : Requêtes universelles avec les ORMs
|
## Hors-programme : Les [ORM]{.naming}
|
||||||
|
|
||||||
C'est bien d'envoyer du SQL à une base de données, mais le problème du standard SQL, c'est que
|
C'est bien d'envoyer du SQL à une base de données, mais le problème du standard SQL, c'est que
|
||||||
tous les systèmes de gestion de bases de données ne gèrent pas toujours le SQL de la même façon;
|
tous les systèmes de gestion de bases de données ne gèrent pas toujours le SQL de la même façon;
|
||||||
@ -138,7 +138,7 @@ très probablement de retoucher ou d'adapter vos requêtes.
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Ce problème est, entre autres questionnements, à l'origine de l'existence des ORMs (`Object Relational Mapper`).
|
Ce problème est, entre autres questionnements, à l'origine de l'existence des ORMs ([Object Relational Mapper]{.naming}).
|
||||||
Ce sont des bibliothèques qui offrent une abstraction de la base de données et la remplacent par
|
Ce sont des bibliothèques qui offrent une abstraction de la base de données et la remplacent par
|
||||||
l'écriture de code, non plus en SQL, mais dans votre langage **orienté objet** préféré,
|
l'écriture de code, non plus en SQL, mais dans votre langage **orienté objet** préféré,
|
||||||
pour représenter des schémas et manipuler vos données.
|
pour représenter des schémas et manipuler vos données.
|
||||||
@ -167,43 +167,6 @@ en charge par l'ORM).
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Bonus : Petite explication sur `isolation_level`
|
|
||||||
|
|
||||||
Dans notre premier slide contenant du code, nous avons défini un argument facultatif à la fonction `connect`, nommé
|
|
||||||
`isolation_level`. Celui-ci permet de définir le [niveau d'isolation](https://en.wikipedia.org/wiki/Isolation_(database_systems)) des commandes SQL que l'on envoie.
|
|
||||||
|
|
||||||
Si l'on passe la valeur `None`{.python} à cet argument, l'auto-commit est activé, ce qui signifie que nous n'avons plus besoin
|
|
||||||
d'appeler manuellement `commit()`{.python} lorsqu'on souhaite persister nos modifications. Ceci est normalement le comportement
|
|
||||||
par défaut pour toute bibliothèque DBAPI, mais pour une raison inconnue, cela n'est pas le cas pour `sqlite`. Le bug sera corrigé
|
|
||||||
dans Python 3.12.
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
En temps normal, si nous n'avions pas précisé ce paramètre :
|
|
||||||
|
|
||||||
- Ouvrir la connexion (sans autocommit)
|
|
||||||
- `connection.execute()`{.python} → ouvre une transaction
|
|
||||||
- `connection.execute()`{.python}
|
|
||||||
- `connection.execute()`{.python}
|
|
||||||
- Aucune modification n'est persistée tant qu'on n'appelle pas `connection.commit()`{.python}
|
|
||||||
|
|
||||||
Le fait de devoir `cnx.commit()`{.python} par défaut n'est pas spécialement intuitif, notamment
|
|
||||||
lorsqu'on débute en bases de données...
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
Grâce à notre paramètre `isolation_level`, le comportement est plus intuitif par défaut :
|
|
||||||
|
|
||||||
- Ouvrir la connexion (avec autocommit)
|
|
||||||
- `connection.execute()`{.python} → modification immédiate
|
|
||||||
- `connection.execute()`{.python} → modification immédiate
|
|
||||||
- `connection.execute("BEGIN")`{.python} → Ouverture explicite d'une transaction
|
|
||||||
- `connection.execute()`{.python} → modification non persistée
|
|
||||||
- `connection.execute("COMMIT")`{.python} → ferme la transaction et applique les modifications si
|
|
||||||
possible
|
|
||||||
|
|
||||||
----
|
|
||||||
|
|
||||||
## Bibliothèques Python compatibles DB API 2.0 :
|
## Bibliothèques Python compatibles DB API 2.0 :
|
||||||
|
|
||||||
- MySQL : `pip install mysql-connector-python`{.shell} ([doc](https://dev.mysql.com/doc/connector-python/en/))
|
- MySQL : `pip install mysql-connector-python`{.shell} ([doc](https://dev.mysql.com/doc/connector-python/en/))
|
||||||
|
@ -12,11 +12,11 @@ author: Steve Kossouho
|
|||||||
En Python, comme dans d'autres langages, vous savez que l'on peut introduire des commentaires dans le code.
|
En Python, comme dans d'autres langages, vous savez que l'on peut introduire des commentaires dans le code.
|
||||||
Il suffit d'utiliser le symbole `(#)` dans une ligne de code, et ce qui suit sera considéré comme commentaire.
|
Il suffit d'utiliser le symbole `(#)` dans une ligne de code, et ce qui suit sera considéré comme commentaire.
|
||||||
|
|
||||||
Mais saviez-vous que Python considère le concept de documentation comme étant à part ?
|
Mais saviez-vous que Python considère le concept de documentation comme étant à part ?
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
print(__doc__) # Ne provoque pas d'erreur, mais affiche `None`
|
print(__doc__) # Ne provoque pas d'erreur, mais affiche `None`
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ Cet attribut « magique » laisse entendre que la notion de documentation fait p
|
|||||||
|
|
||||||
### Documentation dans la bibliothèque standard
|
### Documentation dans la bibliothèque standard
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
print(sqlite3.__doc__) # documentation du module SQLite3
|
print(sqlite3.__doc__) # documentation du module SQLite3
|
||||||
@ -45,7 +45,7 @@ récupérer quelque chose dans son attribut `__doc__`{.python}.
|
|||||||
|
|
||||||
Pour documenter un module, c'est finalement assez simple :
|
Pour documenter un module, c'est finalement assez simple :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
"""Texte de documentation du module."""
|
"""Texte de documentation du module."""
|
||||||
import os, sys
|
import os, sys
|
||||||
print(os.linesep, sys.getwindowsversion())
|
print(os.linesep, sys.getwindowsversion())
|
||||||
@ -81,7 +81,7 @@ Pour documenter, par exemple, un module, il y a deux façons de faire :
|
|||||||
|
|
||||||
Vous pouvez considérer qu'une seule petite phrase peut servir à décrire votre module :
|
Vous pouvez considérer qu'une seule petite phrase peut servir à décrire votre module :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
"""Traitement des données d'épuration des eaux."""
|
"""Traitement des données d'épuration des eaux."""
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ Vous pouvez considérer qu'une seule petite phrase peut servir à décrire votre
|
|||||||
|
|
||||||
### Documentation plus longue
|
### Documentation plus longue
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
"""
|
"""
|
||||||
Traitement des données d'épuration des eaux.
|
Traitement des données d'épuration des eaux.
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ Possibilité d'ajouter des sections, des exemples, soyez exhaustifs si vous le s
|
|||||||
Mieux qu'un long discours, une démo s'impose, avec la bibliothèque `pdoc`.
|
Mieux qu'un long discours, une démo s'impose, avec la bibliothèque `pdoc`.
|
||||||
Un outil beaucoup plus long à mettre en place est `sphinx`, qui permet encore davantage.
|
Un outil beaucoup plus long à mettre en place est `sphinx`, qui permet encore davantage.
|
||||||
|
|
||||||
```{.bash .numberLines}
|
```bash {.numberLines}
|
||||||
pip install pdoc # installer la bibliothèque
|
pip install pdoc # installer la bibliothèque
|
||||||
pdoc [nom du module ou nom du script python] # lance un serveur pour tester
|
pdoc [nom du module ou nom du script python] # lance un serveur pour tester
|
||||||
```
|
```
|
||||||
@ -137,7 +137,7 @@ Depuis Python 3.5 (fin 2015), le langage propose un moyen d'indiquer aux dévelo
|
|||||||
|
|
||||||
Pour annoter une variable et définir quel est son type attendu, on peut :
|
Pour annoter une variable et définir quel est son type attendu, on peut :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
from tartempion import MyClass
|
from tartempion import MyClass
|
||||||
|
|
||||||
variable1: int = 15 # on indique qu'on attend un entier
|
variable1: int = 15 # on indique qu'on attend un entier
|
||||||
@ -166,7 +166,7 @@ function_reference: Callable = range # on attend une fonction
|
|||||||
|
|
||||||
À partir de Python 3.11 (novembre 2022), il est possible de remplacer l'`Union` par un opérateur `|` :
|
À partir de Python 3.11 (novembre 2022), il est possible de remplacer l'`Union` par un opérateur `|` :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
variable: int | float = 15 # soit un entier soit un flottant devrait y être associé
|
variable: int | float = 15 # soit un entier soit un flottant devrait y être associé
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ variable: int | float = 15 # soit un entier soit un flottant devrait y être as
|
|||||||
|
|
||||||
On peut faire la même chose avec des arguments de fonctions :
|
On peut faire la même chose avec des arguments de fonctions :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
# value et default devraient être des entiers
|
# value et default devraient être des entiers
|
||||||
def do_some_important_things(value: int, default: int = 1):
|
def do_some_important_things(value: int, default: int = 1):
|
||||||
print(value, default)
|
print(value, default)
|
||||||
@ -187,7 +187,7 @@ def do_some_important_things(value: int, default: int = 1):
|
|||||||
|
|
||||||
Et on peut également décrire le type attendu du retour des fonctions et méthodes :
|
Et on peut également décrire le type attendu du retour des fonctions et méthodes :
|
||||||
|
|
||||||
```{.python .numberLines}
|
```python {.numberLines}
|
||||||
def do_trivial_things() -> float: # on indique que la fonction retourne un flottant
|
def do_trivial_things() -> float: # on indique que la fonction retourne un flottant
|
||||||
return 100 / 15
|
return 100 / 15
|
||||||
```
|
```
|
||||||
|
Reference in New Issue
Block a user