2010-02-11 21 views
12

¿Cuál es la forma más eficiente/más rápida/mejor de verificar si existe una clave?Python es la mejor manera de verificar si existe una clave

if 'subject' in request.POST: 
    subject = request.POST['subject'] 
else: 
    // handle error 

O

try: 
    subject = request.POST['subject'] 
except KeyError: 
    // handle error 
+0

¿Qué "eficiente", "más rápido" y "mejor" realmente le importa, y qué definición de "eficiente" y "mejor" tiene en mente? –

+0

Supongo que quise decir cuál es la mejor práctica de codificación. En esta situación particular, si 'subject' no es POST, que es un error, no hay ningún valor predeterminado que debería estar allí. Gracias por todas las respuestas. – mhost

Respuesta

28

Este último (try/except) la forma es generalmente la mejor forma.

try bloques son muy baratos, pero la captura de una excepción puede ser más costosa. Un control de contención en un dict tiende a ser barato, pero no es más barato que nada. Sospecho que habrá un equilibrio entre la eficiencia y la frecuencia con la que realmente existe 'subject'. Sin embargo, esto no importa, ya que la optimización prematura es inútil, distrae, desperdicia e ineficaz. Usted iría con la mejor solución.

Si el código sería en realidad de forma

if 'subject' in request.POST: 
    subject = request.POST['subject'] 
else: 
    subject = some_default 

entonces lo que realmente quiere es request.POST.get('subject', some_default).

-2
subject = request.POST.get("subject") 
if subject is None: 
    ... 

:)

+0

Y si el valor asociado con '" asunto "' * es * 'Ninguno'? –

+2

Esto es menos legible que cualquiera de las soluciones en la publicación original. Reemplaza las excepciones con verificación de valor de retorno y es menos directo que una verificación de contención, y tiene un error si 'request.Post ['subject']' ya es 'None'. –

+1

@ Jon-Eric: supongo que no puede ser porque todos los valores publicados en HTTP son cadenas. – recursive

1

Creo que depende de si 'sujeto' no estar en mensaje es en realidad una excepción. Si no se supone que suceda pero usted está siendo extremadamente cuidadoso, entonces su segundo método supondría que sería más eficiente y más rápido. Sin embargo, si usa el cheque para hacer 1 cosa u otra, entonces no es apropiado usar una excepción. Desde el aspecto de su código, iría con su segunda opción.

+0

Sin duda es una circunstancia excepcional (incluso si ocurre el 90% del tiempo). –

+0

¿Cómo puede algo que ocurre el 90% del tiempo ser excepcional? –

+0

Todos los demás casos (la clave existe) están en una categoría diferente. –

2

El segundo error con collections.defaultdict, y la excepción causará un pequeño aumento de rendimiento. Aparte de eso, no hay una diferencia real entre los dos.

+3

Es técnicamente cierto que el segundo método fallará con 'collections.defaultdict', pero más fundamentalmente, * esta es la razón por la cual *' collections.defaultdict' * existe *. –

2

La última vez que revisé, la primera es unos nanosegundos más rápido. Pero la mayoría de los phythonistas parecen favorecer al segundo.

Creo que no soy el único que quiere reservar excepciones para el comportamiento excepcional, así que trato de usar la primera, reservando la segunda cuando es inválida no tener la llave

+0

Esto * es * una circunstancia excepcional. –

1

Yo también me gusta get() también puede especificar un valor predeterminado (que no sea ninguno) en caso de que tenga sentido.

0

dict y muchos objetos dict similar (incluyendo Django HttpRequest que no encontrados) permiten pasar valor predeterminado a get():

subject = request.POST.get('subject', '[some_default_subject]') 

Este es el método preferible ya que es la más corta y más transparente acerca de sus intenciones .

4

Uso el método .get() - es el método preferible.

Python 2.5.2 (r252:60911, Jul 22 2009, 15:33:10) 
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dis 
>>> def f1(key, d): 
... if key in d: 
...  return d[key] 
... else: 
...  return "default" 
... 
>>> dis.dis(f1) 
    2   0 LOAD_FAST    0 (key) 
       3 LOAD_FAST    1 (d) 
       6 COMPARE_OP    6 (in) 
       9 JUMP_IF_FALSE   12 (to 24) 
      12 POP_TOP 

    3   13 LOAD_FAST    1 (d) 
      16 LOAD_FAST    0 (key) 
      19 BINARY_SUBSCR 
      20 RETURN_VALUE 
      21 JUMP_FORWARD    5 (to 29) 
     >> 24 POP_TOP 

    5   25 LOAD_CONST    1 ('default') 
      28 RETURN_VALUE 
     >> 29 LOAD_CONST    0 (None) 
      32 RETURN_VALUE 
>>> def f2(key, d): 
... return d.get(key, "default") 
... 
>>> dis.dis(f2) 
    2   0 LOAD_FAST    1 (d) 
       3 LOAD_ATTR    0 (get) 
       6 LOAD_FAST    0 (key) 
       9 LOAD_CONST    1 ('default') 
      12 CALL_FUNCTION   2 
      15 RETURN_VALUE 
>>> def f3(key, d): 
... try: 
...  return d[key] 
... except KeyError: 
...  return "default" 
... 
>>> dis.dis(f3) 
    2   0 SETUP_EXCEPT   12 (to 15) 

    3   3 LOAD_FAST    1 (d) 
       6 LOAD_FAST    0 (key) 
       9 BINARY_SUBSCR 
      10 RETURN_VALUE 
      11 POP_BLOCK 
      12 JUMP_FORWARD   23 (to 38) 

    4  >> 15 DUP_TOP 
      16 LOAD_GLOBAL    0 (KeyError) 
      19 COMPARE_OP    10 (exception match) 
      22 JUMP_IF_FALSE   11 (to 36) 
      25 POP_TOP 
      26 POP_TOP 
      27 POP_TOP 
      28 POP_TOP 

    5   29 LOAD_CONST    1 ('default') 
      32 RETURN_VALUE 
      33 JUMP_FORWARD    2 (to 38) 
     >> 36 POP_TOP 
      37 END_FINALLY 
     >> 38 LOAD_CONST    0 (None) 
      41 RETURN_VALUE 
Cuestiones relacionadas