2011-08-26 5 views
6

Ho una domanda sulla funzione map in Python.Funzione mappa Python, passando per riferimento/valore?

Da quello che ho capito, la funzione non muta la lista su cui sta operando, ma ne crea una nuova e la restituisce. È corretto ?

Inoltre, ho il seguente pezzo di codice

def reflect(p,dir): 
    if(dir == 'X'): 
    func = lambda (a,b) : (a * -1, b) 
    else: 
    func = lambda (a,b) : (a, b * -1) 
    p = map(func,p) 
    print 'got', p 

points è un array di tuple quali: [(1, 1), (-1, 1), (-1, -1), (1, -1)]

Se chiamo la funzione precedente in modo tale:

print points 
reflect(points,'X') 
print points 

l'elenco points non cambia. All'interno della funzione, tuttavia, la funzione di stampa stampa correttamente ciò che voglio.

Qualcuno potrebbe indicarmi in qualche direzione in cui potrei imparare come tutto questo passaggio per valore/riferimento ecc funziona in python e come posso risolvere il problema precedente? O forse sto cercando troppo difficile da emulare Haskell in pitone ...

Grazie

edit:

Say invece di p = map(func,p) Io

for i in range(len(p)): 
    p[i] = func(p[i]) 

Il valore della lista è aggiornato al di fuori della funzione, come se lavorasse per riferimento. Ugh, spero che questo sia chiaro: S

+0

Potresti spiegare un po 'più esplicitamente qual è la tua domanda/problema? Il riferimento ad Haskel non è molto utile per i programmatori non Haskel. – Achim

+0

Ehi.Sì, mi dispiace per questo, forse ignoro semplicemente il commento di haskell. Sono solo sorpreso dal fatto che anche se faccio 'p = map (func, p)', la lista p non è cambiata al di fuori della funzione. Se sostituisco 'p = map (func, p)' con una iterazione di lista, sembra funzionare. – rafalio

+0

Python non passa né per valore né per riferimento, python passa per oggetto. –

risposta

12

Hai frainteso il modo in cui i riferimenti funzionano in Python. Qui, tutti i nomi sono riferimenti, non ci sono "valori". I nomi sono legati agli oggetti. Ma = non modifica l'oggetto che è puntato da nome - è rebinds il nome a un oggetto diverso:

x = 42 
y = x 
# now: 
# 'is' is a identity operator — it checks whether two names point to the 
# exact same object 
print x is y # => True 
print x, y # 42 42 
y = 69 
# now y has been rebound, but that does not change the '42' object, nor rebinds x 
print x is y # => False 
print x, y # 42 69 

Per modificare l'oggetto stesso, ha bisogno di essere mutabile - vale a dire esporre i membri che mutano o avere un dettato modificabile La stessa cosa di cui sopra si verifica quando si effettua il rebind p - non tocca affatto points, modifica semplicemente il significato del nome locale p.

Se si desidera simulare riferimenti di tipo C++, è necessario incapsulare l'oggetto in un contenitore mutabile, ad es. una lista.

reflect([points], 'X') 

# inside reflect: 
p[0] = ... 

Ma non si dovrebbe, almeno in questo caso, si dovrebbe semplicemente restituire il nuovo oggetto.

points = reflect(points, 'X') 

# inside reflect, instead of p = ... 
return map(func, p) 

Bene, ora che ci penso, si può anche fare

p[:] = map(func, p) 

Ma ancora una volta, tornando nuovo oggetto è solitamente migliore.

+0

Ah ok, questo ha senso. Ero confuso e pensavo che l'operatore "=" funzionasse diversamente da come funziona, grazie. – rafalio

0

Il modello di dati di Python si basa su una trilogia:
identificatore - di riferimento - oggetto

.

  • L'identificatore è un string scritto nel codice.
  • Il riferimento è una variabile senso stretto, vale a dire "un pezzo di memoria il cui contenuto può cambiare". Il valore di un riferimento è l'indirizzo dell'oggetto.
  • L'oggetto ha un'implementazione basata sulle strutture del langage C che sono le basi di Python.

altre parole sono utilizzati anche per designare la 'identificatore':
1) nome
2) variabile; perché questa parola è usata dalla metonimia in matematica per designare i simboli che rappresentano le vere variabili matematiche, e le variabili in un computer hanno concettualmente lo stesso funzionamento delle variabili matematiche (i loro valori possono cambiare).
Questo uso in Python è una pessima abitudine secondo me: crea ambiguità e confusione con quella che viene chiamata "variabile" in informatica: "pezzo di memoria il cui contenuto può cambiare".

La cosa migliore è usare la parola: identificatore

.

Un identificatore e un oggetto sono vincolati in un determinato spazio dei nomi. I namespace sono visualizzati sotto forma di dizionari Python, ma NON SONO dizionari.

  • La obbligatorio dell'identificatore e l'oggettoè indiretto, tramite il riferimento.

  • La obbligatorio dell'identificatore e la riferimento è diretta, e realizzato nel simbolo TABLE (o tabella di simboli).

In informatica, una tabella dei simboli è una struttura dati usata da un traduttore linguaggio come un compilatore o interprete, in cui ogni identificatore nel codice sorgente di un programma è associato con le informazioni relative alla sua dichiarazione o aspetto nell'origine, come il suo tipo , il livello di ambito e talvolta la sua posizione.
http://en.wikipedia.org/wiki/Symbol_table

Dicono: identificatori. Precisamente.
Raramente vedo allusioni alla tabella dei simboli, sebbene sia la cosa fondamentale che fa luce sul funzionamento del modello di dati Python IMO.

Ritengo parola

vincolante

non designa un meccanismo preciso ed univoco ma globalmente l'insieme di tutti i meccanismi che regolano l'identificatore trilogia - riferimento - oggetto

.

Non pretendo di aver perfettamente compreso tutte le questioni relative ai dati e ai modelli di esecuzione di Python e che le considerazioni precedenti sono le più precise e precise che si possono fare.
Tuttavia, mi consentono di avere una comprensione operativa di ciò che accade durante le esecuzioni di codice.
Sarei molto felice di essere corretto su alcuni punti se sbaglio (per Esempio, sono molto soddisfatto di aver appreso da Michael Foord che la natura degli spazi dei nomi non è essere dizionario, che è solo il modo in cui vengono rappresentati)

.

Detto questo, non so quello che viene chiamato il valore di riferimento e quando il soggetto di passare qualcosa come argomento in Python è discusso, e ho l'impressione che molte delle persone che hanno espresso sull'argomento in numerose le discussioni esoteriche non ne sanno più di me. Penso che non ci sia un parere migliore e lucida sull'argomento che questo uno dei Alex Martelli:

"Cercare di riutilizzare terminologia che è più in generale applicata a lingue in cui 'le variabili sono scatole' ad un linguaggio dove "le variabili sono tag post-it" è, IMHO, più probabilità di confondere che aiutare. "

Alex Martelli

http://bytes.com/topic/python/answers/37219-value-reference

+0

In risposta al flag moderatore, solo le domande possono contenere tag. Le risposte hanno automaticamente lo stesso tag (non visualizzato) come la domanda a cui rispondono. –

+0

@Bill the Lizard Grazie. L'ho capito dopo un po 'di tempo. La tua risposta è interessante, perché tu dici che anche le risposte sono identificate dalla domanda, anche se il tag non viene visualizzato. Era qualcosa di cui mi stavo chiedendo: cosa succede quando facciamo una ricerca con i tag? Ora so che i tag vengono presi in considerazione poiché le risposte sono contrassegnate. – eyquem

0

voglio urtare questo. Le risposte in realtà non rispondono alla domanda - ignorano il fatto che l'OP è stata in grado di ottenere il risultato desiderato iterando. La domanda si riduce al comportamento di map. Ecco un esempio più diretta:

f=(lambda pair: pair[0].append(pair[1])) 
a = ([],1) 
f(a) 
print(a) #prints ([1],1) 
a=([],1) 
map(f,[a]) 
print(a) #prints ([0],1) 

Quindi mappa non sta mutando gli oggetti nel modo in cui l'OP si aspetta. Ho la stessa confusione.

chiunque può commentare su esattamente che cosa sta succedendo qui? Penso che sarebbe una buona risposta alla domanda dell'OP.

notare che abbiamo un comportamento diverso se si assegna l'uscita del map come segue (come da risposta Cat Plus Plus')

f=(lambda pair: pair[0].append(pair[1])) 
a = ([],1) 
x = [a] 
x[:] = map(f,x) 
print(x) #prints None 
print(a) # prints [1] 

Si prega di notare che nel primo esempio, abbiamo semplicemente chiamati f(a), non a=f(a) . Perché abbiamo bisogno dell'assegnazione quando si utilizza map e non quando si lavora al di fuori di map?

Problemi correlati