Lors de la publication de l'exemple de code, publiez le résultat de l'exécution dans l'environnement d'exécution suivant. Nous essaierons de le fournir sous une forme aussi exempte d'erreurs que possible, mais veuillez nous pardonner si cela ne fonctionne pas ou est faux.
Que renvoyez-vous si quelque chose d'inattendu se produit lorsque vous le traitez dans une fonction? J'avais l'habitude de renvoyer «Aucun» jusqu'à ce que je sache cela. Par exemple, le code ci-dessous.
#Mauvais exemple (renvoyer None en cas d'inattendu)
from datetime import datetime
def parse_datetimes(datetime_string_list):
result = []
for datetime_string in datetime_string_list:
try:
result.append(datetime.strptime(datetime_string, "%Y-%m-%d"))
except (ValueError, TypeError):
return None
return result
>>> print(parse_datetimes(["2020-09-22"]))
[datetime.datetime(2020, 9, 22, 0, 0)]
>>> print(parse_datetimes([]))
[]
>>> print(parse_datetimes(["hoge"]))
None
Cette fonction accepte une liste de chaînes représentant la date comme entrée, et renvoie une liste convertie en type datetime si l'analyse réussit, et "None" si elle échoue. À première vue, cela a l'air bien, mais cela pose deux problèmes.
, il sera traité de la même manière non seulement dans le cas de
Aucunmais aussi dans le cas de la liste vide
[]`, et il est facile de provoquer un bogue.Pour éviter ces problèmes, ** lancez une exception si quelque chose d'inattendu se produit dans la fonction **.
#Bon exemple (lancer une exception en cas d'inattendu)
from datetime import datetime
class MyError(Exception):
def __init__(self, message):
self.message = message
def parse_datetimes(datetime_string_list):
result = []
for datetime_string in datetime_string_list:
try:
result.append(datetime.strptime(datetime_string, "%Y-%m-%d"))
except (ValueError, TypeError):
raise MyError(f"La valeur saisie n'est pas valide: {datetime_string}") #Lancer une exception
return result
>>> print(parse_datetimes(["2020-09-22"]))
[datetime.datetime(2020, 9, 22, 0, 0)]
>>> print(parse_datetimes([]))
[]
>>> print(parse_datetimes(["hoge"]))
...
Traceback (most recent call last):
...
__main__.MyError:La valeur saisie n'est pas valide: hoge
S'il est implémenté pour lever une exception comme décrit ci-dessus, le traitement ne continuera pas tel quel à moins que l'exception «MyError» ne soit interceptée et que «None» et la liste vide «[]» soient identiques. C'est sûr car il n'y a aucune crainte de le manipuler.
Si vous souhaitez utiliser une valeur pour l'argument, et sinon, utilisez la valeur par défaut. Dans ce cas, il est pratique de définir l'argument par défaut. Par exemple, le code ci-dessous.
#C'est un mauvais exemple
def square(value, result_list=[]):
result_list.append(value ** 2)
return result_list
Cette fonction ajoute le carré de «value» à «result_list» et le renvoie. Quant aux sentiments de ceux qui l'ont mis en œuvre,
result_list
, veuillez renvoyer le résultat dans cette liste.result_list
, veuillez renvoyer le résultat dans une liste vide.Je pense que vous pensez.
# result_Si vous spécifiez list, le résultat sera renvoyé dans cette liste.
>>> result_list = [1, 4]
>>> result_list = square(3, result_list)
>>> print(result_list)
[1, 4, 9]
# result_Si list n'est pas spécifié, le résultat sera renvoyé dans la liste vide.
>>> result_list = square(3)
>>> print(result_list)
[9]
Il semble qu'il n'y ait aucun problème, non? Mais après cela, quelque chose d'étrange se produit.
>>> result_list = square(1)
>>> print(result_list)
[9, 1] #cette?[1]Doit être retourné? ??
>>> result_list = square(2)
print(result_list)
[9, 1, 4] #cette? Pourquoi y a-t-il 3 valeurs? ??
alors. Si vous ne le savez pas, vous vous retrouverez avec un comportement aussi mystérieux.
En fait, ** [les arguments par défaut ne sont évalués qu'une seule fois lorsque le module est chargé, pas à chaque fois que la fonction est appelée](https://docs.python.org/ja/3/ faq / programming.html # why-are-default-values-shared-between-objects) **. Par conséquent, si vous spécifiez une liste vide []
comme argument par défaut, la liste vide sera de plus en plus ajoutée ʻajouter`, ainsi le contenu de la liste augmentera chaque fois que vous l'appelez comme décrit ci-dessus. ..
C'est toujours bon si vous le savez et l'utilisez, mais ce n'est pas un comportement que tout le monde connaît, il est donc préférable d'éviter de spécifier une liste vide ou un dictionnaire vide comme argument par défaut. À la place, écrivez:
#Bon exemple
def square(value, result_list=None):
if result_list is None:
result_list = [] #En initialisant ici, il sera ajouté à la liste vide à chaque fois
result_list.append(value ** 2)
return result_list
S'il est implémenté comme ci-dessus, si result_list
n'est pas spécifié, la liste vide sera retournée avec le résultat.
>>> result_list = square(3)
>>> print(result_list)
[9]
>>> result_list = square(1)
>>> print(result_list)
[1]
>>> result_list = square(2)
>>> print(result_list)
[4]
En passant, selon l'EDI, un avertissement peut être émis, alors assurez-vous de répondre si un avertissement est émis. PyCharm a émis l'avertissement suivant.
Soudain, savez-vous ce que signifie le code ci-dessous?
def safe_division(numerator, denominator, /, hoge, *, ignore_overflow, ignore_zero_division):
...
Vous vous demandez peut-être, "Pourquoi est-ce que / ʻou
* est écrit dans l'argument? " C'est ["Arguments de position seule (côté gauche de
/) "et" Arguments de mot-clé seulement (côté droit de
* `) ajoutés à partir de Python 3.8"](https://docs.python.org/ja/ Il est écrit en utilisant 3 / glossary.html # term-parameter).
Qu'est-ce que ça veut dire?
/
(numérateur
et dénominateur
dans l'exemple ci-dessus) sont des ** arguments de position uniquement **.safe_division (3, 2, ...)
--Cet appel est NG: safe_division (numerator = 3, denominator = 2, ...)
*
(ʻignore_overflow et ʻignore_zero_division
dans l'exemple ci-dessus) sont des ** arguments de mot-clé uniquement **.safe_division (..., ignore_overflow = True, ignore_zero_division = False)
--Cet appel est NG: safe_division (..., True, False)
/
et sur le côté gauche de *
(hoge
dans l'exemple ci-dessus) peuvent être spécifiés en tant qu'arguments positionnels ou arguments de mots-clés.
――En d'autres termes, vous pouvez appeler comme avant
--Cet appel est OK: safe_division (...," a ", ...)
--Cet appel est également OK: safe_division (..., hoge =" a ", ...)
Je pense que les avantages de l'utilisation d'arguments de position uniquement et d'arguments de mots clés sont les suivants.
(dénominateur = 2, molécule = 3, ...)
. est
True! Vous pouvez le forcer à reconnaître cela et spécifier l'argument --Ainsi, vous pouvez réduire l'erreur courante de "Je voulais définir ʻignore_overflow
sur True
, mais j'ai spécifié True
pour ʻignore_zero_division`! "Écrire «/» ou «*» dans l'argument peut sembler étrange au début, mais comme mentionné ci-dessus, cela a aussi des mérites, il est donc préférable de l'utiliser au besoin. Cependant, cela ne fonctionnera pas s'il est inférieur à Python 3.8, alors faites attention!
Sur la base du contenu du chapitre 3
None
.[]
ou un dictionnaire vide {}
comme argument par défaut de la fonction entraînera des bogues inattendus et devrait être évité.Recommended Posts