2013-06-05 10 views
69

Perché non è possibile utilizzare una virgola finale con *args in Python? In altre parole, questo funzionaPerché una virgola finale è un errore SyntaxError in un elenco di argomenti che utilizza la sintassi * args?

>>> f(1, 2, b=4,) 

Ma questo non lo fa

>>> f(*(1, 2), b=4,) 
    File "<stdin>", line 1 
    f(*(1, 2), b=4,) 
       ^
SyntaxError: invalid syntax 

Questo è il caso sia con Python 2 e Python 3.

+4

Qualcosa a che fare con il modo in cui '(1,)' crea una tupla forse. – TankorSmash

+3

Apparentemente la parola chiave args è irrilevante. 'f (* args,)' è anche non consentito. – asmeurer

+0

@TankorSmash Ma qui non c'è una tupla come '(' non appare in una posizione di espressione – user2246674

risposta

100

Guardiamo il language specification:

call     ::= primary "(" [argument_list [","] 
          | expression genexpr_for] ")" 
argument_list  ::= positional_arguments ["," keyword_arguments] 
          ["," "*" expression] ["," keyword_arguments] 
          ["," "**" expression] 
          | keyword_arguments ["," "*" expression] 
          ["," "**" expression] 
          | "*" expression ["," "*" expression] ["," "**" expression] 
          | "**" expression 
positional_arguments ::= expression ("," expression)* 
keyword_arguments ::= keyword_item ("," keyword_item)* 
keyword_item   ::= identifier "=" expression 

Raccogliamo le parti che ci interessano:

call     ::= primary "(" [argument_list [","]] ")" 
argument_list  ::= positional_arguments ["," keyword_arguments] 
          ["," "*" expression] ["," keyword_arguments] 
          ["," "**" expression] 
positional_arguments ::= expression ("," expression)* 
keyword_arguments ::= keyword_item ("," keyword_item)* 
keyword_item   ::= identifier "=" expression 

Quindi, sembra che dopo qualsiasi argomento a una chiamata di funzione, è consentito un ulteriore ,. Quindi questo sembra un bug nell'implementazione di cpython.

Qualcosa come: f(1, *(2,3,4),) dovrebbe funzionare secondo questa grammatica, ma non in CPython.


In una precedente risposta, Eric legata al CPython grammar specification, che include l'implementazione CPython della grammatica sopra. Eccolo qui sotto:

arglist: (argument ',')* (argument [','] 
         | '*' test (',' argument)* [',' '**' test] 
         | '**' test 
         ) 

nota, che questa grammatica è non è la stessa come quello proposto dalla specifica del linguaggio. Lo considererei un bug di implementazione.


Si noti che ci sono ulteriori problemi con l'implementazione CPython. Questo dovrebbe anche essere sostenuto: f(*(1,2,3), *(4,5,6))

Stranamente, però, la specifica non consente f(*(1,2,3), *(4,5,6), *(7,8,9))

Mentre guardo questo di più, penso che questo parte della specifica ha bisogno di qualche fissaggio. Questo è permesso: f(x=1, *(2,3)), ma questo non è: f(x=1, 2, 3).


E per essere forse utile alla domanda iniziale, in CPython, si può avere una virgola finale se non si utilizza il *args o la funzione **kwargs. Sono d'accordo che questo è zoppo.

+15

Devo forzare questo. Questa è la prima volta che vedo qualcuno estrapolare le specifiche del linguaggio di Python per supportare una risposta. – lightalchemist

+0

Buona risposta in generale. Ma non sono sicuro di cosa intendi quando dici che 'f (* (1,2,3), * (4,5,6))' "dovrebbe essere supportato" - non mi sembra né grammatica (la specifica del linguaggio e la grammatica di cpython) lo permetterebbero. –

+2

@EdwardLoper Probabilmente si riferisce alla linea della grammatica specifica che dice '| "*" espressione ["," "*" espressione] ["," "**" espressione] '. La prima clausola tra parentesi quadre sembra essere arrivata per errore, la linea dovrebbe essere '| "*" espressione ["," "**" espressione] '. Come dice Sharth, le specifiche richiedono un po 'di lavoro. – user4815162342

5

Dopo qualche discussione riguardo a questa bug in issue 9232, Guido van Rossum commented:

Sono +1 su come aggiungere questo. Non credo che richieda un PEP. Una virgola finale nelle definizioni è già supportata in alcuni punti, quindi non compro l'argomento che rileva errori. Durante la moratoria eravamo forse troppo severi.

Successivamente, è stato eseguito il commit . Quindi questo è ora risolto in Python 3.6.0 alpha 1.

+1

È fantastico! Inizialmente l'ho trovato nel codice reale e mi ci è voluto un po 'di tempo per capire perché Python mi dicesse che avevo un errore di sintassi. – asmeurer

Problemi correlati