2014-10-30 8 views
6

È Pythonic usare or, in modo simile a come PHP userebbe or die()?Sarebbe pietonico usare `or`, in modo simile a come PHP userebbe` o die() `?

Sono stato con
quiet or print(stuff)
invece di
if verbose: print(stuff)
ultimamente.

Penso che sia più bello, fanno la stessa cosa, e salva in linea. Sarebbe meglio dell'altra in termini di prestazioni?

Il bytecode sia più o meno lo stesso per me, ma io non so davvero cosa sto guardando ...

or


    2   0 LOAD_FAST    0 (quiet) 
       3 JUMP_IF_TRUE_OR_POP  15 
       6 LOAD_GLOBAL    0 (print) 
       9 LOAD_CONST    1 ('foo') 
      12 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
     >> 15 POP_TOP 
      16 LOAD_CONST    0 (None) 
      19 RETURN_VALUE 

vs if


    2   0 LOAD_FAST    0 (verbose) 
       3 POP_JUMP_IF_FALSE  19 

    3   6 LOAD_GLOBAL    0 (print) 
       9 LOAD_CONST    1 ('bar') 
      12 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      15 POP_TOP 
      16 JUMP_FORWARD    0 (to 19) 
     >> 19 LOAD_CONST    0 (None) 
      22 RETURN_VALUE 
+4

Si prega di non farlo. – PaulMcG

+0

Penso che tu abbia chiesto :) –

+0

Non sembra più gradito a nessuno che non sia un programmatore PHP. Per quanto riguarda il salvataggio di una linea, c'è una carenza di linee in cui vivi? Abbiamo extra. –

risposta

18

No, questo non è sicuramente Pythonic. Molte delle decisioni prese lungo il percorso sono state appositamente per scoraggiare questo tipo di codifica.


Il modo giusto di scrivere questo è il modo più ovvio:

if verbose: 
    print(stuff) 

Oppure, se il calcolo stuff di per sé non è costoso/pericolosi/irrevocabile, basta avvolgere print in una funzione che controlla la bandiera:

def printv(*args, **kwargs): 
    if verbose: 
     print(*args, **kwargs) 

... così si può solo fare questo, che è quanto di più conciso, come si sta andando ad ottenere:

printv(stuff) 

Oppure, ancora meglio, utilizzare il modulo logging invece di reinventare la ruota.


Ma cosa succede se stuff è costoso, e si vuole veramente salvare una linea?

Bene, probabilmente non è necessario salvare una riga, e così facendo si sacrifica sempre la leggibilità per brevità; "Conteggi di leggibilità" è una parte fondamentale di the Zen of Python.Ma Python non consentono di mettere una suite con una linea sulla stessa riga della condizione:

if verbose: print(stuff) 

Come PEP 8 lo mette, "a volte va bene", ma è "generalmente scoraggiato". Come ha scritto Guido in una mail sulla mailing list delle idee, "Se devi salvare una riga, usa una frase se una riga piuttosto che qualcosa di 'intelligente', ma se devi salvare una riga, probabilmente non voglio leggi il tuo codice. "

Se si desidera che questo in un'espressione (che non si dovrebbe, come spiegherò più avanti), o se si vuole tecnicamente follow PEP 8 alla lettera, mentre palesemente violando lo spirito:

print(stuff) if verbose else None 

Quindi, cosa c'è di Pythonic a riguardo?

Per prima cosa, si sta utilizzando il risultato di print in un'espressione, anche se print non ha risultati utili e viene chiamato solo per i suoi effetti collaterali. Questo è fuorviante.

E in generale, Python ha solo un effetto collaterale per riga, e si verifica il più a sinistra possibile, il che rende più facile scremare il codice e vedere cosa sta cambiando. Ciò è rafforzato dal forte divario tra le dichiarazioni e le espressioni (e, ad esempio, i compiti sono dichiarazioni), dai metodi con effetti collaterali che restituiscono idiomaticamente None anziché self e così via.

Ma anche ignorare tutto questo, usando and e or solo per cortocircuiti, piuttosto che per i loro risultati, è potenzialmente confuso e, almeno per alcune persone, brutto. Ecco perché è stata aggiunta l'espressione ternaria (spam if eggs else beans): per impedire alle persone di scrivere eggs and spam or beans. Perché è confuso? Per prima cosa, in realtà non legge affatto l'inglese, a meno che tu non stia leggendo più codice Perl che inglese corrente. Per un altro, è molto facile usare per errore un valore valido che è falso; sai di non farlo, e per controllarlo, quando vedi un if, ma non lo fai qui. Si noti inoltre che lo print(stuff) if verbose else None rende esplicito che si sta creando un valore con cui non si fa nulla; esplicito è sempre meglio di implicito, ma soprattutto quando fai qualcosa di non comune.


Infine, per quanto riguarda le prestazioni: (a) chi se ne frega, e (b) il motivo per cui non misura, invece di tentare di indovinare leggendo bytecode che non capisci?

In [511]: quiet = True 
In [512]: %timeit quiet or None 
10000000 loops, best of 3: 48.2 ns per loop 
In [513]: verbose=False 
In [514]: %timeit if verbose: pass 
10000000 loops, best of 3: 38.5 ns per loop 

Così ci si va, nel caso-pass fast food, la dichiarazione if è in realtà circa il 20% più veloce, non più lento e sono entrambi così velocemente che è improbabile che possa influenzare mai il vostro programma in ogni caso . Se stai facendo questo un miliardo di volte in un circuito chiuso e hai bisogno di spremere quella performance, vorrai sollevare il resto del ciclo, anche se questo significa ripetersi con due cloni vicini dello stesso codice (specialmente considerando che un loop senza lo print s è più probabile che si adatti alla cache, ecc.).

Se vuoi sapere perché, dovresti esaminare l'implementazione di quei bytecode sulla particolare versione dell'implementazione particolare che ti interessa ... ma molto probabilmente, dovresti fare un extra POP_TOP invece di avere una fusione nell'operazione precedente fa parte della differenza.

+1

'se verbose: print (stuff)' non è così pythonic, verifica PEP8 – ErlVolton

+0

@ErlVolton: È lontano _more_ Pythonic di quello che la domanda sta facendo. – abarnert

+0

No, non è !! È altrettanto brutto del suo esempio – ErlVolton

3

Non penso che questo sia pitonico. ("Explicit è meglio di implicito").

È possibile scrivere

if verbose: print(stuff) 

quindi se hai un disperato bisogno di tenere contare il vostro linea verso il basso, è possibile.

Il modo più divinatorio ("leggibilità conta".) Sarebbe ancora utilizzare

if verbose: 
    print(stuff) 
+0

Non sono sicuro che questo cada sotto "esplicito è meglio di implicito", almeno direttamente. Ma sicuramente rientra in "conteggi di leggibilità"! (Stavo cercando di pensare a quali parti dello zen fare riferimento, e mi mancava quello più ovvio. :)) – abarnert

+1

@abarnert: Sì, la leggibilità ha un ruolo più importante qui. Con "implicito" mi riferivo alla scelta progettuale di Python (forse non ovvia) per valutare solo un'espressione se la condizione booleana non è stata ancora soddisfatta. Le persone potrebbero chiedersi perché 'print()' non viene sempre chiamato se non sanno di questa funzione. –

Problemi correlati