Ejemplos concretos de la máxima de "la única forma de hacerlo" de Python [cerrado]

34

Estoy aprendiendo Python y estoy intrigado por el siguiente punto en PEP 20 The Zen of Python :

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.

¿Alguien podría ofrecer algún ejemplo concreto de esta máxima? Estoy particularmente interesado en el contraste con otros idiomas como Ruby. Parte de la filosofía de diseño de Ruby (¿originaria de Perl, creo?) Es que múltiples formas de hacerlo es algo bueno. ¿Alguien puede ofrecer algunos ejemplos que muestren los pros y los contras de cada enfoque? Tenga en cuenta que no busco una respuesta que sea mejor (que probablemente sea demasiado subjetiva para ser respondida), sino una comparación imparcial de los dos estilos.

Charles Roper
fuente

Respuestas:

47

En comparación con lenguajes como Perl, Python tiene un número limitado de construcciones de control:

  • única ify no hay unless,
  • solo forque itera sobre secuencias y no foreacho estilo C for,
  • solo whileeso comprueba una condición en cada bucle y no do-while,
  • única if-elify no hay switch,
  • solo hay una construcción de comentario, el #, y para cada línea puedes decir si está comentado o no, sin mirar las líneas anteriores.

Además, hay casi una forma de sangrar su fuente; La mayoría de los casos de sangría creativa se excluyen sintácticamente.

Esto hace que analizar una fuente de Python sea más fácil para los humanos.

Hay intentos de ser mínimos pero completos en los tipos integrados y en la biblioteca estándar.

  • para la lista mutable, usa el único tipo incorporado list; es O (1) para la mayoría de las operaciones, y nunca tiene que elegir la implementación correcta,
  • para listas inmutables, igualmente, solo usa el tupletipo,
  • para los mapas, usa el único incorporado dictque es muy eficiente en la mayoría de los casos, sin necesidad de considerar qué implementación usar.

Python 3 extiende esto a los enteros: no importa qué tan grande sea su entero, usted usa el mismo tipo y nunca le importa la coerción.

Python intenta evitar el azúcar sintáctico. Pero a veces agrega azúcar sintáctico solo para hacer obvio el camino obvio. Puede escribir en if foo is not Nonelugar de if not (foo is None)porque 'no es' está en mayúsculas especiales. Todavía se foo is not Nonelee fácilmente, no se puede malinterpretar, y no tienes que pensar, solo escribes lo obvio.

Por supuesto, la mayoría de las cosas más complejas en Python se pueden hacer de varias maneras. Puede agregar métodos a las clases por declaración o por asignación simple de ranuras, puede pasar argumentos a las funciones de varias maneras creativas, etc. Eso es solo porque los aspectos internos del lenguaje están expuestos en su mayoría.

La clave es que siempre hay una manera que pretende ser la mejor, el caso de cubrir todo. Si existen otras formas, no se agregaron como alternativas iguales (como ify unless) sino que simplemente exponen el funcionamiento interno. Lenta pero constantemente, tales alternativas quedan obsoletas (¡no se eliminan!) Al mejorar el mejor mecanismo conocido.

Los decoradores envuelven las llamadas de función AOP. Antes de 2.6, tenía que usar el __metaclass__miembro mágico para declarar la metaclase de una clase; ahora también puede usar la misma sintaxis de decorador para esto. Antes de 3.0, tenía dos tipos de cadenas, orientadas a bytes y Unicode, que podía mezclar inadvertidamente. Ahora tiene el único Unicode stry el único binario transparente bytes, que no puede mezclar por error.

9000
fuente
3
Solo como nota, no olvide los """comentarios (docstrings). Estos abarcan varias líneas.
asthasr
8
Los literales entre comillas triples son solo cadenas, lo mismo que entre comillas simples, pero pueden abarcar varias líneas sin escapar de los extremos de la línea. Una cadena literal justo después de la declaración se considera una cadena de documentación, y no es un comentario, generalmente es accesible como __doc__atributo. Pero las cadenas es un área donde Python sin duda ofrece muchas formas correctas '': el uso de comillas simples, dobles o triples, implícitamente, se unen a los literales adyacentes, el uso rde literales primas, etc.
9000
1
Creo que el comentario de @ syrion fue sobre el "siempre se puede decidir si una línea se comenta o no con sólo mirarlo", lo cual no es cierto debido a """ cadenas.
blubb
2
"Esto hace que analizar una fuente de Python sea más fácil para los humanos". <- eso es subjetivo
jiggy
¿Cómo cambió la declaración de metaclase en 2.7? No se puede encontrar el patrón decorador en los 2.7 documentos para metaclases.
Nick T
10

Otro par de ejemplos son:
len()es una función en lugar de un método presente en cada secuencia; si se compara con Java que tiene .length, .size(), .getSize(), y otros métodos para encontrar el número de elementos en una secuencia.

Otro ejemplo es el hecho de que .join()es un stringmétodo, no un método presente en cada secuencia. No necesita saber si el parámetro de unión es una lista, un conjunto, una comprensión o lo que sea, funcionará.

Vito De Tullio
fuente
8

En C hay muchas formas posibles de aumentar el valor de una variable en uno:

i++     // Post-increment, returns the number before the increment
++i     // Pre-increment, returns the number after the increment
i += 1 

Cada uno termina aumentando el valor de iby 1, pero cada uno es ligeramente diferente.

En Python, en realidad solo hay una forma; solo agrega uno.

i += 1

Y aunque hay más de una forma sintácticamente válida de hacer esto (por ejemplo i = i + 1), estás haciendo lo mismo con los mismos efectos secundarios.


fuente
1
No soy un experto, pero ese ejemplo parece violar con precisión la idea de "la única forma de hacerlo". Tenemos dos formas de hacerlo, pero ¿cuál es la más obvia? Para mí, el primer ejemplo es más obvio, mientras que el segundo es un poco más breve pero no menos legible u obvio para cualquier programador que haya progresado más allá de lo básico. Gracias por su respuesta, es una buena forma de pensar.
Charles Roper
@Peter (y @Charles): En realidad, i = i + 1es una asignación, no un incremento. En python un incremento es i += 1. En lenguajes de tipo C se puede escribir i++, ++iy i += 1.
Josh K
2
No estoy seguro acerca de su comentario de "mucha confusión", sus tres ejemplos de C (se perdió i += 1, por cierto) producen exactamente el mismo resultado. La única vez que veo que las personas se confunden es cuando incrementan o reducen una variable como parte de una expresión más grande, y eso generalmente se rectifica rápidamente al leer la sección correspondiente de la referencia del lenguaje. Personalmente, habría elegido el hecho de que puede referirse al quinto carácter de una cadena por ambos str[4]o *(str+4), pero tal vez eso fue demasiado fácil ...
TMN
2
@ TMN: algunos casos, como max(i++, ++i)no se pueden rectificar rápidamente. C tiene muchos casos de comportamiento "indefinidos" y "dependientes de la implementación", todos por una buena razón, pero cada uno puede crear una trampa.
9000
@ TMN: Sin mencionar 4 [str] (válido en C, puede no ser válido en C ++).
Vatine
6

Otra posibilidad podría ser la lista de comprensiones. En Python, podrías hacer esto:

new_list = []
    for item in list_of_items:
       if item < 10:
           new_list.append(item)

Pero la forma "obvia" (si eres holandés o estás más familiarizado con Python) de hacerlo sería con una comprensión de la lista:

new_list = [item for item in list_of_items if item < 10]

Es más corto, la nueva_lista se crea en un solo paso, se ejecuta más rápido, creo, y es elegante. En el lado negativo, uno podría argumentar que se siente menos explícito, pero creo que una vez que te acostumbras, es igual de explícito.

Queloniano
fuente
Para sangría y código: añádalo con 4 espacios, luego respetará la sangría.
Inca