Confusione relativa alla funzione def in Python

5

Ho imparato Python per circa 2 mesi (Iniziato con Learn Python The Hard Way, ora sto leggendo Dive Into Python), e all'interno di entrambi i libri, mi sembra ancora di essere confuso su questo un bit di codice.

Ti basterà prendere il codice predefinito che Dive Into Python usa come esempio:

def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.


    Returns string."""
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

if __name__ == "__main__":
    myParams = {"server":"mpilgrim",
                "database":"master",
                "uid":"sa",
                "pwd":"secret"
               }

print buildConnectionString(myParams)

Come fa la funzione buildConnectionString con l'argomento (params) a sapere di ottenere i suoi dati dalla variabile myParams ? O params.items() , anche all'interno della riga return ? L'argomento in buildConnectionString non dovrebbe essere impostato come buildConnectionString(myParams) per poter essere letto correttamente? Come puoi impostare la variabile dei tuoi dati su myParams , ma avere l'argomento della tua funzione essere params e leggerlo? Come fa a leggere myParams come params ?

E c'è una ragione dietro non nominare la tua variabile params , o viceversa nominare il tuo argomento nella tua funzione myParams ? È stato estremamente confuso vedere l'argomento impostato come una parola, e poi avere la variabile denominata qualcosa di completamente diverso, ma avere la funzione è ancora in grado di leggere il tuo codice, anche quando il nome dell'argomento è diverso dalla tua variabile con i dati che tu hai " stampa da.

    
posta Kevin 25.07.2012 - 13:02
fonte

8 risposte

8

Non si tratta di Python.

Ma comunque, per risponderti francamente. Diciamo che hai una funzione:

def doSomethingWithParmas(params):
    params.doSomething()

Ora puoi chiamarlo in seguito con:

print doSomethingWithParams(myParams)

e / o

print doSomethingWithParams(yourParams)

È come funzionano le funzioni, puoi chiamarlo con qualsiasi parametro che ti piace, tutta la funzione che importa, è che sono una sorta di param che può gestire.

EDIT: Un'osservazione: non ho mai codificato una riga di Python nella mia vita.

    
risposta data 25.07.2012 - 13:40
fonte
5

Forse sarebbe più chiaro se gli argomenti fossero diversamente nominati?

def buildConnectionString(placeholder_for_whatever_is_passed_in):
    return ";".join(["%s=%s" % (k, v) for k, v in placeholder_for_whatever_is_passed_in.items()])

if __name__ == "__main__":
    what_I_actually_pass in = { "server":"mpilgrim",
                                "database":"master",
                                "uid":"sa",
                                "pwd":"secret"   } 

print buildConnectionString(what_I_actually_pass_in)
    
risposta data 28.07.2012 - 03:27
fonte
1

Se diamo un'occhiata a

def buildConnectionString(params):
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

params è una variabile localmente applicata . Non si riferisce ad altre variabili nel codice, è il nome della variabile che si passa alla funzione. Ciò significa che puoi passare qualsiasi variabile in buildConnectionString() senza dover sapere in anticipo cosa stai passando.

Per quanto riguarda il nominare myParams rispetto a params non c'è una vera ragione. Puoi facilmente chiamarlo params se ti aiuta a tenere traccia delle cose. Ma cosa succede quando è necessario mantenere due serie di variabili params? Questo è il motivo per cui si passano le variabili nella propria funzione anziché le variabili globali di riferimento (definite al di fuori di una funzione). Potresti aver scritto quella funzione come

myParams = {"server":"mpilgrim",
            "database":"master",
            "uid":"sa",
            "pwd":"secret"
           }

def buildConnectionString():
    return ";".join(["%s=%s" % (k, v) for k, v in myParams.items()])

print buildConnectionString(myParams)

Fare ciò significa che puoi stampare solo myParams . Ma se definisci myOtherParams non puoi stamparlo affatto. Devi solo ricordare che tutte le variabili definite all'interno delle parentesi sono solo una copia della variabile che ci passi sopra, non la stessa variabile originale.

    
risposta data 28.07.2012 - 22:38
fonte
1

Per prima cosa, devi capire a cosa servono le funzioni. Potresti dire che una funzione fornisce un servizio: fa qualcosa per te.

Funzioni

  • Fornisci un servizio
  • non sai che esisti

Una stampante ad esempio è una sorta di servizio: stampa documenti per te, non devi farlo tu stesso. Se fornisci alla stampante le informazioni necessarie (i parametri), la stampante farà felicemente il suo lavoro.

La stampante non sa quali dati riceverà, altrimenti non avrebbe bisogno di un parametro. Il parametro è lo "sconosciuto" necessario per eseguire il servizio.

def my_function(a, b):
    pass

Questo fornisce un servizio (o una funzione) che richiede due informazioni da te. Una volta che ha questa informazione, deve essere in grado di riferirsi ad essa in qualche modo . La notazione (a, b) significa semplicemente che qualunque cosa tu gli dai come prima "informazione", sarà accessibile dal nome a e quello che passi secondo sarà accessibile dal nome b .

Quando si chiama effettivamente la funzione (ad esempio, indica alla stampante di stampare effettivamente qualcosa), è necessario riempire queste lacune di conoscenza in questo modo:

my_function(data_that_i_know, other_data_that_i_know)

Le tue domande

How does the function buildConnectionString with the argument (params) know to get it's data from the variable myParams?

Non è così. La mia stampante sa che sto per stampare un documento relativo alla programmazione di domani? No. Domani invierò le informazioni alla mia stampante, che stamperà felicemente. La stampante non sa nemmeno che esisto.

Allo stesso modo, "invia" (passa) i dati ( myParams ) alla tua funzione con la seguente espressione:

buildConnectionString(myParams)

In qualche altro punto del tuo programma, potresti voler eseguire la tua funzione con dati diversi. Simile alla stampante, la funzione non sa chi la chiamerà, o quando verrà chiamata, o con quali dati verrà chiamata.

Or params.items(), too within the return line?

La funzione, una volta eseguita, ha ricevuto alcuni dati in modo che possa svolgere il proprio lavoro. Questo eseguirà una funzione chiamata items() su qualunque funzione sia stata assegnata alla funzione.

Una funzione di esempio

Voglio creare il mio servizio, che può calcolare il quadrato di un numero. Ciò implica che è necessario fornire un numero per poter funzionare. Dopotutto, non puoi quadrare nulla, vero?

La funzione non sa, quale numero sarà dato. Tuttavia, per essere in grado di moltiplicare questo numero, dobbiamo essere in grado di fare riferimento ad esso in qualche modo, quindi, gli diamo un nome: x .

def square(x):
    return x * x

Definisce una funzione chiamata square a cui deve essere assegnato un pezzo di dati (il x ).

Ora posso usare questa funzione per quadrare un numero:

>>> print square(2) # "Please square this number 2 for me"
4

All'interno della funzione, x ora si riferisce al valore 2 .

Ma avrei anche potuto chiamare la funzione con il numero 3:

>>> print square(3) # "Please square this number 2 for me"
9

Avrei potuto scegliere il nome two invece di x per la mia funzione. Ma questo sarebbe fuorviante: il valore non deve essere 2 , può essere qualunque cosa io desideri che sia.

And is there a reason behind not naming your variable params, or vice versa naming your argument in your function myParams?

I nomi nella programmazione possono essere scelti arbitrariamente, a condizione che non siano riservati dalla lingua (sono chiamati parole chiave).

Solitamente, nominerai le tue variabili in qualunque senso abbia senso in quel contesto. Ad esempio, nel codice relativo agli oggetti geometrici, la mia variabile locale può essere denominata area che verrà quindi quadrata utilizzando la funzione square() . Nel codice di un'auto, potrei avere una variabile denominata weight nell'altra mano. Sono sicuro che sarai d'accordo che posso chiamare square con square(weight) e square(area) trasmette un sacco di informazioni.

Ora modificheresti il parametro square da x a weight_or_area ? Spero che non lo faresti. Cosa succede se dovessi utilizzare la funzione in relazione a length s? Dovrai abituarti al fatto che i parametri e gli argomenti delle funzioni sono di solito denominati in modo diverso, ovvero Good Thing® .

It's just been extremely confusing seeing the argument set as one word, and then having the variable named something completely different, but having the function still be able to read your code, even when the argument name is different from your variable with the data you're printing from.

È importante capire che la funzione non legge il tuo codice. Non ha idea nemmeno esiste. Questo ci riporta all'analogia della stampante: sa che tu o io esistiamo? No, è lì per svolgere un lavoro, senza fare domande. La stessa cosa vale per le funzioni: sono lì per fare le nostre offerte. Non agiscono da soli e "leggono il codice" per vedere dove sono referenziati.

    
risposta data 28.07.2012 - 23:17
fonte
1

Hai ragione a chiedersi perché questo simbolo non sembra significare nulla per il resto del file, ma la sua ortografia non è il suo unico attributo. Considera il suo posizionamento.

La confusione sta nel cercare di equiparare il nome del parametro e il nome dell'argomento. Hai ragione, non c'è connessione tra i nomi in quanto tali. Ma se hai visto un messaggio di errore di Python a causa di un argomento mancante all'interno di parentesi, potresti vedere la terminologia "argomento posizionale". È il posizionamento dell'argomento tra parentesi dopo il richiamo della funzione x che identifica l'argomento come corrispondente al parametro dall'istruzione def della stessa funzione.

Ti chiedi perché il parametro e l'argomento non hanno lo stesso nome. I due nomi hanno la stessa posizione rispetto al nome della funzione, che è la loro unica connessione.

Che cosa è significativo in questa funzione:

print('Say anything.')
nilj = input()
def rabberd(durf):
    print(nilj + ' what?')

rabberd(nilj)

Significativo per Python: "def", "input" e "print".

Significativo per il file:

  • rabberd is rabberd
  • nilj è input
  • posizionamento relativo di nilj e durf li equivalgono tra loro.
  • durf in quanto una parola è arbitraria; solo la sua posizione è significativa.
risposta data 07.03.2015 - 06:43
fonte
0

Devi leggere questo per una comprensione completa di come funzionano le funzioni ei loro parametri in python: link

Una semplice spiegazione è che l'interprete python corrisponde al primo parametro nella tua chiamata di funzione al primo valore nella definizione della funzione, il secondo al secondo e così via se i parametri nella chiamata di funzione non sono denominati.

Nel tuo esempio, quando fai print buildConnectionString(myParams) come hai fatto, python presuppone che tu intenda print buildConnectionString(params=myParams) che è una buona ipotesi da prendere. Il valore dei parametri può essere qualsiasi cosa tu voglia, ma se incasini il nome del parametro stesso, otterrai un errore.

Questo non ti darà un errore: print buildConnectionString(params=whateveryouwant)

Ma questo ti darà un errore: print buildConnectionString(wrongparametername=myParams)

    
risposta data 29.07.2012 - 19:07
fonte
0

Stai notando la differenza tra parametri e argomenti e anche la nozione di ambito .

Un parametro è un nome che fa riferimento a un valore passato in una funzione. Considera una definizione di funzione banale:

def f(x):
    return x

Qui, x è un parametro di f . Un argomento è il valore assegnato a un parametro durante una chiamata di funzione.

print f(42)

Qui, 42 è un argomento a f . In una chiamata di funzione, puoi pensare di sostituire tutte le istanze del parametro (nome) con l'argomento (valore). Quindi quando scrivi f(42) , ciò che fa l'interprete è return 42 .

Allo stesso modo, quando scrivi buildConnectionString(myParams) , è esattamente come se avessi scritto:

";".join(["%s=%s" % (k, v) for k, v in {
    "server":"mpilgrim",
    "database":"master",
    "uid":"sa",
    "pwd":"secret" }.items()])

params viene sostituito con il valore di myParams e le istruzioni risultanti vengono eseguite.

    
risposta data 07.03.2015 - 08:11
fonte
0

Ok, quando ho capito bene il tuo problema è che non sai perché i param all'interno della funzione sono associati al dizionario myParams che hai inserito nella funzione, giusto?

Ok, iniziamo dall'inizio:

Quando hai il seguente codice Python, come fa Python a sapere che puoi chiamare il metodo upper() (che rende tutto maiuscolo) sulla variabile?

a = "hello"
...
print a.upper() 

a potrebbe essere un numero intero se abbiamo scritto a = 1 anziché a = "hello" . Ma come forse hai già imparato, python è un linguaggio dinamico ed è in grado di gestirlo senza definire cosa dovrebbe tenere una variabile in primo luogo.

Ora per il tuo problema con la funzione. Diciamo che abbiamo la seguente funzione:

def divide(a,b)
    return a / b

a e b non sono solo parametri, sono variabili. Quando python vede la riga result = divide(4,2) , tecnicamente fa quanto segue:

""" Create local variables and assign the input values to them """
a = 4
b = 2
result = a / b
""" Because the variables were local they do not exists after the function
    call ended """

Se ora proviamo a chiamare questa funzione come divide("hello","world") il programma si blocca perché non puoi usare la divisione sulle stringhe. Fin qui tutto bene.

Quindi la tua domanda può essere ridotta al seguente problema:

myParams = { "foo":"bar", "meow":"purr" }
someOtherVariable = myParams
print someOtherVariable["meow"]

In che modo Python sa che someOtherVariable può essere trattato come myParams ? Perché gli abbiamo detto di essere lo stesso. E questo è esattamente ciò che accade quando chiami la tua funzione con myParams . Rende implicitamente params = myParams fino alla fine della chiamata di funzione. Questo codice funziona perché la funzione presuppone che il contenuto di params abbia i metodi su cui viene chiamato (in questo esempio items() ). In caso contrario, si blocca. Puoi provare questo chiamando buildConnectionString(1) . Dirà che int has no attribute 'items' .

TLDR; i parametri delle funzioni sono come normali variabili. Python prova a fare con loro quello che hai scritto nel tuo corpo della funzione - se tu chiami funzioni sugli oggetti che non hanno il tuo programma si blocca come farebbe quando hai fatto la stessa cosa con una variabile normale.

    
risposta data 07.03.2015 - 09:22
fonte

Leggi altre domande sui tag