Certes, la plupart des langages de programmation font de l'ordre des paramètres une partie du contrat d'appel de fonction, mais cela n'a pas besoin d'être ainsi. Pourquoi le ferait-il? Ma compréhension de la question est donc de savoir si Python est différent des autres langages de programmation à cet égard. En plus d'autres bonnes réponses pour Python 2, veuillez tenir compte des éléments suivants:
__named_only_start = object()
def info(param1,param2,param3,_p=__named_only_start,spacing=10,collapse=1):
if _p is not __named_only_start:
raise TypeError("info() takes at most 3 positional arguments")
return str(param1+param2+param3) +"-"+ str(spacing) +"-"+ str(collapse)
La seule façon pour un appelant de fournir des arguments spacing
et de collapse
positionner (sans exception) serait:
info(arg1, arg2, arg3, module.__named_only_start, 11, 2)
La convention de ne pas utiliser d'éléments privés appartenant à d'autres modules est déjà très basique en Python. Comme avec Python lui-même, cette convention pour les paramètres ne serait que semi-appliquée.
Sinon, les appels devront être de la forme:
info(arg1, arg2, arg3, spacing=11, collapse=2)
Un appel
info(arg1, arg2, arg3, 11, 2)
attribuerait la valeur 11 au paramètre _p
et une exception augmentée par la première instruction de la fonction.
Caractéristiques:
- Les paramètres avant
_p=__named_only_start
sont admis par position (ou par nom).
- Les paramètres après
_p=__named_only_start
doivent être fournis uniquement par leur nom (à moins que la connaissance de l'objet sentinelle spécial ne __named_only_start
soit obtenue et utilisée).
Avantages:
- Les paramètres sont explicites en nombre et en signification (le dernier si de bons noms sont également choisis, bien sûr).
- Si la sentinelle est spécifiée comme premier paramètre, tous les arguments doivent être spécifiés par leur nom.
- Lors de l'appel de la fonction, il est possible de passer en mode positionnel en utilisant l'objet sentinelle
__named_only_start
dans la position correspondante.
- Une meilleure performance que d'autres alternatives peut être anticipée.
Les inconvénients:
La vérification se produit au moment de l'exécution, pas au moment de la compilation.
- Utilisation d'un paramètre supplémentaire (mais pas d'un argument) et d'une vérification supplémentaire. Petite dégradation des performances par rapport aux fonctions régulières.
- La fonctionnalité est un hack sans support direct par la langue (voir note ci-dessous).
- Lors de l'appel de la fonction, il est possible de passer en mode positionnel en utilisant l'objet sentinelle
__named_only_start
dans la bonne position. Oui, cela peut également être considéré comme un pro.
Veuillez garder à l'esprit que cette réponse n'est valable que pour Python 2. Python 3 implémente le mécanisme similaire, mais très élégant, supporté par le langage décrit dans d'autres réponses.
J'ai trouvé que lorsque j'ouvre mon esprit et que j'y pense, aucune question ou décision d'une autre ne semble stupide, stupide ou simplement stupide. Bien au contraire: j'apprends généralement beaucoup.
_named_only_start
, il devient impossible de la référencer à partir d'un module externe, ce qui enlève un pro et un con. (les seuls traits de soulignement à la portée du module sont privés, IIRC)__named_only_start
et unnamed_only_start
(pas de trait de soulignement initial), le second indiquant que le mode nommé est "recommandé", mais pas au niveau d'être "activement promu" (car l'un est public et le autre n'est pas). En ce qui concerne le "caractère privé" de_names
commencer par des traits de soulignement, ce n'est pas très fortement imposé par le langage: il peut être facilement contourné par l'utilisation d'importations spécifiques (non *) ou de noms qualifiés. C'est pourquoi plusieurs documents Python préfèrent utiliser le terme «non public» au lieu de «privé».Vous pouvez le faire d'une manière qui fonctionne à la fois dans Python 2 et Python 3 , en créant un premier argument de mot-clé "faux" avec une valeur par défaut qui ne se produira pas "naturellement". Cet argument de mot-clé peut être précédé d'un ou plusieurs arguments sans valeur:
Cela permettra:
mais non:
Si vous modifiez la fonction en:
alors tous les arguments doivent avoir des mots-clés et
info(odbchelper)
ne fonctionneront plus.Cela vous permettra de positionner des arguments de mots clés supplémentaires n'importe où après
_kw
, sans vous obliger à les placer après la dernière entrée. Cela a souvent du sens, par exemple, grouper les choses de manière logique ou organiser les mots-clés par ordre alphabétique peut aider à la maintenance et au développement.Il n'est donc pas nécessaire de revenir à l'utilisation
def(**kwargs)
et à la perte des informations de signature dans votre éditeur intelligent. Votre contrat social consiste à fournir certaines informations, en forçant (certaines d'entre elles) à exiger des mots-clés, l'ordre dans lequel ils sont présentés est devenu inutile.la source
Mettre à jour:
J'ai réalisé que l'utilisation
**kwargs
ne résoudrait pas le problème. Si vos programmeurs changent les arguments de fonction comme ils le souhaitent, on pourrait, par exemple, changer la fonction en ceci:et l'ancien code se casserait à nouveau (car maintenant chaque appel de fonction doit inclure le premier argument).
Cela revient vraiment à ce que dit Bryan.
En général, lors du changement de fonction, les nouveaux arguments doivent toujours aller à la fin. Sinon, cela casse le code. Cela devrait être évident.
Si quelqu'un modifie la fonction pour que le code se brise, ce changement doit être rejeté.
(Comme le dit Bryan, c'est comme un contrat)
En regardant la signature de la fonction (ie
def info(object, spacing=10, collapse=1)
) on devrait immédiatement voir que tout argument qui n'a pas de valeur par défaut, est obligatoire.Ce que l'argument est pour, devrait entrer dans le docstring.
Ancienne réponse (conservée par souci d'exhaustivité) :
Ce n'est probablement pas une bonne solution:Vous pouvez définir les fonctions de cette manière:
kwargs
est un dictionnaire contenant n'importe quel argument de mot-clé. Vous pouvez vérifier si un argument obligatoire est présent et sinon, lever une exception.L'inconvénient est que ce n'est peut-être plus aussi évident, quels arguments sont possibles, mais avec une docstring appropriée, ça devrait aller.
la source
Les arguments de mots clés python3 uniquement (
*
) peuvent être simulés dans python2.x avec**kwargs
Considérez le code python3 suivant:
et son comportement:
Cela peut être simulé en utilisant ce qui suit, je note ai pris la liberté de passer
TypeError
àKeyError
dans le cas, il ne serait pas « requis argument nommé » trop de travail à faire que le même type d'exception aussi bienEt comportement:
La recette fonctionne aussi bien dans python3.x, mais doit être évitée si vous êtes uniquement python3.x
la source
kwargs.pop('foo')
est donc un idiome Python 2? J'ai besoin de mettre à jour mon style de codage. J'utilisais toujours cette approche en Python 3 🤔Vous pouvez déclarer vos fonctions comme réception
**args
uniquement. Cela nécessiterait des arguments de mots-clés, mais vous auriez du travail supplémentaire pour vous assurer que seuls les noms valides sont transmis.la source
foo(**kwargs)
. Qu'est-ce que je passe là-dedans?foo(killme=True, when="rightnowplease")
dict
.Comme le disent d'autres réponses, changer les signatures de fonction est une mauvaise idée. Ajoutez de nouveaux paramètres à la fin ou corrigez chaque appelant si des arguments sont insérés.
Si vous souhaitez toujours le faire, utilisez un décorateur de fonctions et la fonction inspect.getargspec . Il serait utilisé quelque chose comme ceci:
La mise en œuvre de
require_named_args
est laissée comme un exercice pour le lecteur.Je ne me dérangerais pas. Il sera lent à chaque fois que la fonction est appelée, et vous obtiendrez de meilleurs résultats en écrivant le code plus soigneusement.
la source
Vous pouvez utiliser le
**
opérateur:de cette façon, les gens sont obligés d'utiliser des paramètres nommés.
la source
en python si vous utilisez * args cela signifie que vous pouvez passer n-nombre d'arguments pour ce paramètre - qui sera une liste à l'intérieur de la fonction pour accéder
et si vous utilisez ** kw cela signifie ses arguments de mot-clé, qui peuvent être accédés en tant que dict - vous pouvez passer n-nombre d'arguments kw, et si vous voulez restreindre cet utilisateur doit entrer la séquence et les arguments dans l'ordre, alors n'utilisez pas * et ** - (sa manière pythonique de fournir des solutions génériques pour les grandes architectures ...)
si vous souhaitez restreindre votre fonction avec des valeurs par défaut, vous pouvez vérifier à l'intérieur
la source
Je ne comprends pas pourquoi un programmeur ajoutera un paramètre entre deux autres en premier lieu.
Si vous souhaitez que les paramètres de fonction soient utilisés avec des noms (par ex.
info(spacing=15, object=odbchelper)
), l'ordre dans lequel ils sont définis ne devrait pas avoir d'importance, vous pouvez donc aussi bien mettre les nouveaux paramètres à la fin.Si vous voulez que la commande compte, vous ne pouvez pas vous attendre à ce que quelque chose fonctionne si vous le modifiez!
la source