Introduction
Dans cette section, nous repensons une décision de conception prise précédemment.
Noms de fichiers vs Itérables
Comparez ces deux programmes qui renvoient la même sortie.
## Fournir un nom de fichier
def read_data(filename):
records = []
with open(filename) as f:
for line in f:
...
records.append(r)
return records
d = read_data('file.csv')
## Fournir des lignes
def read_data(lines):
records = []
for line in lines:
...
records.append(r)
return records
with open('file.csv') as f:
d = read_data(f)
- Quelle de ces fonctions préférez-vous? Pourquoi?
- Quelle de ces fonctions est la plus flexible?
Idée profonde : "Duck Typing"
Duck Typing est un concept de programmation informatique pour déterminer si un objet peut être utilisé à une fin particulière. C'est une application du test canard.
Si ça ressemble à un canard, nage comme un canard et canarde comme un canard, alors c'est probablement un canard.
Dans la deuxième version de read_data() ci-dessus, la fonction attend n'importe quel objet itérable. Pas seulement les lignes d'un fichier.
def read_data(lines):
records = []
for line in lines:
...
records.append(r)
return records
Cela signifie que nous pouvons l'utiliser avec d'autres lignes.
## Un fichier CSV
lines = open('data.csv')
data = read_data(lines)
## Un fichier compressé au format zip
lines = gzip.open('data.csv.gz','rt')
data = read_data(lines)
## L'entrée standard
lines = sys.stdin
data = read_data(lines)
## Une liste de chaînes de caractères
lines = ['ACME,50,91.1','IBM,75,123.45',...]
data = read_data(lines)
Il y a une flexibilité considérable avec cette conception.
Question : Devrions-nous accepter ou combattre cette flexibilité?
Meilleures pratiques de conception de bibliothèques
Les bibliothèques de code sont souvent mieux servies en acceptant la flexibilité. Ne restreignez pas vos options. Avec une grande flexibilité vient un grand pouvoir.
Exercice 3.17 : Passer de noms de fichiers à des objets similaires à des fichiers
Vous avez maintenant créé un fichier fileparse.py qui contenait une fonction parse_csv(). La fonction fonctionnait comme ceci :
>>> import fileparse
>>> portfolio = fileparse.parse_csv('portfolio.csv', types=[str,int,float])
>>>
En ce moment, la fonction attend qu'on lui passe un nom de fichier. Cependant, vous pouvez rendre le code plus flexible. Modifiez la fonction de sorte qu'elle fonctionne avec n'importe quel objet similaire à un fichier/itérable. Par exemple :
>>> import fileparse
>>> import gzip
>>> with gzip.open('portfolio.csv.gz', 'rt') as file:
... port = fileparse.parse_csv(file, types=[str,int,float])
...
>>> lines = ['name,shares,price', 'AA,100,34.23', 'IBM,50,91.1', 'HPE,75,45.1']
>>> port = fileparse.parse_csv(lines, types=[str,int,float])
>>>
Dans ce nouveau code, que se passe-t-il si vous passez un nom de fichier comme avant?
>>> port = fileparse.parse_csv('portfolio.csv', types=[str,int,float])
>>> port
... regardez la sortie (elle devrait être folle)...
>>>
Oui, vous devrez faire attention. Pourriez-vous ajouter une vérification de sécurité pour éviter cela?
Exercice 3.18 : Correction de fonctions existantes
Corrigez les fonctions read_portfolio() et read_prices() dans le fichier report.py de sorte qu'elles fonctionnent avec la version modifiée de parse_csv(). Cela devrait ne nécessiter qu'une modification mineure. Ensuite, vos programmes report.py et pcost.py devraient fonctionner de la même manière qu'auparavant.
Sommaire
Félicitations! Vous avez terminé le laboratoire de discussion sur la conception. Vous pouvez pratiquer d'autres laboratoires sur LabEx pour améliorer vos compétences.