Qual è il modo divinatorio per evitare i parametri di default che sono liste vuote?

StackOverflow https://stackoverflow.com/questions/366422

  •  21-08-2019
  •  | 
  •  

Domanda

A volte sembra naturale avere un parametro di default, che è una lista vuota. Eppure Python dà un comportamento imprevisto in queste situazioni .

Se, per esempio, ho una funzione:

def my_func(working_list = []):
    working_list.append("a")
    print(working_list)

La prima volta che viene chiamato il default funzionerà, ma chiede dopo che aggiornerà l'elenco esistente (con una "a" ogni chiamata) e stampare la versione aggiornata.

Quindi, qual è il modo divinatorio per ottenere il comportamento che desidero (una lista fresca per ogni chiamata)?

È stato utile?

Soluzione

def my_func(working_list=None):
    if working_list is None: 
        working_list = []

    working_list.append("a")
    print(working_list)

La documentazione dicono che si dovrebbe usare None come predefinito e per esso nel corpo del la funzione.

Altri suggerimenti

risposte esistenti hanno già fornito le soluzioni dirette come richiesto. Tuttavia, dal momento che si tratta di una trappola molto comune per i nuovi programmatori Python, vale la pena di aggiungere la spiegazione del perché pitone comporta in questo modo, che è ben riassunto in " Guida autostoppisti a Python ", come " mutevole argomenti di default ": http://docs.python-guide.org/en/latest/writing/ grattacapi /

Citazione:. " argomenti di default di Python vengono valutate una volta quando viene definita la funzione, non ogni volta che la funzione viene chiamata (come è nel dire, Ruby) Ciò significa che se si utilizza un argomento di default mutevole e mutare esso, si vuole e hanno mutato tale oggetto per tutte le future chiamate alla funzione e "

Il codice di esempio per la sua attuazione:

def foo(element, to=None):
    if to is None:
        to = []
    to.append(element)
    return to

Non che sia importante in questo caso, ma è possibile utilizzare identità di un oggetto per verificare Nessuno:

if working_list is None: working_list = []

Si potrebbe anche approfittare di come l'operatore booleano o è definita in python:

working_list = working_list or []

Anche se questo si comporterà in modo imprevisto se il chiamante ti dà una lista vuota (che conta come false) come working_list e si aspetta che la funzione per modificare l'elenco lo diede.

Se l'intento della funzione è quella di Modifica il parametro passato come working_list, vedere la risposta di HenryR (= None, verificare la presenza di nessuno all'interno).

Ma se non avete intenzione di mutare l'argomento, basta usarlo come punto di partenza per una lista, si può semplicemente copiare:

def myFunc(starting_list = []):
    starting_list = list(starting_list)
    starting_list.append("a")
    print starting_list

(o in questo caso semplice basta print starting_list + ["a"] ma credo che era solo un esempio giocattolo)

In generale, mutando le sue argomentazioni è cattivo stile in Python. Le uniche funzioni che sono completamente dovrebbero mutare un oggetto sono metodi dell'oggetto. E 'ancora più raro di mutare un argomento opzionale - è un effetto collaterale che si verifica solo in alcune chiamate davvero il migliore interfaccia

  • Se lo si fa dalla C abitudine di "argomenti" di uscita, che è completamente inutile -. Si può sempre tornare più valori come una tupla

  • Se si esegue questa operazione per costruire in modo efficiente una lunga lista di risultati senza costruire liste intermedi, non crei come un generatore e utilizzando result_list.extend(myFunc()) quando si sta chiamando esso. In questo modo i vostri convenzioni di chiamata resta molto pulito.

Un modello in cui mutando un ARG opzionale è di frequente fatto è un nascosto "memo" arg in funzioni ricorsive:

def depth_first_walk_graph(graph, node, _visited=None):
    if _visited is None:
        _visited = set()  # create memo once in top-level call

    if node in _visited:
        return
    _visited.add(node)
    for neighbour in graph[node]:
        depth_first_walk_graph(graph, neighbour, _visited)

Potrei essere off-topic, ma ricordate che se si desidera solo per passare un numero variabile di argomenti, il modo divinatorio è quello di passare una tupla *args o un dizionario **kargs. Questi sono opzionali e sono meglio di sintassi myFunc([1, 2, 3]).

Se si desidera passare una tupla:

def myFunc(arg1, *args):
  print args
  w = []
  w += args
  print w
>>>myFunc(1, 2, 3, 4, 5, 6, 7)
(2, 3, 4, 5, 6, 7)
[2, 3, 4, 5, 6, 7]

Se si desidera passare un dizionario:

def myFunc(arg1, **kargs):
   print kargs
>>>myFunc(1, option1=2, option2=3)
{'option2' : 2, 'option1' : 3}

Ci sono già state buone e risposte corrette fornite. Volevo solo dare un altro sintassi per scrivere quello che si vuole fare che trovo più bello quando si desidera, ad esempio per creare una classe con predefiniti liste vuote:

class Node(object):
    def __init__(self, _id, val, parents=None, children=None):
        self.id = _id
        self.val = val
        self.parents = parents if parents is not None else []
        self.children = children if children is not None else []

Questo frammento fa uso della sintassi, se dell'operatore altro. Mi piace soprattutto perché è un po 'uno-liner pulito senza i due punti, ecc coinvolti e si legge quasi come un normale frase inglese. :)

Nel tuo caso si potrebbe scrivere

def myFunc(working_list=None):
    working_list = [] if working_list is None else working_list
    working_list.append("a")
    print working_list

Ho preso la classe estensione UCSC Python for programmer

Il che è vero: def Fn (data = []):

  

a) è una buona idea in modo che le vostre liste di dati iniziano vuota con ogni chiamata.

     

b) è una buona idea in modo che tutte le chiamate alla funzione che non forniscono alcun argomento sulla chiamata otterrà la lista vuota come dati.

     

c) è un'idea ragionevole fino a quando il dato è una lista di stringhe.

     

d) è una cattiva idea, perché il default [] si accumulano i dati e il default [] cambierà con le chiamate successive.

Risposta:

  

d) è una cattiva idea, perché il default [] si accumulano i dati e il default [] cambierà con le chiamate successive.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top