Funzionalità nascoste di Python [chiuso]


1419

Quali sono le funzionalità meno conosciute ma utili del linguaggio di programmazione Python?

  • Prova a limitare le risposte al core di Python.
  • Una funzione per risposta.
  • Fornisci un esempio e una breve descrizione della funzione, non solo un collegamento alla documentazione.
  • Etichetta la funzione usando un titolo come prima riga.

Collegamenti rapidi alle risposte:

Risposte:


740

Concatenare operatori di confronto:

>>> x = 5
>>> 1 < x < 10
True
>>> 10 < x < 20 
False
>>> x < 10 < x*10 < 100
True
>>> 10 > x <= 9
True
>>> 5 == x > 4
True

Nel caso in cui stai pensando che stia facendo 1 < x, che viene fuori come True, e quindi confrontando True < 10, che è anche True, quindi no, non è proprio quello che succede (vedi l'ultimo esempio.) Si sta davvero traducendo in 1 < x and x < 10, ex < 10 and 10 < x * 10 and x*10 < 100 , ma con meno digitazioni e il termine viene valutato una sola volta.


121
Questo è molto utile. Dovrebbe essere standard per tutte le lingue. Purtroppo no.
stalepretzel,

8
dovresti aggiungere alcuni esempi che restituiscono anche false. come >>> 10 <x <20 False
ShoeLace,

19
Questo vale anche per altri operatori di confronto, motivo per cui le persone a volte sono sorprese dal fatto che code like (5 in [5] è True) sia False (ma non è vero testare esplicitamente contro booleani come quello per cominciare).
Miglia

19
Buono ma attenzione per la stessa prcedenza, come 'in' e '='. 'A in B == C in D' significa '(A in B) e (B == C) e (C in D)' che potrebbero essere inattesi.
Charles Merriam

15
Azafe: I confronti di Lisp funzionano naturalmente in questo modo. Non è un caso speciale perché non esiste un altro (ragionevole) modo di interpretare (< 1 x 10). Puoi persino applicarli a singoli argomenti, come ad esempio (= 10): cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/…
Ken

512

Ottieni l'albero di analisi di regex python per eseguire il debug di regex.

Le espressioni regolari sono una grande caratteristica di Python, ma il loro debug può essere una seccatura, ed è fin troppo facile sbagliare una regex.

Fortunatamente, Python può stampare l'albero di analisi regex, passando la bandiera nascosta, sperimentale, nascosta re.DEBUG(in realtà, 128) a re.compile.

>>> re.compile("^\[font(?:=(?P<size>[-+][0-9]{1,2}))?\](.*?)[/font]",
    re.DEBUG)
at at_beginning
literal 91
literal 102
literal 111
literal 110
literal 116
max_repeat 0 1
  subpattern None
    literal 61
    subpattern 1
      in
        literal 45
        literal 43
      max_repeat 1 2
        in
          range (48, 57)
literal 93
subpattern 2
  min_repeat 0 65535
    any None
in
  literal 47
  literal 102
  literal 111
  literal 110
  literal 116

Una volta compresa la sintassi, è possibile individuare gli errori. Ci possiamo vedere che ho dimenticato di sfuggire al []di[/font] .

Ovviamente puoi combinarlo con qualsiasi flag tu voglia, come regex commentati:

>>> re.compile("""
 ^              # start of a line
 \[font         # the font tag
 (?:=(?P<size>  # optional [font=+size]
 [-+][0-9]{1,2} # size specification
 ))?
 \]             # end of tag
 (.*?)          # text between the tags
 \[/font\]      # end of the tag
 """, re.DEBUG|re.VERBOSE|re.DOTALL)

3
Tranne analizzare HTML usando l'espressione regolare è lento e doloroso. Anche il modulo parser 'html' incorporato non usa regex per completare il lavoro. E se il modulo HTML non ti soddisfa, ci sono molti moduli parser XML / HTML che fanno il lavoro senza dover reinventare la ruota.
BatchyX,

Un collegamento alla documentazione sulla sintassi di output sarebbe ottimo.
Personman,

1
Questa dovrebbe essere una parte ufficiale di Python, non sperimentale ... RegEx è sempre difficile e riuscire a rintracciare ciò che sta accadendo è davvero utile.
Cahit,

460

enumerare

Avvolgi un iterabile con enumerato e produrrà l'oggetto insieme al suo indice.

Per esempio:


>>> a = ['a', 'b', 'c', 'd', 'e']
>>> for index, item in enumerate(a): print index, item
...
0 a
1 b
2 c
3 d
4 e
>>>

Riferimenti:


56
Sono sorpreso che questo non sia trattato abitualmente nei tutorial che parlano di liste di Python.
Draemon,

45
E per tutto questo tempo stavo codificando in questo modo: for i in range (len (a)): ... e quindi usando un [i] per ottenere l'elemento corrente.
Fernando Martin,

4
@Berry Tsakala: per quanto ne so, non è stato deprecato.
JAB,

23
Santa merda, questo è fantastico. per i in xrange (len (a)): è sempre stato il mio idioma di pitone meno preferito.
Personman,

15
l'enumerazione può iniziare dall'indice arbitrario, non necessario 0. Esempio: 'per i, elemento in elenco ( elenco , inizio = 1): stampa i, elemento' inizierà l'enumerazione da 1, non 0.
dmitry_romanov

419

Creazione di oggetti generatori

Se scrivi

x=(n for n in foo if bar(n))

puoi uscire dal generatore e assegnarlo a x. Ora significa che puoi farlo

for n in x:

Il vantaggio di questo è che non hai bisogno di memoria intermedia, di cui avresti bisogno se lo facessi

x = [n for n in foo if bar(n)]

In alcuni casi ciò può comportare una notevole accelerazione.

Puoi aggiungere molte istruzioni if ​​alla fine del generatore, sostanzialmente replicando nidificato per i loop:

>>> n = ((a,b) for a in range(0,2) for b in range(4,6))
>>> for i in n:
...   print i 

(0, 4)
(0, 5)
(1, 4)
(1, 5)

Potresti anche usare una comprensione dell'elenco nidificato per questo, sì?
shapr

54
Di particolare nota è il risparmio di memoria. I valori vengono calcolati su richiesta, quindi non si ha mai l'intero risultato della comprensione dell'elenco in memoria. Ciò è particolarmente desiderabile se in seguito si ripete solo una parte della comprensione dell'elenco.
saffsd,

19
Questo non è particolarmente "nascosto", ma vale anche la pena notare che non è possibile riavvolgere un oggetto generatore, mentre è possibile ripetere un elenco un numero di volte.
presume il

13
La funzione "nessun riavvolgimento" dei generatori può causare confusione. In particolare, se si stampa il contenuto di un generatore per il debug, quindi lo si utilizza in seguito per elaborare i dati, non funziona. I dati vengono prodotti, consumati da print (), quindi non sono disponibili per l'elaborazione normale. Questo non si applica alla comprensione dell'elenco, poiché sono completamente archiviati nella memoria.
johntellsall,

4
Risposta simile (duplice?): Stackoverflow.com/questions/101268/hidden-features-of-python/… Nota, tuttavia, che la risposta che ho qui menzionato menziona una presentazione VERAMENTE BUONA sul potere dei generatori. Dovresti davvero dare un'occhiata.
Denilson Sá Maia,

353

iter () può accettare un argomento richiamabile

Per esempio:

def seek_next_line(f):
    for c in iter(lambda: f.read(1),'\n'):
        pass

La iter(callable, until_value)funzione chiama ripetutamente callablee produce il suo risultato fino a quando non until_valueviene restituita.


Come novizio di Python, puoi spiegare perché la lambdaparola chiave è necessaria qui?
SiegeX,

@SiegeX senza lambda, f.read (1) verrebbe valutato (restituendo una stringa) prima di essere passato alla funzione iter. Invece, la lambda crea una funzione anonima e la passa a iter.
jmilloy,

339

Fai attenzione con argomenti predefiniti mutabili

>>> def foo(x=[]):
...     x.append(1)
...     print x
... 
>>> foo()
[1]
>>> foo()
[1, 1]
>>> foo()
[1, 1, 1]

Invece, dovresti usare un valore sentinella che indica "non fornito" e sostituirlo con il mutevole che desideri come predefinito:

>>> def foo(x=None):
...     if x is None:
...         x = []
...     x.append(1)
...     print x
>>> foo()
[1]
>>> foo()
[1]

39
Questa è sicuramente una delle più brutte funzionalità nascoste. Ci sono imbattuto di tanto in tanto.
Torsten Marek,

77
L'ho trovato molto più facile da capire quando ho appreso che gli argomenti predefiniti vivono in una tupla che è un attributo della funzione, ad es foo.func_defaults. Che, essendo una tupla, è immutabile.
Robert Rossney,

2
@grayger: man mano che l'istruzione def viene eseguita, i suoi argomenti vengono valutati dall'interprete. Questo crea (o ricollega) un nome a un oggetto codice (la suite della funzione). Tuttavia, gli argomenti predefiniti vengono istanziati come oggetti al momento della definizione. Questo vale per qualsiasi momento dell'oggetto predefinito, ma significativo (esponendo la semantica visibile) quando l'oggetto è mutabile. Non c'è modo di ricollegare quel nome di argomento predefinito nella chiusura della funzione sebbene possa ovviamente essere sovrascritto per qualsiasi chiamata o l'intera funzione può essere ridefinita).
Jim Dennis,

3
@Robert naturalmente gli argomenti tupla potrebbero essere immutabili, ma gli oggetti a cui punta non sono necessariamente immutabili.
poolie,

16
Un rapido trucco per rendere la tua inizializzazione un po 'più breve: x = x o []. È possibile utilizzare quello invece dell'istruzione if a 2 righe.
Dave Mankoff,

317

Invio di valori nelle funzioni del generatore . Ad esempio con questa funzione:

def mygen():
    """Yield 5 until something else is passed back via send()"""
    a = 5
    while True:
        f = (yield a) #yield a and possibly get f in return
        if f is not None: 
            a = f  #store the new value

Puoi:

>>> g = mygen()
>>> g.next()
5
>>> g.next()
5
>>> g.send(7)  #we send this back to the generator
7
>>> g.next() #now it will yield 7 until we send something else
7

Concordato. Trattiamo questo come un brutto esempio di una funzione nascosta di Python :)
Rafał Dowgird,

89
In altre lingue, credo che questo dispositivo magico sia chiamato "variabile".
finnw,

5
le coroutine dovrebbero essere coroutine e anche il geneneratore dovrebbe essere se stesso, senza mescolarsi. Mega-great link e talk ed esempi su questo qui: dabeaz.com/coroutines
u0b34a0f6ae

31
@finnw: l'esempio implementa qualcosa di simile a una variabile. Tuttavia, la funzione potrebbe essere utilizzata in molti altri modi ... a differenza di una variabile. Dovrebbe anche essere ovvio che una semantica simile può essere implementata usando oggetti (una classe che implementa il metodo call di Python , in particolare).
Jim Dennis,

4
Questo è un esempio troppo banale per le persone che non hanno mai visto (e probabilmente non capiranno) le co-routine. L'esempio che implementa la media corrente senza il rischio di overflow delle variabili di somma è buono.
Prashant Kumar l'

313

Se non ti piace usare gli spazi bianchi per indicare gli ambiti, puoi usare lo stile C {} emettendo:

from __future__ import braces

122
Questo è male. :)
Jason Baker il

37
>>> da __future__ importare parentesi graffe File "<stdin>", riga 1 Sintassi Errore: nessuna possibilità: P
Benjamin W. Smith,

40
questa è una bestemmia!
Berk D. Demir,

335
Penso che potremmo avere un errore sintattico qui, non dovrebbe essere "da __past__ import braces"?
Bill K,

47
da __cruft__ import braces
Phillip B Oldham,

305

L'argomento step negli operatori slice. Per esempio:

a = [1,2,3,4,5]
>>> a[::2]  # iterate over the whole list in 2-increments
[1,3,5]

Il caso speciale x[::-1]è un utile linguaggio per "x invertito".

>>> a[::-1]
[5,4,3,2,1]

31
molto più chiara, secondo me, è la funzione reversed (). >>> list (reverse (range (4))) [3, 2, 1, 0]
Christian Oudard

3
allora come scrivere "this ia string" [:: - 1] in un modo migliore? la retromarcia non sembra aiutare
Berry Tsakala,

24
Il problema con reversed () è che restituisce un iteratore, quindi se si desidera preservare il tipo di sequenza invertita (tupla, stringa, elenco, unicode, tipi di utente ...), è necessario un passaggio aggiuntivo per riconvertirlo .
Rafał Dowgird,

6
def reverse_string (stringa): return string [:: - 1]
pi.

4
@pi Penso che se uno sa abbastanza per definire reverse_string come hai, allora puoi lasciare il [:: - 1] nel tuo codice e sentirti a tuo agio con il suo significato e la sensazione che sia appropriata.
physicsmichael,

289

decoratori

I decoratori consentono di avvolgere una funzione o un metodo in un'altra funzione che può aggiungere funzionalità, modificare argomenti o risultati, ecc. Scrivi i decoratori una riga sopra la definizione della funzione, iniziando con un segno "at" (@).

L'esempio mostra un print_argsdecoratore che stampa gli argomenti della funzione decorata prima di chiamarla:

>>> def print_args(function):
>>>     def wrapper(*args, **kwargs):
>>>         print 'Arguments:', args, kwargs
>>>         return function(*args, **kwargs)
>>>     return wrapper

>>> @print_args
>>> def write(text):
>>>     print text

>>> write('foo')
Arguments: ('foo',) {}
foo

54
Quando definisco i decoratori, consiglierei di decorare il decoratore con @decorator. Crea un decoratore che conserva la firma di una funzione quando si fa introspezione su di essa. Maggiori informazioni qui: phyast.pitt.edu/~micheles/python/documentation.html
sirwart

45
In che modo questa è una funzione nascosta?
Vetle,

50
Bene, non è presente nella maggior parte dei semplici tutorial di Python e mi sono imbattuto molto tempo dopo aver iniziato a usare Python. Questo è ciò che definirei una funzione nascosta, praticamente uguale agli altri post principali qui.
DzinX,

16
Vetler, la domanda richiede "funzionalità meno note ma utili del linguaggio di programmazione Python". Come si misurano le "funzioni meno note ma utili"? Voglio dire come sono nascoste queste risposte?
Johnd,

4
@vetler La maggior parte delle cose qui non sono quasi "nascoste".
Humphrey Bogart,

288

La sintassi for ... else (vedi http://docs.python.org/ref/for.html )

for i in foo:
    if i == 0:
        break
else:
    print("i was never 0")

Il blocco "else" verrà normalmente eseguito alla fine del ciclo for, a meno che non venga chiamato il break.

Il codice sopra potrebbe essere emulato come segue:

found = False
for i in foo:
    if i == 0:
        found = True
        break
if not found: 
    print("i was never 0")

218
Penso che la sintassi for / else sia imbarazzante. "Sembra" come se la clausola else dovesse essere eseguita se il corpo del loop non viene mai eseguito.
codeape,

14
ah. Non l'ho mai visto! Ma devo dire che è un po 'improprio. Chi si aspetterebbe che il blocco else venga eseguito solo se break non lo fa mai? Sono d'accordo con codeape: sembra che sia stato inserito altro per i foos vuoti.
Daren Thomas,

52
sembra che la parola chiave dovrebbe essere finalmente, non altro
Jiaaro,

21
Tranne che finalmente è già usato in un modo in cui quella suite viene sempre eseguita.

7
Sicuramente non dovrebbe essere "altro". Forse 'then' o qualcosa del genere, e quindi 'else' per quando il loop non è mai stato eseguito.
Tor Valamo,

258

Da 2.5 in poi i dicts hanno un metodo speciale __missing__che viene invocato per gli oggetti mancanti:

>>> class MyDict(dict):
...  def __missing__(self, key):
...   self[key] = rv = []
...   return rv
... 
>>> m = MyDict()
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

Esiste anche una sottoclasse dict che collectionschiama defaultdictpraticamente allo stesso modo ma chiama una funzione senza argomenti per elementi non esistenti:

>>> from collections import defaultdict
>>> m = defaultdict(list)
>>> m["foo"].append(1)
>>> m["foo"].append(2)
>>> dict(m)
{'foo': [1, 2]}

Consiglio di convertire tali dicts in dicts regolari prima di passarli a funzioni che non prevedono tali sottoclassi. Un sacco di codice utilizza d[a_key]e rileva KeyErrors per verificare se esiste un elemento che aggiungerebbe un nuovo elemento al dict.


10
Preferisco usare setdefault. m = {}; m.setdefault ('foo', 1)
grayger

22
@grayger voleva dire questo m={}; m.setdefault('foo', []).append(1).
Cristian Ciupitu,

1
Ci sono tuttavia casi in cui passare il defaultdict è molto utile. La funzione può ad esempio scorrere il valore e funziona per chiavi indefinite senza codice aggiuntivo, poiché l'impostazione predefinita è un elenco vuoto.
Marian,

3
defaultdict è migliore in alcune circostanze rispetto a setdefault, poiché non crea l'oggetto predefinito a meno che non manchi la chiave. setdefault lo crea sia che manchi o meno. Se il tuo oggetto predefinito è costoso da creare, questo può essere un successo in termini di prestazioni: ho ottenuto una velocità decente da un programma semplicemente cambiando tutte le chiamate predefinite.
Whatang,

2
defaultdictè anche più potente del setdefaultmetodo in altri casi. Ad esempio, per un contro- dd = collections.defaultdict(int) ... dd[k] += 1vs d.setdefault(k, 0) += 1.
Mike Graham,

247

Scambio di valori sul posto

>>> a = 10
>>> b = 5
>>> a, b
(10, 5)

>>> a, b = b, a
>>> a, b
(5, 10)

Il lato destro del compito è un'espressione che crea una nuova tupla. Il lato sinistro del compito disimballa immediatamente quella tupla (senza riferimenti) ai nomi ae b.

Dopo l'assegnazione, la nuova tupla non è referenziata e contrassegnata per la garbage collection e i valori associati ae bscambiati.

Come notato nella sezione tutorial di Python sulle strutture di dati ,

Si noti che l'assegnazione multipla è in realtà solo una combinazione di imballaggio tupla e disimballaggio sequenza.


1
Questo utilizza più memoria reale rispetto al modo tradizionale? Immagino di si, visto che stai creando una tupla, invece di una sola variabile di scambio
Nathan,

75
Non usa più memoria. Usa meno .. L'ho appena scritto in entrambi i modi e ho decompilato il bytecode .. il compilatore ottimizza, come speri. Questo risultato mostra che sta impostando le variabili, quindi ROT_TWOing. ROT_TWO significa "scambia i due più grandi stack" ... Abbastanza elegante, in realtà.
royal

5
Inavvertitamente fai notare anche un'altra bella caratteristica di Python, che è che puoi implicitamente creare una tupla di elementi semplicemente separandoli con una virgola.
asmeurer,

3
Dana the Sane: l'assegnazione in Python è un'affermazione, non un'espressione, quindi quell'espressione non sarebbe valida se = avesse priorità più alta (cioè fosse interpretata come a, (b = b), a).
hbn

5
Questa è la funzione meno nascosta che ho letto qui. Bello, ma esplicitamente descritto in ogni tutorial di Python.
Thiago Chaves,

235

Espressioni regolari leggibili

In Python puoi dividere un'espressione regolare su più righe, nominare le tue corrispondenze e inserire commenti.

Sintassi dettagliata di esempio (da Dive in Python ):

>>> pattern = """
... ^                   # beginning of string
... M{0,4}              # thousands - 0 to 4 M's
... (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                     #            or 500-800 (D, followed by 0 to 3 C's)
... (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                     #        or 50-80 (L, followed by 0 to 3 X's)
... (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                     #        or 5-8 (V, followed by 0 to 3 I's)
... $                   # end of string
... """
>>> re.search(pattern, 'M', re.VERBOSE)

Esempi di corrispondenze di denominazione (dal Regular Expression HOWTO )

>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'

Puoi anche scrivere verbalmente una regex senza usare re.VERBOSEgrazie alla concatenazione letterale di stringhe.

>>> pattern = (
...     "^"                 # beginning of string
...     "M{0,4}"            # thousands - 0 to 4 M's
...     "(CM|CD|D?C{0,3})"  # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
...                         #            or 500-800 (D, followed by 0 to 3 C's)
...     "(XC|XL|L?X{0,3})"  # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
...                         #        or 50-80 (L, followed by 0 to 3 X's)
...     "(IX|IV|V?I{0,3})"  # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
...                         #        or 5-8 (V, followed by 0 to 3 I's)
...     "$"                 # end of string
... )
>>> print pattern
"^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$"

7
Non so se considererei davvero che una funzionalità Python, la maggior parte dei motori RE ha un'opzione dettagliata.
Jeremy Banks,

18
Sì, ma poiché non puoi farlo in grep o nella maggior parte degli editor, molte persone non sanno che è lì. Il fatto che altre lingue abbiano una funzione equivalente non lo rende una funzionalità utile e poco nota di Python
Mark Baker,

7
In un grande progetto con molte espressioni regolari ottimizzate (leggi: ottimizzato per la macchina ma non per gli esseri umani), ho morso il proiettile e le ho convertite tutte in sintassi dettagliata. Ora, presentare nuovi sviluppatori ai progetti è molto più semplice. Da ora in poi applichiamo RE dettagliate su ogni progetto.
Berk D. Demir,

Preferirei solo dire: centinaia = "(CM | CD | D? C {0,3})" # 900 (CM), 400 (CD), ecc. La lingua ha già un modo per dare nomi alle cose, un un modo per aggiungere commenti e un modo per combinare stringhe. Perché usare la sintassi speciale della libreria qui per cose che la lingua già fa perfettamente bene? Sembra andare direttamente contro l'Epigramma di Perlis 9.
Ken,

3
@Ken: un regex potrebbe non essere sempre direttamente nel sorgente, potrebbe essere letto dalle impostazioni o da un file di configurazione. Consentire commenti o solo spazi bianchi aggiuntivi (per leggibilità) può essere di grande aiuto.

222

Argomento della funzione decompressione

È possibile decomprimere un elenco o un dizionario come argomenti di funzione utilizzando *e **.

Per esempio:

def draw_point(x, y):
    # do some magic

point_foo = (3, 4)
point_bar = {'y': 3, 'x': 2}

draw_point(*point_foo)
draw_point(**point_bar)

Scorciatoia molto utile poiché elenchi, tuple e dadi sono ampiamente usati come contenitori.


27
* è anche noto come operatore splat
Gabriel,

3
Mi piace questa funzione, ma il pilastro non purtroppo.
Stephen Paulger,

5
Il consiglio di Pylint non è una legge. L'altro modo, apply (callable, arg_seq, arg_map), è obsoleto dal 2.3.
Yann Vernier,

1
Il consiglio di Pylint potrebbe non essere legge, ma è dannatamente un buon consiglio. Il debug del codice che si dedica eccessivamente a cose come questa è un vero inferno. Come osserva il poster originale, questa è una scorciatoia utile .
Andrew,

2
Ho visto questo essere usato nel codice una volta e mi chiedevo cosa facesse. Sfortunatamente è difficile cercare su Google "Python **"
Fraser Graham il

205

ROT13 è una codifica valida per il codice sorgente, quando si utilizza la dichiarazione di codifica corretta nella parte superiore del file di codice:

#!/usr/bin/env python
# -*- coding: rot13 -*-

cevag "Uryyb fgnpxbiresybj!".rapbqr("rot13")

10
Grande! Nota come le stringhe di byte vengono prese letteralmente, ma le stringhe unicode vengono decodificate: provacevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
sfortunatamente viene rimosso da py3k
mykhal

9
Questo è buono per bypassare l'antivirus.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
Non ha nulla a che fare con la codifica, è solo Python scritto in gallese. :-P
Olivier Verdier,

33
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn!
Manuel Ferreria,

183

Creazione di nuovi tipi in modo completamente dinamico

>>> NewType = type("NewType", (object,), {"x": "hello"})
>>> n = NewType()
>>> n.x
"hello"

che è esattamente lo stesso di

>>> class NewType(object):
>>>     x = "hello"
>>> n = NewType()
>>> n.x
"hello"

Probabilmente non è la cosa più utile, ma bello da sapere.

Modifica : il nome fisso del nuovo tipo deve essere NewTypeidentico a quello classdell'istruzione.

Modifica : modificato il titolo per descrivere più accuratamente la funzione.


8
Ciò ha molte potenzialità di utilità, ad es. JIT ORMs
Mark Cidade,

8
Lo uso per generare classi HTML-Form basate su un input dinamico. Molto bella!
pi.

15
Nota: tutte le classi vengono create in fase di esecuzione. Quindi puoi usare l'istruzione 'class' all'interno di un condizionale o all'interno di una funzione (molto utile per creare famiglie di classi o classi che fungono da chiusure). Il miglioramento apportato da "tipo" è la capacità di definire ordinatamente un insieme di attributi (o basi) generati dinamicamente.
spookylukey,

1
Puoi anche creare tipi anonimi con una stringa vuota come: type ('', (object,), {'x': 'blah'})
bluehavana

3
Potrebbe essere molto utile per iniezioni di codice.
Avihu Turzion,

179

Gestori di contesto e " with" Dichiarazione

Introdotto in PEP 343 , un gestore di contesto è un oggetto che funge da contesto di runtime per una suite di istruzioni.

Poiché la funzione utilizza nuove parole chiave, viene introdotta gradualmente: è disponibile in Python 2.5 tramite la __future__direttiva. Python 2.6 e versioni successive (incluso Python 3) lo rendono disponibile per impostazione predefinita.

Ho usato molto la frase "with" perché penso che sia un costrutto molto utile, ecco una breve demo:

from __future__ import with_statement

with open('foo.txt', 'w') as f:
    f.write('hello!')

Quello che sta succedendo qui dietro le quinte è che l' istruzione "with" chiama lo speciale __enter__e i __exit__metodi sull'oggetto file. Anche i dettagli dell'eccezione vengono passati a__exit__ se è stata sollevata un'eccezione dal corpo dell'istruzione with, consentendo in tal modo la gestione delle eccezioni.

Ciò che questo fa per te in questo caso particolare è che garantisce che il file sia chiuso quando l'esecuzione non rientra nell'ambito della withsuite, indipendentemente dal fatto che si verifichi normalmente o che sia stata generata un'eccezione. È fondamentalmente un modo per sottrarre il codice comune di gestione delle eccezioni.

Altri casi d'uso comuni per questo includono il blocco con thread e transazioni di database.


3
Non approverei una revisione del codice che importasse qualcosa dal futuro . Le funzionalità sono più carine che utili e di solito finiscono per confondere i nuovi arrivati ​​di Python.
un secchione pagato

6
Sì, funzionalità "carine" come ambiti e generatori nidificati sono meglio lasciate a coloro che sanno cosa stanno facendo. E chiunque voglia essere compatibile con le versioni future di Python. Per ambiti e generatori nidificati, "versioni future" di Python significa rispettivamente 2.2 e 2.5. Per l'istruzione with, "versioni future" di Python significa 2.6.
Chris B.

10
Questo può essere ovvio, ma con Python v2.6 +, non è più necessario importare dal futuro . con è ora una parola chiave di prima classe.
fitzgeraldsteele,

25
In 2.7 puoi averne diversi withs:) with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson,

5
@Austin non sono riuscito a far funzionare quella sintassi su 2.7. questo tuttavia ha funzionato: with open('filea') as filea, open('fileb') as fileb: ...
mercoledì

168

I dizionari hanno un metodo get ()

I dizionari hanno un metodo 'get ()'. Se fai d ['chiave'] e la chiave non c'è, otterrai un'eccezione. Se si fa d.get ('chiave'), si ottiene indietro Nessuno se 'chiave' non è presente. Puoi aggiungere un secondo argomento per riavere quell'elemento invece di None, ad esempio: d.get ('key', 0).

È ottimo per cose come aggiungere numeri:

sum[value] = sum.get(value, 0) + 1


39
inoltre, controlla il metodo setdefault.
Daren Thomas,

27
inoltre, verifica la collezione di classi.defaultdict.
jfs,

8
Se stai usando Python 2.7 o versioni successive, o 3.1 o versioni successive, controlla la classe Counter nel modulo collezioni. docs.python.org/library/collections.html#collections.Counter
Elias Zamaria,

Oh amico, da sempre get(key, None). Non avevo idea che Nonefosse fornito di default.
Jordan Reiter,

152

descrittori

Sono la magia dietro un sacco di funzioni Python di base.

Quando si utilizza l'accesso punteggiato per cercare un membro (ad esempio, xy), Python cerca innanzitutto il membro nel dizionario dell'istanza. Se non viene trovato, lo cerca nel dizionario delle classi. Se lo trova nel dizionario delle classi e l'oggetto implementa il protocollo descrittore, invece di restituirlo, Python lo esegue. Un descrittore è un qualsiasi classe che implementa l' __get__, __set__o__delete__ metodi.

Ecco come implementare la tua versione (sola lettura) della proprietà usando i descrittori:

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

e lo useresti proprio come la proprietà built-in ():

class MyClass(object):
    @Property
    def foo(self):
        return "Foo!"

I descrittori sono usati in Python per implementare proprietà, metodi associati, metodi statici, metodi di classe e slot, tra le altre cose. Comprenderli rende facile capire perché molte cose che in precedenza sembravano "stranezze" di Python sono come sono.

Raymond Hettinger ha un eccellente tutorial che fa un lavoro molto migliore nel descriverli di me.


Questo è un duplicato di decoratori, vero? ( Stackoverflow.com/questions/101268/... )
gecco

2
no, decoratori e descrittori sono cose totalmente diverse, anche se nel codice di esempio sto creando un descrittore decoratore. :)
Nick Johnson,

1
L'altro modo per farlo è con un lambda:foo = property(lambda self: self.__foo)
Pete Peterson

1
@PetePeterson Sì, ma di per propertysé è implementato con descrittori, che era il punto del mio post.
Nick Johnson,

142

Cessione condizionale

x = 3 if (y == 1) else 2

Fa esattamente quello che sembra: "assegna 3 a x se y è 1, altrimenti assegna 2 a x". Nota che i genitori non sono necessari, ma mi piacciono per leggibilità. Puoi anche incatenarlo se hai qualcosa di più complicato:

x = 3 if (y == 1) else 2 if (y == -1) else 1

Anche se a un certo punto, va un po 'troppo lontano.

Nota che puoi usare if ... else in qualsiasi espressione. Per esempio:

(func1 if y == 1 else func2)(arg1, arg2) 

Qui sarà chiamato func1 se y è 1 e func2, altrimenti. In entrambi i casi la funzione corrispondente verrà chiamata con argomenti arg1 e arg2.

Analogamente, vale anche quanto segue:

x = (class1 if y == 1 else class2)(arg1, arg2)

dove class1 e class2 sono due classi.


29
L'assegnazione non è la parte speciale. Potresti fare altrettanto facilmente: return 3 if (y == 1) else 2.
Brian

25
Quella strada alternativa è la prima volta che vedo Python offuscato.
Craig McQueen,

3
Kylebrooks: In tal caso, gli operatori booleani non sono in corto circuito. Valuterà solo 2 se bool (3) == False.
RoadieRich,

15
questo codice all'indietro mi confonde. qualcosa di simile x = ((y == 1) ? 3 : 2)ha più senso per me
mpen

13
Sento esattamente l'opposto di @Mark, gli operatori ternari in stile C mi hanno sempre confuso, è il lato destro o il mezzo che viene valutato in una falsa condizione? Preferisco di gran lunga la sintassi ternaria di Python.
Jeffrey Harris,

141

Doctest : documentazione e unit test allo stesso tempo.

Esempio estratto dalla documentazione di Python:

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    If the result is small enough to fit in an int, return an int.
    Else return a long.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result

def _test():
    import doctest
    doctest.testmod()    

if __name__ == "__main__":
    _test()

6
I doctest sono certamente fantastici, ma non mi piace molto tutte le cruft che devi digitare per testare che qualcosa dovrebbe sollevare un'eccezione
TM.

60
I doctest sono sopravvalutati e inquinano la documentazione. Con quale frequenza testate una funzione autonoma senza setUp ()?
un secchione pagato

2
chi dice che non è possibile eseguire l'installazione in un doctest? scrivi una funzione che genera il contesto e ritorna locals()quindi nel tuo doctest do locals().update(setUp())= D
Jiaaro

12
Se una funzione autonoma richiede un setUp, è molto probabile che debba essere disaccoppiato da alcune cose non correlate o inserito in una classe. Lo spazio dei nomi doctest di classe può quindi essere riutilizzato nei doctest del metodo di classe, quindi è un po 'come setUp, solo DRY e leggibile.
Andy Mikhaylenko,

4
"Ogni quanto test una funzione autonoma" - un sacco. Trovo che i doctest spesso emergano naturalmente dal processo di progettazione quando decido di facciate.
Gregg Lind,

138

Formattazione denominata

% -formatting accetta un dizionario (applica anche la convalida% i /% s ecc.).

>>> print "The %(foo)s is %(bar)i." % {'foo': 'answer', 'bar':42}
The answer is 42.

>>> foo, bar = 'question', 123

>>> print "The %(foo)s is %(bar)i." % locals()
The question is 123.

E poiché locals () è anche un dizionario, puoi semplicemente passarlo come dict e avere% -substitions dalle tue variabili locali. Penso che questo sia disapprovato, ma semplifica le cose ..

Formattazione del nuovo stile

>>> print("The {foo} is {bar}".format(foo='answer', bar=42))

60
Verrà gradualmente eliminato e infine sostituito con il metodo format () di stringa.
Constantin,

3
La formattazione dei nomi è molto utile per i traduttori in quanto tendono a vedere solo la stringa di formato senza i nomi delle variabili per il contesto
pixelbeat

2
Sembra funzionare in Python 3.0.1 (necessario per aggiungere parentesi attorno alla chiamata di stampa).
Pasi Savolainen,

9
un hash , eh? Vedo da dove vieni.
shylent,

11
La formattazione% s non verrà eliminata gradualmente. str.format () è sicuramente più pythonic, tuttavia in realtà è 10x più lento per la semplice sostituzione di stringhe. La mia convinzione è che la formattazione di% s sia ancora la migliore pratica.
Kenneth Reitz,

132

Per aggiungere più moduli Python (specialmente quelli di terze parti), la maggior parte delle persone sembra usare le variabili di ambiente PYTHONPATH o aggiungono collegamenti simbolici o directory nelle loro directory dei pacchetti del sito. Un altro modo è utilizzare i file * .pth. Ecco la spiegazione ufficiale del documento Python:

"Il modo più conveniente [per modificare il percorso di ricerca di Python] è aggiungere un file di configurazione del percorso a una directory che è già sul percorso di Python, di solito alla directory ... / site-pacchetti /. I file di configurazione del percorso hanno un'estensione di .pth e ogni riga deve contenere un singolo percorso che verrà aggiunto a sys.path (poiché i nuovi percorsi vengono aggiunti a sys.path, i moduli nelle directory aggiunte non sovrascriveranno i moduli standard. Ciò significa che non è possibile utilizzare questo meccanismo per l'installazione di versioni fisse di moduli standard.) "


1
Non ho mai stabilito la connessione tra quel file .pth nella directory dei pacchetti del sito da setuptools e questa idea. eccezionale.
dave paola,

122

Clausola di eccezione altro :

try:
  put_4000000000_volts_through_it(parrot)
except Voom:
  print "'E's pining!"
else:
  print "This parrot is no more!"
finally:
  end_sketch()

L'uso della clausola else è meglio dell'aggiunta di codice aggiuntivo alla clausola try perché evita di catturare accidentalmente un'eccezione che non è stata sollevata dal codice protetto dall'istruzione try ... tranne.

Vedi http://docs.python.org/tut/node10.html


8
+1 questo è fantastico. Se il blocco try viene eseguito senza immettere blocchi di eccezione, viene inserito il blocco else. E poi, naturalmente, il blocco finally viene eseguito
inspector

Finalmente capisco perché l '"altro" è lì! Grazie.
taynaron,

Avrebbe più senso usare continue, ma immagino che sia già stato utilizzato;)
Paweł Prażak

Nota che nelle versioni precedenti di Python2 non puoi avere entrambi: e infine: clausole per lo stesso tentativo: blocco
Kevin Horn,

1
@ Paweł Prażak, come ha detto Kevin Horn, questa sintassi è stata introdotta dopo il rilascio iniziale di Python e l'aggiunta di nuove parole chiave riservate alla lingua esistente è sempre problematica. Ecco perché una parola chiave esistente viene solitamente riutilizzata (vedi "auto" nel recente standard C ++).
Costantina,

114

Aumentare nuovamente le eccezioni :

# Python 2 syntax
try:
    some_operation()
except SomeError, e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

# Python 3 syntax
try:
    some_operation()
except SomeError as e:
    if is_fatal(e):
        raise
    handle_nonfatal(e)

L'istruzione 'raise' senza argomenti all'interno di un gestore degli errori dice a Python di rilanciare l'eccezione con il traceback originale intatto , permettendoti di dire "oh, scusa, scusa, non volevo prenderlo, scusa, scusa. "

Se desideri stampare, archiviare o giocherellare con il traceback originale, puoi ottenerlo con sys.exc_info () e stamparlo come farebbe Python con il modulo 'traceback'.


Ci dispiace ma questa è una caratteristica ben nota e comune in quasi tutte le lingue.
Lucas S.,

6
Nota il testo in corsivo. Alcune persone raise einvece lo faranno , il che non preserva il traceback originale.
habnabit,

12
Forse più magico, exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]equivale a questo, ma è possibile modificare quei valori in giro (ad esempio, cambiare il tipo di eccezione o il messaggio)
ianb

3
@Lucas S. Beh, non lo sapevo e sono contento che sia scritto qui.
e-satis

potrei mostrare qui la mia giovinezza, ma ho sempre usato la sintassi di Python 3 in Python 2.7 senza problemi
wim

106

Messaggi principali :)

import this
# btw look at this module's source :)

Decifrato :

Lo Zen di Python, di Tim Peters

Bello è meglio che brutto.
Esplicito è meglio che implicito.
Semplice è meglio di complesso.
Complesso è meglio che complicato.
Flat è meglio di nidificato.
Sparse è meglio che denso.
La leggibilità conta.
I casi speciali non sono abbastanza speciali da infrangere le regole.
Sebbene la praticità superi la purezza.
Gli errori non dovrebbero mai passare silenziosamente.
A meno che non sia esplicitamente messo a tacere.
Di fronte all'ambiguità, rifiuta la tentazione di indovinare. Dovrebbe esserci uno - e preferibilmente solo un - modo obsoleto di farlo.
Anche se in quel modo all'inizio potrebbe non essere ovvio a meno che tu non sia olandese.
Adesso è meglio che mai.
Anche se spesso non è mai meglio diproprio ora
Se l'implementazione è difficile da spiegare, è una cattiva idea.
Se l'implementazione è facile da spiegare, potrebbe essere una buona idea.
Gli spazi dei nomi sono un'ottima idea per suonare il clacson: facciamo di più!


1
Qualche idea sul perché la fonte sia stata cifrata in quel modo? Era solo per divertimento o c'era qualche altra ragione?
MiniQuark,

42
il modo in cui la fonte è scritta va contro lo zen!
hasen


2
Ho aggiornato il mio /usr/lib/python2.6/this.py sostituendo il vecchio codice con questo print s.translate("".join(chr(64<i<91 and 65+(i-52)%26 or 96<i<123 and 97+(i-84)%26 or i) for i in range(256)))e ora sembra molto meglio !! MrGreen
fortran il

2
@MiniQuark: lezione di storia rapida: wefearchange.org/2010/06/import-this-and-zen-of-python.html

105

Completamento della scheda Interprete interattivo

try:
    import readline
except ImportError:
    print "Unable to load readline module."
else:
    import rlcompleter
    readline.parse_and_bind("tab: complete")


>>> class myclass:
...    def function(self):
...       print "my function"
... 
>>> class_instance = myclass()
>>> class_instance.<TAB>
class_instance.__class__   class_instance.__module__
class_instance.__doc__     class_instance.function
>>> class_instance.f<TAB>unction()

Dovrai anche impostare una variabile d'ambiente PYTHONSTARTUP.


2
Questa è una funzione molto utile. Tanto che ho un semplice script per abilitarlo (oltre a un paio di altri miglioramenti dell'introspezione): pixelbeat.org/scripts/inpy
pixelbeat

43
IPython ti offre questo oltre a tonnellate di altre cose ordinate
Akaihola il

Ciò sarebbe stato più utile al prompt di pdb rispetto al normale prompt di python (poiché IPython serve comunque a tale scopo). Tuttavia, questo non sembra funzionare al prompt di pdb, probabilmente perché pdb si lega da solo per tab (che è meno utile). Ho provato a chiamare parse_and_bind () al prompt di pdb, ma non ha ancora funzionato. L'alternativa di ottenere il prompt pdb con IPython è più lavoro, quindi tendo a non usarlo.
haridsv,

2
@haridsv - easy_install ipdb- allora puoi usareimport ipdb; ipdb.set_trace()
Doug Harris

1
Su osx [e immagino altri sistemi che usano libedit] devi farereadline.parse_and_bind ("bind ^I rl_complete")
Foo Bah,

91

Comprensioni dell'elenco nidificato ed espressioni del generatore:

[(i,j) for i in range(3) for j in range(i) ]    
((i,j) for i in range(4) for j in range(i) )

Questi possono sostituire enormi blocchi di codice a ciclo nidificato.


"for j in range (i)" - è un errore di battitura? Normalmente vorresti intervalli fissi per iej. Se accedi a un array 2d, ti perderei metà degli elementi.
Peter Gibson,

In questo esempio non accedo ad alcuna matrice. L'unico scopo di questo codice è mostrare che le espressioni dagli intervalli interni possono accedere a quelle da quelli esterni. Il sottoprodotto è un elenco di coppie (x, y) tali che 4> x> y> 0.
Rafał Dowgird,

2
una sorta di doppia integrazione nel calcolo o doppia somma.
Yoo,

22
Il punto chiave da ricordare qui (che mi ci è voluto molto tempo per capire) è che l'ordine delle fordichiarazioni deve essere scritto nell'ordine in cui ti aspetteresti che siano scritte in un ciclo standard, dall'esterno verso l'interno.
Sykora,

2
Per aggiungere a commento di Sykora: immaginate si sta iniziando con una pila di fors e ifs con yield xal suo interno. Per convertirlo in un'espressione del generatore, spostati xprima, elimina tutti i due punti (e il yield) e racchiudi il tutto tra parentesi. Per rendere invece comprensibile un elenco, sostituire le parentesi esterne con parentesi quadre.
Ken Arnold,

91

Sovraccarico dell'operatore per il setbuilt-in:

>>> a = set([1,2,3,4])
>>> b = set([3,4,5,6])
>>> a | b # Union
{1, 2, 3, 4, 5, 6}
>>> a & b # Intersection
{3, 4}
>>> a < b # Subset
False
>>> a - b # Difference
{1, 2}
>>> a ^ b # Symmetric Difference
{1, 2, 5, 6}

Maggiori dettagli dal riferimento della libreria standard: Imposta tipi


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.