10

A purefunction è una funzione simile a una funzione matematica, in cui non vi è alcuna interazione con il "mondo reale" né effetti collaterali. Da un punto di vista più pratico, ciò significa che una funzione puro può non:Come verificare se una funzione è pura in Python?

  • Stampa o comunque mostrare un messaggio
  • essere casuale
  • dipendono dal tempo del sistema
  • modificare le variabili globali
  • E altri

Tutte queste limitazioni rendono più facile ragionare sulla funzione pura s di quelli non puri. La maggior parte delle funzioni dovrebbe quindi essere pura in modo che il programma possa avere meno bug.

In lingue con un enorme sistema di tipi come Haskell il lettore può sapere fin dall'inizio se una funzione è o non è pura, rendendo più facile la lettura successiva.

In Python questa informazione può essere emulata da un decoratore @pure messo sopra la funzione. Mi piacerebbe anche che il decoratore eseguisse effettivamente dei lavori di validazione. Il mio problema sta nell'implementazione di un decoratore di questo tipo.

In questo momento guardo semplicemente il codice sorgente della funzione per parole chiave come global o random o print e si lamenta se ne trova uno.

import inspect 

def pure(function): 
    source = inspect.getsource(function) 
    for non_pure_indicator in ('random', 'time', 'input', 'print', 'global'): 
     if non_pure_indicator in source: 
      raise ValueError("The function {} is not pure as it uses `{}`".format(
       function.__name__, non_pure_indicator)) 
    return function 

Tuttavia ci si sente come un hack strano, che può o non può funzionare a seconda della fortuna, la prego di aiutarmi a scrivere un decoratore di meglio?

+3

Si potrebbe 'inspect.getsource' quindi' ast.parse' e ​​si cammina con i nodi per controllare varie cose ... ma si andrebbe contro il motivo per cui esiste la lingua - guarda usando il modulo 'abc' se vuoi roba, quindi 'isinstance' controlla dove devono essere ... - python è ** fortemente ** digitato - non ** staticamente ** digitato –

+0

@JonClements i linguaggi dinamici di fatto eseguono meno verifiche in fase di compilazione, ma penso che sia un controllo particolare migliorerebbe notevolmente l'organizzazione del programma e controllerebbe di nuovo la comprensione del proprio lavoro da parte dei programmatori. – Caridorc

+4

Quindi usa un linguaggio tipizzato staticamente ... :) Puoi vederlo come una cosa * male * o * buona * ... ma è così che è –

risposta

9

Vedo da dove vieni ma non penso che funzioni.Facciamo un semplice esempio:

def add(a,b): 
    return a + b 

Quindi questo probabilmente sembra "puro" per te. Ma in Python il + qui è una funzione arbitraria che può fare qualsiasi cosa, solo in base ai binding in vigore quando viene chiamata. In modo che a + b può avere effetti collaterali arbitrari.

Ma è anche peggio di così. Anche se questo è solo il numero intero standard +, allora c'è altro materiale "impuro" in corso.

+ sta creando un nuovo oggetto. Ora, se sei sicuro che solo il chiamante ha un riferimento a quel nuovo oggetto, allora c'è un senso in cui puoi pensare a questo come a una funzione pura. Ma non puoi essere sicuro che, durante il processo di creazione di quell'oggetto, nessun riferimento sia trapelato.

Ad esempio:

class RegisteredNumber(int): 

    numbers = [] 

    def __new__(cls,*args,**kwargs): 
     self = int.__new__(cls,*args,**kwargs) 
     self.numbers.append(self) 
     return self 

    def __add__(self,other): 
     return RegisteredNumber(super().__add__(other)) 

c = RegisteredNumber(1) + 2 

print(RegisteredNumber.numbers) 

Questo mostrerà che la funzione add presunto puro è effettivamente cambiato lo stato della classe RegisteredNumber. Questo non è un esempio stupidamente inventato: nella mia base di codice di produzione abbiamo classi che tengono traccia di ogni istanza creata, ad esempio, per consentire l'accesso tramite chiave.

La nozione di purezza non ha molto senso in Python.

0

(non una risposta, ma troppo lungo per un commento)

Quindi, se una funzione può restituire valori diversi per lo stesso insieme di argomenti, non è puro?

Ricordate che le funzioni in Python sono oggetti, quindi si desidera controllare la purezza di un oggetto ...

Prendete questo esempio:

def foo(x): 
    ret, foo.x = x*x+foo.x, foo.x+1 
    return ret 
foo.x=0 

chiamando ripetutamente foo(3) dà:

>>> foo(3) 
9 

>>> foo(3) 
10 

>>> foo(3) 
11 

...

Inoltre, la lettura di globals non richiede l'uso dell'istruzione global o del global() incorporato nella funzione. Le variabili globali potrebbero cambiare da qualche altra parte, influenzando la purezza della tua funzione.

Tutte le situazioni di cui sopra potrebbero essere difficili da rilevare in fase di esecuzione.

+0

Interessante idea, ma posso pensare a molte funzioni che non sono pure che potrebbero sembrare così a breve termine come ottenere l'ora del giorno, numero di versione o/s, ramo git corrente, ecc. – wallyk

Problemi correlati