Pourquoi les fonctions devraient-elles toujours retourner le même type?
J'ai lu quelque part que les fonctions doivent toujours retourner qu'un seul type de
ainsi, le code suivant est considéré comme un mauvais code:
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return None
Je suppose que la meilleure solution serait
def x(foo):
if 'bar' in foo:
return (foo, 'bar')
return ()
Ne serait-il pas moins cher de la mémoire de sage-retour d'un rien, puis de créer un nouveau tuple vide ou est-ce la différence de temps trop petite pour avis, même dans les grands projets?
source d'informationauteur self.self
Vous devez vous connecter pour publier un commentaire.
Pourquoi devrait fonctions retournent des valeurs d'un même type? Afin de respecter les deux règles suivantes.
Règle 1-une fonction a un "type" -- entrées mappés à des sorties. Elle doit retourner une cohérence type de résultat, ou il n'est pas une fonction. C'est un gâchis.
Mathématiquement, nous disons qu'une fonction F est une cartographie de domaine, D, à la plage, R.
F: D -> R
. Le domaine et forme le "type" de la fonction. Les types d'entrée et le type de résultat sont essentiels pour la définition de la fonction est le nom ou le corps.Règle 2 -- quand vous avez un "problème" ou ne pouvez pas retourner un bon résultat, lever une exception.
Vous peut briser les règles ci-dessus, mais le coût de la maintenance à long terme et la compréhensibilité est astronomique.
"Ne serait-il pas moins cher de mémoire sage de renvoyer une Personne"? Mauvaise question.
Le point est pas d'optimisation de la mémoire au détriment de clair, lisible, code évident.
Il n'est pas si clair qu'une fonction doit toujours retourner les objets d'un type limité, ou que le retour Aucun n'est mauvais. Par exemple, re.recherche peut retourner un
_sre.SRE_Match
objet ou unNoneType
objet:Conçu de cette façon, vous pouvez tester pour un match avec l'idiome
Si les développeurs avaient exigé une nouvelle.la recherche renvoie un
_sre.SRE_Match
objet, puisl'idiome devrait changer pour
Il n'y aurait pas de gain significatif en exigeant re.recherche de toujours renvoyer un
_sre.SRE_Match
objet.Donc je pense que la façon dont vous concevez la fonction doit dépendre de la situation et, en particulier, la façon dont vous prévoyez d'utiliser la fonction.
Également noter que les deux
_sre.SRE_Match
etNoneType
sont les instances de l'objet, donc dans un sens large, ils sont du même type. Donc la règle que "les fonctions doivent toujours retourner qu'un seul type" est plutôt vide de sens.Cela dit, il est d'une belle simplicité des fonctions qui retournent des objets qui partagent tous les mêmes propriétés. (Duck-typing, pas de typage statique, est le python!) Il peut vous permettre de la chaîne d'ensemble des fonctions: foo(bar(baz))) et de connaître avec certitude le type d'objet que vous recevrez à l'autre extrémité.
Cela peut vous aider à vérifier l'exactitude de votre code. En exigeant que la fonction renvoie uniquement les objets d'un certain type, il y a moins de cas à vérifier. "foo retourne toujours un entier, donc aussi longtemps qu'un nombre entier est attendu partout où je utiliser foo, je suis d'or..."
Les meilleures pratiques en ce qu'une fonction doit retourner varie considérablement d'une langue à l'autre, et même entre les différentes Python projets.
Pour Python en général, je suis d'accord avec la prémisse que le retour Aucun n'est mauvais, si votre fonction retourne généralement un objet iterable, parce que l'itération sans contrôle devient impossible. Juste de retour d'un vide itératif dans ce cas, il faudra encore tester False si vous utilisez Python standard vérité test:
et toujours vous permettent de parcourir sans test:
Pour les fonctions qui sont susceptibles de renvoyer qu'une seule valeur, je pense que le retour Aucune n'est parfaitement acceptable, tout document qui pourrait se produire dans votre docstring.
Personnellement, je pense qu'il est parfaitement bien pour une fonction de retour d'un n-uplet ou Aucun. Cependant, une fonction doit retourner au plus 2 les différents types et le second doit être un Aucun. Une fonction ne devrait jamais retourner une chaîne de caractères et de la liste par exemple.
Voici mes impressions sur tout ça et je vais essayer d'expliquer aussi pourquoi je pense que l'on a accepté la réponse est la plupart du temps erronées.
Tout d'abord
programming functions != mathematical functions
. Le plus proche que vous pouvez obtenir à des fonctions mathématiques est si vous faites de la programmation fonctionnelle, mais même alors, il y a beaucoup d'exemples qui disent le contraire.Une fonction en termes de programmation doit être considérée simplement comme un bloc de mémoire avec un début (la fonction du point d'entrée), un corps (vide ou non) et de sortie (un ou plusieurs en fonction de la mise en œuvre) qui sont là dans le but de réutiliser du code que vous avez écrit. Même si vous ne le voyez pas une fonction toujours des "retours" de quelque chose. Ce "quelque chose" est en fait l'adresse de la prochaine instruction à droite après l'appel de la fonction. C'est quelque chose que vous allez voir dans toute sa gloire, si vous n'avez vraiment de bas niveau de la programmation avec un langage d'Assemblage (j'ose vous à aller le mile supplémentaire et faire un peu de code machine, à la main comme Linus Torvalds, qui a déjà si souvent fait mention de cet au cours de ses séminaires et entretiens :D). En outre, vous pouvez également prendre une entrée et aussi cracher sur la sortie. C'est pourquoi
est parfaitement correct morceau de code.
Alors pourquoi le renvoi de plusieurs types-elle être mauvaise? Eh bien...Ce n'est pas du tout, sauf si vous en abusez. C'est bien sûr une question de mauvaise compétences en programmation et/ou ne sachant pas quelle est la langue que vous utilisez peut faire.
Autant que je sache - oui, de retour d'un
NoneType
objet serait beaucoup moins cher de mémoire-sage. Voici une petite expérience (valeurs renvoyées sont octets):En fonction du type d'objet que vous êtes en utilisant comme valeur de retour (type numérique, liste, dictionnaire, tuple, etc.) Python gère la mémoire de différentes manières, notamment à l'origine de stockage réservée.
Cependant, vous devez également considérer le code qui est autour de l'appel de la fonction et de la façon dont il traite, quel que soit votre fonction retourne. Vérifiez-vous pour
NoneType
? Ou avez-vous simplement de vérifier si le retour de n-uplet a longueur de 0? Cette propagation de la valeur retournée et son type (NoneType
vs tuple vide dans votre cas) pourrait en fait être plus fastidieux à manipuler et à faire exploser dans votre visage. N'oubliez pas le code lui-même est chargé dans la mémoire de sorte que si la manipulation de laNoneType
exige trop de code (même des petits morceaux de code, mais en grande quantité) mieux vaut laisser le tuple vide, ce qui permettra également d'éviter la confusion dans les esprits des hommes à l'aide de votre fonction et de l'oubli qu'il retourne en fait 2 types de valeurs.Parlant de retourner plusieurs types de valeur, c'est la partie où je suis d'accord avec la accepté de répondre (mais en partie seulement) - de retour d'un seul type rend le code plus facile à maintenir, sans doute. Il est beaucoup plus facile de vérifier uniquement pour le type A, puis A, B, C, ... etc.
Cependant, le langage Python est un langage orienté-objet et en tant que tel héritage, les classes abstraites, etc. et tout ce qui fait partie de l'ensemble de la programmation orientée objet, les manigances entre en jeu. Il peut aller aussi loin que même la création de classes à la volée, que j'ai découvert il y a quelques mois et a été stupéfait (jamais vu ce genre de choses en C/C++).
Note de côté: Vous pouvez lire un peu plus sur metaclasses et dynamique des classes dans cette belle vue d'ensemble de l'article avec beaucoup d'exemples.
Il existe en effet plusieurs modèles de conception et des techniques qui ne serait même pas existe sans le soi-disant fonctions polymorphes. Ci-dessous je vous donne deux très populaires sujets (ne peut pas trouver une meilleure façon de résumer les deux dans un seul terme):
Enfin, si votre fonction renvoie un ou plusieurs types totalement axé sur le problème que vous devez résoudre. Cela peut-il polymorphes être le comportement de violence? Bien sûr, comme tout le reste.
Si
x
est appelé comme celaretour
None
entraînerait unesi
'bar'
n'est pas dansfoo
.Exemple
Il en résulte:
L'optimisation prématurée est la racine de tous les maux. La minuscule gains d'efficacité pourraient être importants, mais pas jusqu'à ce que vous avez prouvé que vous en avez besoin.
Quel que soit votre langue: une fonction est définie à la fois, mais tend à être utilisé à n'importe quel nombre de places. Ayant une constante de type de retour (pour ne pas mentionner documenté pré - et postconditions) signifie que vous avez à dépenser plus d'efforts définition la fonction, mais vous simplifier la utilisation de la fonction énormément. Deviner si les coûts ont tendance à l'emporter sur les économies répétées...?