2009-04-03 6 views
27

Il est de notoriété publique que les fonctions Python peuvent avoir un maximum de 256 arguments. Ce que je suis curieux de savoir si cette limite est applique à *args et **kwargs quand ils déroulèrent de la manière suivante:Quel est le nombre maximal d'arguments dans une fonction Python?

items = [1,2,3,4,5,6] 

def do_something(*items): 
    pass 

Je demande parce que, par hypothèse, il pourrait y avoir des cas où une liste plus de 256 articles se déroule comme un ensemble de *args ou **kwargs.

Répondre

21

WFM

>>> fstr = 'def f(%s): pass' % (', '.join(['arg%d' % i for i in range(5000)])) 
>>> exec(fstr) 
>>> f 
<function f at 0x829bae4> 

Mise à jour: que Brian a remarqué, la limite est du côté de l'appel:

>>> exec 'f(' + ','.join(str(i) for i in range(5000)) + ')' 

Traceback (most recent call last): 
    File "<pyshell#63>", line 1, in <module> 
    exec 'f(' + ','.join(str(i) for i in range(5000)) + ')' 
    File "<string>", line 1 
SyntaxError: more than 255 arguments (<string>, line 1) 

d'autre part cela fonctionne:

>>> f(*range(5000)) 
>>> 

Conclusion: non, cela ne s'applique pas aux arguments déroulés.

+0

Il semble que la limite soit du côté appelant. Essayez exec 'f (' + ','. Join (str (i) pour i dans la plage (5000)) + ')' – Brian

+0

"WFM"? WTF? .... –

+0

@Stefan: * Fonctionne pour moi * –

1

J'ai essayé pour une liste de 4000 articles, et cela a fonctionné. Donc je suppose que cela fonctionnera aussi pour des valeurs plus grandes.

1

pour ** kwargs, Si je me souviens bien, c'est un dictionnaire. Il n'a donc pas de limites. Pour * args, je ne suis pas si sûr, mais je pense que c'est un uplet ou une liste, donc il n'a pas non plus de limite.

Sans limite, je veux dire sauf peut-être la limite de mémoire.

+0

Oui * args est un tuple. –

5

Cela semble être une restriction dans la compilation de la source, donc il existera probablement uniquement pour les arguments passés directement, pas dans * args ou ** kwargs.

Le code correspondant se trouve dans ast.c:

if (nargs + nkeywords + ngens > 255) { 
    ast_error(n, "more than 255 arguments"); 
    return NULL; 
} 

Mais notez que cela est en ast_for_call, et ainsi que applys du côté appelant. c'est-à-dire f(a,b,c,d,e...), plutôt que la définition, bien qu'il compte à la fois les paramètres de position (a,b,c,d) et keyword (a=1, b=2, c=3). Les paramètres réels *args et **kwargs semblent ne devoir être comptés que comme un argument à cet effet du côté appelant.

20

La limite est due à la façon dont le bytecode compilé traite l'appel d'une fonction avec des arguments de position et/ou des mots-clés.

L'optic de bytecode de préoccupation est CALL_FUNCTION qui porte un op_arg qui est de 4 octets de longueur, mais sur les deux octets les moins significatifs sont utilisés. Parmi ceux-ci, l'octet le plus significatif représente le nombre d'arguments de mot-clé sur la pile et l'octet le moins significatif le nombre d'arguments positionnels sur la pile. Par conséquent, vous pouvez avoir au plus 0xFF == 255 arguments de mot-clé ou 0xFF == 255 arguments positionnels.

Cette limite ne s'applique pas à * args et ** kwargs, car les appels avec cette grammaire utilisent les opérations de code de bycecode CALL_FUNCTION_VAR, CALL_FUNCTION_KW et CALL_FUNCTION_VAR_KW en fonction de la signature. Pour ces opcodes, la pile consiste en un itérable pour les * args et un dict pour les ** kwargs. Ces éléments sont transmis directement au récepteur qui les déroule au besoin.

+0

Est-ce une restriction d'implémentation de CPython, ou fait-elle partie de Python lui-même? – EOL

+1

Il s'agit d'un détail d'implémentation du bytecode CPython. –

+0

... en effet. La limitation sera publiée avec CPython 3.7. – EOL

2

CPython a une limite de 255 arguments transmis explicitement dans un appel:

>>> def f(*args, **kwargs): pass 
... 
>>> exec("f({})".format(', '.join(map(str, range(256))))) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 1 
SyntaxError: more than 255 arguments 

Cette limitation est en place parce que Python 3.5, la CALL_FUNCTION opcode surchargée l'argument opcode pour coder à la fois la. nombre d'arguments de position et de mot-clé sur la pile, tous deux codés dans un seul octet.

Cette limitation est supprimée dans la prochaine version de Python 3.7, voir issue #27213 et issue #12844; # 27213 retravaillé la famille d'opcodes CALL_FUNCTION* pour la performance et la simplicité (partie de 3.6), libérant l'argument opcode pour coder seulement un seul argument, et # 12844 enlevé la vérification à la compilation qui empêchait le code avec plus d'arguments d'être compilés.

En 3.7, avec le EXTENDED_ARG() opcode, il est maintenant pas de limite du tout sur le nombre d'arguments, vous pouvez passer en utilisant des arguments explicites, enregistrez combien peuvent être montés sur la pile (donc lié maintenant par votre mémoire):

>>> import sys 
>>> sys.version_info 
sys.version_info(major=3, minor=7, micro=0, releaselevel='alpha', serial=2) 
>>> def f(*args, **kwargs): pass 
... 
>>> exec("f({})".format(', '.join(map(str, range(256))))) 
>>> exec("f({})".format(', '.join(map(str, range(2 ** 16))))) 

Notez que la liste, tuples et les dictionnaires sont limités à sys.maxsize éléments, donc si la fonction appelée utilise *args et/ou **kwargs rattrapages tous les paramètres puis ceux sont limitées.

Pour la syntaxe d'appel *args et **kwargs (arguments d'expansion) il n'y a pas de limites autres que les mêmes limites de taille sys.maxint sur les types standard Python.

+0

Belle rafraîchir la réponse fournissant de nouvelles informations et contexte – Rookie

Questions connexes