Características ocultas de Python [cerrado]


1419

¿Cuáles son las características menos conocidas pero útiles del lenguaje de programación Python?

  • Intenta limitar las respuestas al núcleo de Python.
  • Una característica por respuesta.
  • Dé un ejemplo y una breve descripción de la función, no solo un enlace a la documentación.
  • Etiquete la característica usando un título como la primera línea.

Enlaces rápidos a respuestas:

Respuestas:


740

Operadores de comparación de encadenamiento:

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

En caso de que piense que lo está haciendo 1 < x, que aparece como True, y luego compara True < 10, que también es True, entonces no, eso no es realmente lo que sucede (vea el último ejemplo). Realmente se traduce en 1 < x and x < 10, y x < 10 and 10 < x * 10 and x*10 < 100, con menos tipeo y cada uno el término solo se evalúa una vez.


121
Eso es muy útil Debe ser estándar para todos los idiomas. Lamentablemente, no lo es.
stalepretzel

8
debe agregar algunos ejemplos que también devuelven falso. como >>> 10 <x <20 Falso
ShoeLace

19
Esto también se aplica a otros operadores de comparación, razón por la cual las personas a veces se sorprenden de por qué un código como (5 en [5] es verdadero) es falso (pero para empezar, no es lógico probar explícitamente contra booleanos como ese).
Miles

19
Bueno, pero ten cuidado con la misma precedencia, como 'in' y '='. 'A en B == C en D' significa '(A en B) y (B == C) y (C en D)' que pueden ser inesperados.
Charles Merriam

15
Azafe: las comparaciones de Lisp naturalmente funcionan de esta manera. No es un caso especial porque no hay otra forma (razonable) de interpretar (< 1 x 10). Incluso puede aplicarlos a argumentos individuales, como (= 10): cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/…
Ken

512

Obtenga el árbol de análisis de expresiones regulares de python para depurar su expresión regular.

Las expresiones regulares son una gran característica de python, pero depurarlas puede ser una molestia, y es muy fácil equivocarse con una expresión regular.

Afortunadamente, python puede imprimir el árbol de análisis de expresiones regulares, pasando el indicador oculto, indocumentado, experimental re.DEBUG(en realidad, 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 vez que comprenda la sintaxis, puede detectar sus errores. No podemos ver que se me olvidó para escapar de la []en [/font].

Por supuesto, puede combinarlo con las banderas que desee, como expresiones regulares comentadas:

>>> 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
Excepto que analizar HTML usando expresiones regulares es lento y doloroso. Incluso el módulo analizador 'html' incorporado no usa expresiones regulares para hacer el trabajo. Y si el módulo html no le agrada, hay muchos módulos de analizador XML / HTML que hacen el trabajo sin tener que reinventar la rueda.
BatchyX

Un enlace a la documentación sobre la sintaxis de salida sería genial.
Personman

1
Esto debería ser una parte oficial de Python, no experimental ... RegEx siempre es complicado y poder rastrear lo que está sucediendo es realmente útil.
Cahit

460

enumerar

Envuelva un iterable con enumerate y generará el elemento junto con su índice.

Por ejemplo:


>>> 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
>>>

Referencias


56
Me sorprende que esto no esté cubierto de forma rutinaria en los tutoriales que hablan sobre las listas de Python.
Draemon

45
Y todo este tiempo estaba codificando de esta manera: para i en rango (len (a)): ... y luego usando un [i] para obtener el elemento actual.
Fernando Martin

44
@Berry Tsakala: Que yo sepa, no ha quedado en desuso.
JAB

23
Mierda esto es impresionante. para i en xrange (len (a)): siempre ha sido mi idioma de Python menos favorito.
Personman

15
enumerar puede comenzar desde un índice arbitrario, no necesario 0. Ejemplo: 'para i, elemento en enumerar ( lista , inicio = 1): imprimir i, elemento' comenzará la enumeración desde 1, no 0.
dmitry_romanov

419

Crear objetos generadores

Si tú escribes

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

puedes sacar el generador y asignarlo a x. Ahora significa que puedes hacer

for n in x:

La ventaja de esto es que no necesita almacenamiento intermedio, que necesitaría si lo necesitara

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

En algunos casos, esto puede conducir a una aceleración significativa.

Puede agregar muchas declaraciones if al final del generador, básicamente replicando los bucles anidados:

>>> 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)

También podría usar una comprensión de lista anidada para eso, ¿sí?
shapr

54
De particular interés es el ahorro de gastos generales de memoria. Los valores se calculan a pedido, por lo que nunca tendrá el resultado completo de la comprensión de la lista en la memoria. Esto es particularmente deseable si luego repite solo una parte de la comprensión de la lista.
saffsd

19
Esto no es particularmente "oculto", pero también vale la pena señalar el hecho de que no puede rebobinar un objeto generador, mientras que puede reiterar una lista varias veces.
susmite el

13
La característica "sin rebobinar" de los generadores puede causar cierta confusión. Específicamente, si imprime el contenido de un generador para la depuración, luego lo usa para procesar los datos, no funciona. Los datos son producidos, consumidos por print (), luego no están disponibles para el procesamiento normal. Esto no se aplica a las comprensiones de listas, ya que están completamente almacenadas en la memoria.
johntellsall

44
Respuesta similar (dup?): Stackoverflow.com/questions/101268/hidden-features-of-python/… Tenga en cuenta, sin embargo, que la respuesta que vinculé aquí menciona una presentación REALMENTE BUENA sobre el poder de los generadores. Realmente deberías echarle un vistazo.
Denilson Sá Maia

353

iter () puede tomar un argumento invocable

Por ejemplo:

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

La iter(callable, until_value)función llama repetidamente callabley produce su resultado hasta que until_valuese devuelve.


Como novato en python, ¿puede explicar por qué la lambdapalabra clave es necesaria aquí?
SiegeX

@SiegeX sin lambda, f.read (1) sería evaluado (devolviendo una cadena) antes de pasar a la función iter. En cambio, la lambda crea una función anónima y se la pasa a iter.
jmilloy

339

Tenga cuidado con los argumentos predeterminados mutables

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

En su lugar, debe usar un valor centinela que denote "no dado" y reemplazarlo con el mutable que desea por defecto:

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

39
Esa es definitivamente una de las características ocultas más desagradables. Me lo he encontrado de vez en cuando.
Torsten Marek

77
Esto me resultó mucho más fácil de entender cuando aprendí que los argumentos predeterminados viven en una tupla que es un atributo de la función, por ejemplo foo.func_defaults. Lo cual, siendo una tupla, es inmutable.
Robert Rossney el

2
@grayger: a medida que se ejecuta la declaración def, el intérprete evalúa sus argumentos. Esto crea (o vuelve a vincular) un nombre a un objeto de código (el conjunto de la función). Sin embargo, los argumentos predeterminados se instancian como objetos en el momento de la definición. Esto es cierto en cualquier momento del objeto predeterminado, pero solo significativo (exponiendo la semántica visible) cuando el objeto es mutable. No hay forma de volver a vincular ese nombre de argumento predeterminado en el cierre de la función, aunque obviamente se puede anular para cualquier llamada o se puede redefinir toda la función).
Jim Dennis

3
@Robert, por supuesto, la tupla de argumentos puede ser inmutable, pero los objetos a los que apunta no son necesariamente inmutables.
poolie

16
Un truco rápido para acortar un poco su inicialización: x = x o []. Puede usar eso en lugar de la instrucción if de 2 líneas.
Dave Mankoff

317

Envío de valores a las funciones del generador . Por ejemplo, tener esta función:

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

Usted puede:

>>> 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

Convenido. Tratemos esto como un desagradable ejemplo de una característica oculta de Python :)
Rafał Dowgird

89
En otros idiomas, creo que este dispositivo mágico se llama "variable".
finnw

55
las corutinas deben ser corutinas y el generador también deben ser ellos mismos, sin mezclar. Enlace y charla megagrandes
u0b34a0f6ae

31
@finnw: el ejemplo implementa algo similar a una variable. Sin embargo, la característica podría usarse de muchas otras maneras ... a diferencia de una variable. También debería ser obvio que se puede implementar una semántica similar usando objetos (una clase que implementa el método de llamada de Python , en particular).
Jim Dennis

44
Este es un ejemplo demasiado trivial para las personas que nunca han visto (y probablemente no entenderán) co-rutinas. El ejemplo que implementa el promedio móvil sin riesgo de desbordamiento de variable de suma es bueno.
Prashant Kumar

313

Si no le gusta usar espacios en blanco para denotar ámbitos, puede usar el estilo C {} emitiendo:

from __future__ import braces

122
Eso es malo :)
Jason Baker,

37
>>> de __future__ import braces Archivo "<stdin>", línea 1 SyntaxError: no es una posibilidad: P
Benjamin W. Smith

40
eso es blasfemia!
Berk D. Demir

335
Creo que podemos tener un error sintáctico aquí, ¿no debería ser "de __past__ import braces"?
Bill K

47
from __cruft__ import braces
Phillip B Oldham

305

El argumento paso en operadores de corte. Por ejemplo:

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

El caso especial x[::-1]es un lenguaje útil para 'x invertido'.

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

31
mucho más claro, en mi opinión, es la función invertida (). >>> lista (invertida (rango (4))) [3, 2, 1, 0]
Christian Oudard el

3
entonces, ¿cómo escribir "esta cadena ia" [:: - 1] de una mejor manera? revertido no parece ayudar
Berry Tsakala

24
El problema con reverse () es que devuelve un iterador, por lo que si desea preservar el tipo de secuencia invertida (tupla, cadena, lista, unicode, tipos de usuario ...), necesita un paso adicional para convertirlo nuevamente .
Rafał Dowgird

66
def reverse_string (string): devuelve string [:: - 1]
pi.

44
@pi Creo que si uno sabe lo suficiente como para definir reverse_string como usted tiene, puede dejar el [:: - 1] en su código y sentirse cómodo con su significado y la sensación de que es apropiado.
physicsmichael

289

Decoradores

Los decoradores permiten ajustar una función o método en otra función que puede agregar funcionalidad, modificar argumentos o resultados, etc. Usted escribe decoradores una línea sobre la definición de la función, comenzando con un signo "at" (@).

El ejemplo muestra un print_argsdecorador que imprime los argumentos de la función decorada antes de llamarla:

>>> 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
Al definir decoradores, recomiendo decorar el decorador con @decorator. Crea un decorador que conserva una firma de funciones cuando se realiza una introspección en él. Más información aquí: phyast.pitt.edu/~micheles/python/documentation.html
sirwart

45
¿Cómo es esto una característica oculta?
Vetle

50
Bueno, no está presente en la mayoría de los tutoriales simples de Python, y me topé mucho tiempo después de que comencé a usar Python. Eso es lo que llamaría una función oculta, casi lo mismo que otras publicaciones principales aquí.
DzinX

16
vetler, las preguntas piden "características menos conocidas pero útiles del lenguaje de programación Python". ¿Cómo se miden las 'características menos conocidas pero útiles'? Quiero decir, ¿cómo se oculta alguna de estas respuestas?
Johnd

44
@vetler La mayoría de las cosas aquí apenas están "ocultas".
Humphrey Bogart

288

La sintaxis de for ... else (ver http://docs.python.org/ref/for.html )

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

El bloque "else" se ejecutará normalmente al final del ciclo for, a menos que se llame al break.

El código anterior se puede emular de la siguiente manera:

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

218
Creo que la sintaxis for / else es incómoda. "Se siente" como si la cláusula else debería ejecutarse si el cuerpo del bucle nunca se ejecuta.
codeape

14
ah ¡Nunca vi esa! Pero debo decir que es un nombre poco apropiado. ¿Quién esperaría que el bloque else se ejecute solo si break nunca lo hace? Estoy de acuerdo con codeape: parece que se ingresa otra cosa para los foos vacíos.
Daren Thomas el

52
parece que la palabra clave debería ser finalmente, no otra cosa
Jiaaro

21
Excepto que finalmente ya se usa de una manera en que esa suite siempre se ejecuta.

77
Definitivamente no debería ser 'otra cosa'. Tal vez 'entonces' o algo así, y luego 'otra cosa' para cuando el bucle nunca se ejecutó.
Tor Valamo

258

De 2.5 en adelante, los dictos tienen un método especial __missing__que se invoca para los elementos faltantes:

>>> 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]}

También hay una subclase dict en collectionsllamada defaultdictque hace más o menos lo mismo pero llama a una función sin argumentos para elementos no existentes:

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

Recomiendo convertir dichos dictos a dictos regulares antes de pasarlos a funciones que no esperan tales subclases. Una gran cantidad de código usa d[a_key]y captura KeyErrors para verificar si existe un elemento que agregaría un nuevo elemento al dict.


10
Prefiero usar setdefault. m = {}; m.setdefault ('foo', 1)
grayger

22
@grayger quiso decir esto m={}; m.setdefault('foo', []).append(1).
Cristian Ciupitu

1
Sin embargo, hay casos en los que pasar el defaultdict es muy útil. La función puede, por ejemplo, superar el valor y funciona para claves indefinidas sin código adicional, ya que el valor predeterminado es una lista vacía.
Marian

3
defaultdict es mejor en algunas circunstancias que setdefault, ya que no crea el objeto predeterminado a menos que falte la clave. setdefault lo crea si falta o no. Si crear su objeto predeterminado es costoso, esto puede ser un golpe de rendimiento: obtuve una aceleración decente de un programa simplemente cambiando todas las llamadas predeterminadas establecidas.
Whatang

2
defaultdictTambién es más potente que el setdefaultmétodo en otros casos. Por ejemplo, para un contra- dd = collections.defaultdict(int) ... dd[k] += 1vs d.setdefault(k, 0) += 1.
Mike Graham

247

Intercambio de valor en el lugar

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

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

El lado derecho de la tarea es una expresión que crea una nueva tupla. El lado izquierdo de la tarea desempaqueta inmediatamente esa tupla (sin referencia) a los nombresa y b.

Después de la asignación, la nueva tupla no está referenciada y marcada para la recolección de basura, y los valores vinculados a a y bse han intercambiado.

Como se señaló en el sección del tutorial de Python sobre estructuras de datos ,

Tenga en cuenta que la asignación múltiple es realmente solo una combinación de empaque de tuplas y desempaque de secuencia.


1
¿Utiliza esto más memoria real que la forma tradicional? Supongo que sí, ya que estás creando una tupla, en lugar de una sola variable de intercambio
Nathan

75
No usa más memoria. Utiliza menos ... Acabo de escribirlo en ambos sentidos y descompilé el código de bytes ... el compilador se optimiza, como es de esperar. Estos resultados mostraron que está configurando los vars y luego ROT_TWOing. ROT_TWO significa 'intercambiar los dos vars de pila más altos' ... bastante elegante, en realidad.
real

55
También, sin darse cuenta, señala otra buena característica de Python, que es que implícitamente puede hacer una tupla de elementos simplemente separándolos por comas.
asmeurer

3
Dana the Sane: la asignación en Python es una declaración, no una expresión, por lo que esa expresión sería inválida si = tuviera mayor prioridad (es decir, se interpretó como a, (b = b), a).
hbn

55
Esta es la característica menos oculta que he leído aquí. Agradable, pero se describe explícitamente en cada tutorial de Python.
Thiago Chaves

235

Expresiones regulares legibles

En Python puede dividir una expresión regular en varias líneas, nombrar sus coincidencias e insertar comentarios.

Ejemplo de sintaxis detallada (de Dive into 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)

Ejemplo de coincidencias de nomenclatura (del COMO de expresiones regulares )

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

También puedes escribir una expresión regular sin usar re.VERBOSEgracias a la concatenación literal de cadenas.

>>> 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})$"

77
No sé si realmente consideraría que es una característica de Python, la mayoría de los motores RE tienen una opción detallada.
Jeremy Banks

18
Sí, pero como no puedes hacerlo en grep o en la mayoría de los editores, mucha gente no sabe que está ahí. El hecho de que otros idiomas tengan una función equivalente no la convierte en una característica útil y poco conocida de Python
Mark Baker

77
En un proyecto grande con muchas expresiones regulares optimizadas (léase: optimizado para máquina pero no para seres humanos), mordí la viñeta y las convertí a sintaxis detallada. Ahora, presentar nuevos desarrolladores a los proyectos es mucho más fácil. De ahora en adelante, aplicamos RE detallados en cada proyecto.
Berk D. Demir

Prefiero simplemente decir: cientos = "(CM | CD | D? C {0,3})" # 900 (CM), 400 (CD), etc. El lenguaje ya tiene una forma de dar nombres a las cosas, un forma de agregar comentarios y una forma de combinar cadenas. ¿Por qué usar una sintaxis de biblioteca especial aquí para cosas que el lenguaje ya hace perfectamente bien? Parece que ir directamente contra Epigram Perlis' 9.
Ken

3
@Ken: una expresión regular puede no estar siempre directamente en la fuente, podría leerse desde la configuración o desde un archivo de configuración. Permitir comentarios o solo espacios en blanco adicionales (para facilitar la lectura) puede ser de gran ayuda.

222

Desembalaje de argumento de función

Puede descomprimir una lista o un diccionario como argumentos de función utilizando *y **.

Por ejemplo:

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)

Atajo muy útil ya que las listas, tuplas y dictados se usan ampliamente como contenedores.


27
* también es conocido como el operador splat
Gabriel

3
Me gusta esta característica, pero tristemente, pylint no.
Stephen Paulger

55
El consejo de Pylint no es una ley. La otra forma, apply (invocable, arg_seq, arg_map), está en desuso desde 2.3.
Yann Vernier

1
El consejo de Pylint puede no ser ley, pero es un buen consejo. La depuración de código que se excede en cosas como esta es un verdadero infierno. Como señala el póster original, este es un atajo útil .
Andrew

2
Vi que esto se usaba en código una vez y me preguntaba qué hacía. Desafortunadamente, es difícil buscar en Google "Python **"
Fraser Graham el

205

ROT13 es una codificación válida para el código fuente, cuando utiliza la declaración de codificación correcta en la parte superior del archivo de código:

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

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

10
¡Excelente! Observe cómo se toman literalmente cadenas de bytes, pero se decodifican las cadenas Unicode: trycevag h"Uryyb fgnpxbiresybj!"
u0b34a0f6ae

12
desafortunadamente se elimina de py3k
mykhal

99
Esto es bueno para evitar el antivirus.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

96
Eso no tiene nada que ver con la codificación, es solo Python escrito en galés. :-P
Olivier Verdier

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

183

Crear nuevos tipos de manera totalmente dinámica

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

que es exactamente lo mismo que

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

Probablemente no sea lo más útil, pero es bueno saberlo.

Editar : El nombre fijo del nuevo tipo debe ser NewTypeexactamente lo mismo que con la classdeclaración.

Editar : Ajustó el título para describir con mayor precisión la función.


8
Esto tiene un gran potencial de utilidad, por ejemplo, JIT ORMs
Mark Cidade

8
Lo uso para generar clases de formulario HTML basadas en una entrada dinámica. ¡Muy agradable!
pi.

15
Nota: todas las clases se crean en tiempo de ejecución. Por lo tanto, puede usar la declaración 'clase' dentro de una condicional o dentro de una función (muy útil para crear familias de clases o clases que actúan como cierres). La mejora que trae el "tipo" es la capacidad de definir claramente un conjunto de atributos (o bases) generados dinámicamente.
spookylukey

1
También puede crear tipos anónimos con una cadena en blanco como: type ('', (object,), {'x': 'blah'})
bluehavana

3
Podría ser muy útil para inyecciones de código.
Avihu Turzion

179

Los administradores de contexto y la " with" Declaración

Introducido en PEP 343 , un administrador de contexto es un objeto que actúa como contexto de tiempo de ejecución para un conjunto de declaraciones.

Dado que la función utiliza nuevas palabras clave, se introduce gradualmente: está disponible en Python 2.5 a través de __future__ directiva. Python 2.6 y superior (incluido Python 3) lo tiene disponible de forma predeterminada.

He usado mucho la declaración "con" porque creo que es una construcción muy útil, aquí hay una demostración rápida:

from __future__ import with_statement

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

Lo que sucede aquí detrás de escena es que la instrucción "con" llama a los métodos especiales __enter__y __exit__al objeto del archivo. Los detalles de excepción también se pasan a__exit__ si surgió alguna excepción del cuerpo de la declaración with, lo que permite el manejo de excepciones allí.

Lo que esto hace por usted en este caso particular es que garantiza que el archivo se cierre cuando la ejecución esté fuera del alcance de la withsuite, independientemente de si eso ocurre normalmente o si se produjo una excepción. Básicamente es una forma de abstraer el código común de manejo de excepciones.

Otros casos de uso comunes para esto incluyen el bloqueo con hilos y transacciones de bases de datos.


3
No aprobaría una revisión de código que importara algo del futuro . Las características son más lindas que útiles, y generalmente terminan confundiendo a los recién llegados de Python.
un nerd pagado

66
Sí, es mejor dejar esas características "lindas" como ámbitos anidados y generadores para aquellos que saben lo que están haciendo. Y cualquiera que quiera ser compatible con futuras versiones de Python. Para ámbitos anidados y generadores, "versiones futuras" de Python significa 2.2 y 2.5, respectivamente. Para la declaración with, "versiones futuras" de Python significa 2.6.
Chris B.

10
Esto puede ser evidente, pero con python v2.6 +, ya no necesita importar desde el futuro . with es ahora una palabra clave de primera clase.
fitzgeraldsteele

25
En 2.7 puedes tener múltiples withs:) with open('filea') as filea and open('fileb') as fileb: ...
Austin Richardson

55
@Austin no pude conseguir que esa sintaxis funcione en 2.7. Sin embargo este trabajo lo hizo: with open('filea') as filea, open('fileb') as fileb: ...
Wim

168

Los diccionarios tienen un método get ()

Los diccionarios tienen un método 'get ()'. Si haces d ['clave'] y la clave no está allí, obtienes una excepción. Si hace d.get ('clave'), regresa Ninguno si 'clave' no está allí. Puede agregar un segundo argumento para recuperar ese elemento en lugar de Ninguno, por ejemplo: d.get ('clave', 0).

Es genial para cosas como sumar números:

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


39
también, verifique el método setdefault.
Daren Thomas el

27
también, pago colecciones. clase defaultfault.
jfs el

8
Si está utilizando Python 2.7 o posterior, o 3.1 o posterior, consulte la clase Counter en el módulo de colecciones. docs.python.org/library/collections.html#collections.Counter
Elias Zamaria

Oh hombre, todo este tiempo he estado haciendo get(key, None). No tenía idea de que Nonese proporcionaba por defecto.
Jordan Reiter

152

Descriptores

Son la magia detrás de un montón de características centrales de Python.

Cuando usa el acceso punteado para buscar un miembro (por ejemplo, xy), Python primero busca el miembro en el diccionario de instancias. Si no se encuentra, lo busca en el diccionario de la clase. Si lo encuentra en el diccionario de la clase y el objeto implementa el protocolo descriptor, en lugar de simplemente devolverlo, Python lo ejecuta. Un descriptor es cualquier clase que implementa la __get__, __set__o__delete__ métodos.

Así es como implementaría su propia versión (de solo lectura) de la propiedad utilizando descriptores:

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)

y lo usarías igual que la propiedad incorporada ():

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

Los descriptores se usan en Python para implementar propiedades, métodos enlazados, métodos estáticos, métodos de clase y ranuras, entre otras cosas. Comprenderlos hace que sea fácil ver por qué muchas de las cosas que antes parecían 'peculiaridades' de Python son como son.

Raymond Hettinger tiene un excelente tutorial que hace un trabajo mucho mejor describiéndolos que yo.


Este es un duplicado de decoradores, ¿no? ( stackoverflow.com/questions/101268/… )
gecco

2
no, los decoradores y los descriptores son cosas totalmente diferentes, aunque en el código de ejemplo, estoy creando un decorador de descriptores. :)
Nick Johnson

1
La otra forma de hacerlo es con una lambda:foo = property(lambda self: self.__foo)
Pete Peterson el

1
@PetePeterson Sí, pero en propertysí se implementa con descriptores, que fue el punto de mi publicación.
Nick Johnson el

142

Asignación Condicional

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

Hace exactamente lo que parece: "asigna 3 a x si y es 1, de lo contrario asigna 2 a x". Tenga en cuenta que los parens no son necesarios, pero me gustan para facilitar la lectura. También puedes encadenarlo si tienes algo más complicado:

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

Aunque en cierto punto, va un poco demasiado lejos.

Tenga en cuenta que puede usar if ... else en cualquier expresión. Por ejemplo:

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

Aquí se llamará a func1 si y es 1 y func2, de lo contrario. En ambos casos, la función correspondiente se llamará con argumentos arg1 y arg2.

Análogamente, lo siguiente también es válido:

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

donde class1 y class2 son dos clases.


29
La asignación no es la parte especial. Podrías hacer algo como: devolver 3 si (y == 1) más 2.
Brian

25
Esa forma alternativa es la primera vez que veo Python ofuscado.
Craig McQueen

3
Kylebrooks: No es así en ese caso, los operadores booleanos hacen corto circuito. Solo evaluará 2 si bool (3) == False.
RoadieRich

15
Esta codificación de estilo al revés me confunde. algo así x = ((y == 1) ? 3 : 2)tiene más sentido para mí
mpen

13
Siento exactamente lo contrario de @Mark, los operadores ternarios de estilo C siempre me han confundido, ¿es el lado derecho o el medio lo que se evalúa en una condición falsa? Prefiero la sintaxis ternaria de Python.
Jeffrey Harris

141

Doctest : documentación y pruebas unitarias al mismo tiempo.

Ejemplo extraído de la documentación de 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()

66
Las pruebas de documentos son realmente geniales, pero realmente no me gusta todo lo que tienes que escribir para probar que algo debería generar una excepción
TM.

6060
Los doctest están sobrevalorados y contaminan la documentación. ¿Con qué frecuencia prueba una función independiente sin ninguna configuración ()?
un nerd pagado

2
¿Quién dice que no se puede configurar en un doctest? escriba una función que genere el contexto y regrese locals()luego en su doctest do locals().update(setUp())= D
Jiaaro

12
Si una función independiente requiere una configuración, hay muchas posibilidades de que se desacople de algunas cosas no relacionadas o se coloque en una clase. El espacio de nombres de doctest de clase se puede reutilizar en doctests de método de clase, por lo que es un poco como setUp, solo DRY y legible.
Andy Mikhaylenko

44
"¿Con qué frecuencia se prueba una función independiente"? Lotes. Encuentro que los doctests a menudo surgen naturalmente del proceso de diseño cuando decido por las fachadas.
Gregg Lind

138

Formato con nombre

El formato% toma un diccionario (también aplica la validación% i /% s, etc.).

>>> 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.

Y dado que locals () también es un diccionario, simplemente puede pasarlo como un dict y tener% -substitions de sus variables locales. Creo que esto está mal visto, pero simplifica las cosas ...

Nuevo formato de estilo

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

6060
Será eliminado y eventualmente reemplazado por el método format () de la cadena.
Constantin

3
El formato con nombre es muy útil para los traductores, ya que tienden a ver la cadena de formato sin los nombres de las variables para el contexto
pixelbeat

2
Parece funcionar en python 3.0.1 (necesario para agregar paréntesis alrededor de la llamada impresa).
Pasi Savolainen

99
un hash , ¿eh? Ya veo de dónde vienes.
shylent

11
El formato% s no se eliminará gradualmente. str.format () es ciertamente más pitónico, sin embargo, en realidad es 10 veces más lento para el reemplazo simple de cadenas. Mi creencia es que el formateo% s sigue siendo la mejor práctica.
Kenneth Reitz

132

Para agregar más módulos de Python (especialmente los de terceros), la mayoría de las personas parecen usar las variables de entorno PYTHONPATH o agregan enlaces simbólicos o directorios en sus directorios de paquetes de sitio. Otra forma es usar archivos * .pth. Aquí está la explicación oficial del documento de Python:

"La forma más conveniente [de modificar la ruta de búsqueda de Python] es agregar un archivo de configuración de ruta a un directorio que ya está en la ruta de Python, generalmente al directorio ... / site-packages /. Los archivos de configuración de ruta tienen una extensión de .pth , y cada línea debe contener una única ruta que se agregará a sys.path. (Debido a que las nuevas rutas se agregan a sys.path, los módulos en los directorios agregados no anularán los módulos estándar. Esto significa que no puede usar este mecanismo para instalar versiones fijas de módulos estándar.) "


1
Nunca hice la conexión entre ese archivo .pth en el directorio de paquetes del sitio desde setuptools y esta idea. increíble.
dave paola

122

Excepción otra cláusula:

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

El uso de la cláusula else es mejor que agregar código adicional a la cláusula try porque evita detectar accidentalmente una excepción que no fue generada por el código protegido por la declaración try ... except.

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


8
+1 esto es asombroso. Si el bloque try se ejecuta sin ingresar ningún bloque de excepción, se ingresa el bloque else. Y luego, por supuesto, se ejecuta el bloque finalmente
inspectorG4dget

¡Finalmente entiendo por qué el 'otro' está ahí! Gracias.
taynaron

Tendría más sentido usar continuar, pero supongo que ya está tomado;)
Paweł Prażak

Tenga en cuenta que en versiones anteriores de Python2 no puede tener las dos cosas más: y finalmente: cláusulas para el mismo intento: bloque
Kevin Horn

1
@ Paweł Prażak, como mencionó Kevin Horn, esta sintaxis se introdujo después del lanzamiento inicial de Python y agregar nuevas palabras clave reservadas al lenguaje existente siempre es problemático. Es por eso que una palabra clave existente generalmente se reutiliza (cf "auto" en el estándar C ++ reciente).
Constantin

114

Volver a plantear excepciones :

# 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)

La declaración 'raise' sin argumentos dentro de un controlador de errores le dice a Python que vuelva a aumentar la excepción con el rastreo original intacto , permitiéndole decir "oh, lo siento, lo siento, no quise captar eso, lo siento, lo siento. "

Si desea imprimir, almacenar o manipular el rastreo original, puede obtenerlo con sys.exc_info (), e imprimirlo como Python lo haría con el módulo 'rastreo'.


Lo sentimos, pero esta es una característica bien conocida y común de casi todos los idiomas.
Lucas S.

66
Tenga en cuenta el texto en cursiva. Algunas personas lo harán en su raise elugar, lo que no conserva el rastreo original.
habnabit

12
Tal vez sea más mágico, exc_info = sys.exc_info(); raise exc_info[0], exc_info[1], exc_info[2]es equivalente a esto, pero puede cambiar esos valores (por ejemplo, cambiar el tipo de excepción o el mensaje)
Ianb

3
@Lucas S. Bueno, no lo sabía, y me alegra que esté escrito aquí.
e-satis

Puedo estar mostrando mi juventud aquí, pero siempre he usado la sintaxis de Python 3 en Python 2.7 sin ningún problema
wim

106

Mensajes principales :)

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

Descifrado :

El zen de Python, por Tim Peters

Hermoso es mejor que feo.
Explícito es mejor que implícito.
Simple es mejor que complejo.
Complejo es mejor que complicado.
Plano es mejor que anidado.
Escaso es mejor que denso.
La legibilidad cuenta.
Los casos especiales no son lo suficientemente especiales como para romper las reglas.
Aunque la practicidad supera la pureza.
Los errores nunca deben pasar en silencio.
A menos que sea silenciado explícitamente.
Ante la ambigüedad, rechaza la tentación de adivinar. Debe haber una, y preferiblemente solo una, forma obvia de hacerlo.
Aunque esa manera puede no ser obvia al principio a menos que seas holandés. correcto Si la implementación es difícil de explicar, es una mala idea.
Ahora es mejor que nunca.
Aunque nunca es a menudo mejor que ahora. Si la implementación es fácil de explicar, puede ser una buena idea. Los espacios de nombres son una gran idea, ¡hagamos más de eso!



1
¿Alguna idea de por qué se cifró la fuente de esa manera? ¿Fue solo por diversión o hubo alguna otra razón?
MiniQuark

42
la forma en que se escribe la fuente va en contra del zen!
hasen


2
¡He actualizado mi /usr/lib/python2.6/this.py reemplazando el código anterior con esto 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)))y ahora se ve mucho mejor! :-D
fortran

2
@MiniQuark: lección de historia rápida: wefearchange.org/2010/06/import-this-and-zen-of-python.html

105

Finalización de la pestaña de intérprete interactivo

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()

También deberá establecer una variable de entorno PYTHONSTARTUP.


2
Esta es una caracteristica muy útil. Tanto es así que tengo un script simple para habilitarlo (más un par de otras mejoras de introspección): pixelbeat.org/scripts/inpy
pixelbeat

43
IPython le ofrece este más toneladas de otras cosas
interesantes

Esto habría sido más útil en la solicitud de pdb que en la solicitud de Python normal (ya que IPython cumple ese propósito de todos modos). Sin embargo, esto no parece funcionar en el indicador de pdb, probablemente porque pdb se une a su propia pestaña (que es menos útil). Intenté llamar a parse_and_bind () en el indicador pdb, pero aún así no funcionó. La alternativa de obtener pdb prompt con IPython es más trabajo, por lo que tiendo a no usarlo.
haridsv

2
@haridsv - easy_install ipdb- entonces puedes usarimport ipdb; ipdb.set_trace()
Doug Harris

1
En osx [e imagino otros sistemas que usan libedit] tienes que hacerreadline.parse_and_bind ("bind ^I rl_complete")
Foo Bah

91

Lista de comprensiones anidadas y expresiones generadoras:

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

Estos pueden reemplazar enormes fragmentos de código de bucle anidado.


"for j in range (i)" - ¿es esto un error tipográfico? Normalmente querrás rangos fijos para i y j. Si está accediendo a una matriz 2D, se perderá la mitad de sus elementos.
Peter Gibson el

No estoy accediendo a ninguna matriz en este ejemplo. El único propósito de este código es mostrar que las expresiones de los rangos internos pueden acceder a las de los externos. El subproducto es una lista de pares (x, y) de modo que 4> x> y> 0.
Rafał Dowgird

2
algo así como la doble integración en el cálculo, o la sumatoria doble.
Yoo

22
El punto clave para recordar aquí (que me llevó mucho tiempo darme cuenta) es que el orden de las fordeclaraciones debe escribirse en el orden que esperarías que se escriban en un bucle for estándar, desde afuera hacia adentro.
sykora

2
Para añadir al comentario de sykora: imagine que está comenzando con una pila de fors y ifs con yield xel interior. Para convertir eso en una expresión generadora, muévase xprimero, elimine todos los dos puntos (y el yield), y rodee todo entre paréntesis. Para hacer una lista de comprensión, reemplace los parentes exteriores con corchetes.
Ken Arnold

91

Sobrecarga del operador para la setconstrucción:

>>> 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}

Más detalles de la referencia de biblioteca estándar: Establecer tipos


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.