stringtranslate.com

Sintaxis y semántica de Python

Un fragmento de código Python con palabras clave resaltadas en negrita amarilla

La sintaxis del lenguaje de programación Python es el conjunto de reglas que definen cómo se escribirá e interpretará un programa Python (tanto por el sistema de ejecución como por los lectores humanos). El lenguaje Python tiene muchas similitudes con Perl , C y Java . Sin embargo, existen algunas diferencias definitivas entre los idiomas. Admite múltiples paradigmas de programación , incluida la programación estructurada, orientada a objetos y la programación funcional, y cuenta con un sistema de tipos dinámicos y administración automática de memoria.

La sintaxis de Python es simple y consistente, y se adhiere al principio de que "debe haber una, y preferiblemente solo una, forma obvia de hacerlo". El lenguaje incorpora estructuras y tipos de datos integrados, mecanismos de flujo de control, funciones de primera clase y módulos para una mejor reutilización y organización del código . Python también usa palabras clave en inglés donde otros idiomas usan puntuación, lo que contribuye a su diseño visual ordenado.

El lenguaje proporciona un manejo sólido de errores a través de excepciones e incluye un depurador en la biblioteca estándar para una resolución eficiente de problemas. La sintaxis de Python, diseñada para facilitar la lectura y el uso, lo convierte en una opción popular tanto entre principiantes como entre profesionales.

Filosofía de diseño

Python fue diseñado para ser un lenguaje altamente legible . [1] Tiene un diseño visual relativamente ordenado y utiliza palabras clave en inglés con frecuencia mientras que otros idiomas usan puntuación . Python pretende ser simple y consistente en el diseño de su sintaxis, resumido en el mantra "Debería haber una, y preferiblemente solo una, forma obvia de hacerlo", del Zen de Python . [2]

Este mantra se opone deliberadamente al mantra de Perl y Ruby : " hay más de una manera de hacerlo ".

Palabras clave

Python tiene 35 palabras clave o palabras reservadas ; no se pueden utilizar como identificadores . [3] [4]

Además, Python también tiene 3 palabras clave suaves . A diferencia de las palabras clave duras normales , las palabras clave blandas son palabras reservadas solo en contextos limitados donde interpretarlas como palabras clave tendría sentido sintáctico. Estas palabras pueden usarse como identificadores en otros lugares; Puede definir una función o variable denominada coincidencia o caso . [6] [7]

Sangría

Python usa espacios en blanco para delimitar bloques de flujo de control (siguiendo la regla fuera de juego ). Python toma prestada esta característica de su predecesor ABC : en lugar de puntuación o palabras clave, utiliza sangría para indicar la ejecución de un bloque .

En los llamados lenguajes de "formato libre", que utilizan la estructura de bloques derivada de ALGOL , los bloques de código se marcan con llaves ( { }) o palabras clave. En la mayoría de las convenciones de codificación para estos lenguajes, los programadores convencionalmente aplican sangrías al código dentro de un bloque, para diferenciarlo visualmente del código circundante.

Una función recursiva denominada , a la que se le pasa un solo parámetro , y si el parámetro es 0 llamará a una función diferente denominada y, de lo contrario, llamará a , pasando y también se llamará a sí misma de forma recursiva, pasando como parámetro, podría implementarse así en Python :fooxbarbazxx-1

def  foo ( x ):  si  x  ==  0 :  bar ()  más :  baz ( x )  foo ( x  -  1 )

y podría escribirse así en C con estilo de sangría K&R :

void foo ( int x ) { si ( x == 0 ) { bar (); } más { baz ( x ); foo ( x - 1 ); } }                

Un lector humano podría interpretar mal el código con sangría incorrecta de forma diferente a como lo interpretaría un compilador o intérprete. Por ejemplo, si la llamada a la función foo(x - 1)en la última línea del ejemplo anterior tenía una sangría errónea para estar fuera del bloque if/ :else

def  foo ( x ):  si  x  ==  0 :  bar ()  más :  baz ( x )  foo ( x  -  1 )

Haría que la última línea siempre se ejecutara, incluso cuando xsea 0, lo que resultaría en una recursividad sin fin .

Si bien se aceptan caracteres de espacio y tabulación como formas de sangría y se puede usar cualquier múltiplo de espacios, se recomiendan espacios [8] y 4 espacios (como en los ejemplos anteriores) y son, con diferencia, los más utilizados. [9] [10] [ ¿ fuente poco confiable? ] No se permite mezclar espacios y tabulaciones en líneas consecutivas a partir de Python 3 [11] porque eso puede crear errores que son difíciles de ver, ya que muchos editores de texto no distinguen visualmente espacios y tabulaciones.

Estructuras de datos

Dado que Python es un lenguaje de tipado dinámico , los valores de Python, no las variables, transportan información de tipo . Todas las variables en Python contienen referencias a objetos y estas referencias se pasan a funciones. Algunas personas (incluido el propio Guido van Rossum ) han llamado a este esquema de paso de parámetros "llamada por referencia de objeto". Una referencia de objeto significa un nombre, y la referencia pasada es un "alias", es decir, una copia de la referencia al mismo objeto, tal como en C/ C++ . El valor del objeto se puede cambiar en la función llamada con el "alias", por ejemplo:

>>> alista  =  [ 'a' ,  'b' ,  'c' ] >>> def  mi_func ( al ): ...  al . agregar ( 'x' ) ...  imprimir ( al ) ... >>> my_func ( alista ) ['a', 'b', 'c', 'x'] >>> alista ['a', ' b', 'c', 'x']

La función my_funccambia el valor de alistcon el argumento formal al, que es un alias de alist. Sin embargo, cualquier intento de operar (asignar una nueva referencia de objeto) en el alias en sí no tendrá ningún efecto en el objeto original. [ se necesita aclaración ]

>>> alista  =  [ 'a' ,  'b' ,  'c' ] >>> def  mi_func ( al ): ...  # al.append('x') ...  al  =  al  +  [ 'x' ]  # una nueva lista creada y asignada a al significa que al ya no es un alias para alist ...  print ( al ) ... >>> my_func ( alist ) ['a', 'b', 'c', 'x '] >>> imprimir ( alista ) ['a', 'b', 'c']

En Python, los nombres accesibles no locales más internos y no declarados globales son todos alias.

Entre los lenguajes de tipado dinámico, Python tiene una verificación de tipo moderada. La conversión implícita se define para tipos numéricos (así como booleanos ), por lo que se puede multiplicar válidamente un número complejo por un número entero (por ejemplo) sin conversión explícita . Sin embargo, no existe una conversión implícita entre, por ejemplo, números y cadenas ; una cadena es un argumento no válido para una función matemática que espera un número.

Tipos de bases

Python tiene una amplia gama de tipos de datos básicos. Además de la aritmética convencional de números enteros y de coma flotante , admite de forma transparente la aritmética de precisión arbitraria , los números complejos y los números decimales .

Python admite una amplia variedad de operaciones con cadenas. Las cadenas en Python son inmutables , por lo que una operación de cadena, como una sustitución de caracteres , que en otros lenguajes de programación podría alterar la cadena en su lugar , devuelve una nueva cadena en Python. Las consideraciones de rendimiento a veces impulsan el uso de técnicas especiales en programas que modifican cadenas de manera intensiva, como unir matrices de caracteres en cadenas sólo cuando sea necesario.

Tipos de colección

Uno de los aspectos muy útiles de Python es el concepto de tipos de colección (o contenedor ). En general, una colección es un objeto que contiene otros objetos de una manera que se puede referenciar o indexar fácilmente . Las colecciones se presentan en dos formas básicas: secuencias y mapeos .

Los tipos secuenciales ordenados son listas ( matrices dinámicas ), tuplas y cadenas. Todas las secuencias están indexadas posicionalmente ( de 0 a longitud - 1 ) y todas, excepto las cadenas, pueden contener cualquier tipo de objeto, incluidos varios tipos en la misma secuencia. Tanto las cadenas como las tuplas son inmutables, lo que las convierte en candidatas perfectas para claves de diccionario (ver más abajo). Las listas, por otra parte, son mutables; Los elementos se pueden insertar, eliminar, modificar, agregar u ordenar in situ .

Las asignaciones, por otro lado, son tipos (a menudo desordenados) implementados en forma de diccionarios que "mapean" un conjunto de claves inmutables a los elementos correspondientes (muy parecido a una función matemática). Por ejemplo, se podría definir un diccionario que tenga una cadena "toast"asignada a un número entero 42o viceversa. Las claves de un diccionario deben ser de un tipo Python inmutable, como un número entero o una cadena, porque en el fondo se implementan mediante una función hash . Esto hace que los tiempos de búsqueda sean mucho más rápidos, pero requiere que las claves no se cambien.

Los diccionarios son fundamentales para el funcionamiento interno de Python, ya que residen en el núcleo de todos los objetos y clases: las asignaciones entre nombres de variables (cadenas) y los valores a los que hacen referencia los nombres se almacenan como diccionarios (consulte Sistema de objetos). Dado que se puede acceder directamente a estos diccionarios (a través del __dict__atributo de un objeto), la metaprogramación es un proceso sencillo y natural en Python.

Un tipo de colección de conjuntos es una colección desordenada y no indexada que no contiene duplicados e implementa operaciones teóricas de conjuntos como unión , intersección , diferencia , diferencia simétrica y pruebas de subconjuntos . Hay dos tipos de conjuntos: sety frozenset, la única diferencia es que setes mutable y frozensetes inmutable. Los elementos de un conjunto deben ser hash. Así, por ejemplo, a frozensetpuede ser un elemento de un regular set, mientras que lo contrario no es cierto.

Python también proporciona amplias capacidades de manipulación de colecciones, como verificación de contención integrada y un protocolo de iteración genérico.

Sistema de objetos

En Python todo es un objeto, incluso las clases. Las clases, como objetos, tienen una clase, que se conoce como metaclase . Python también admite herencia múltiple y mixins .

El lenguaje admite una extensa introspección de tipos y clases. Los tipos se pueden leer y comparar; los tipos son instancias de type. Los atributos de un objeto se pueden extraer como un diccionario.

Los operadores se pueden sobrecargar en Python definiendo funciones miembro especiales; por ejemplo, definir un método nombrado __add__en una clase permite usar el +operador en objetos de esa clase.

Literales

Instrumentos de cuerda

Python tiene varios tipos de cadenas literales .

Literales de cadena normales

Se pueden utilizar comillas simples o dobles para citar cadenas. A diferencia de los lenguajes shell de Unix, Perl o lenguajes influenciados por Perl como Ruby o Groovy , las comillas simples y dobles funcionan de manera idéntica, es decir, no hay interpolación de cadenas de expresiones $foo . Sin embargo, la interpolación se puede realizar de varias maneras: con "f-strings" (desde Python 3.6 [12] ), usando el formatmétodo o el antiguo operador de formato de cadena % .

Por ejemplo, todas estas declaraciones de Python:

print ( f "Acabo de imprimir { num } páginas en la impresora { impresora } " )print ( "Acabo de imprimir {} páginas en la impresora {} " . formato ( num ,  impresora )) print ( " Acabo de imprimir {0} páginas en la impresora {1} " . formato ( num ,  impresora )) print ( "Acabo de imprimir {num} páginas en la impresora {printer} " . formato ( num = num ,  impresora = impresora ))print ( "Acabo de imprimir %s páginas en la impresora %s "  %  ( num ,  impresora )) print ( "Acabo de imprimir %(num)s páginas en la impresora %(printer)s "  %  { "num" :  num ,  "impresora" :  impresora })

son equivalentes a la declaración de Perl:

print "Acabo de imprimir $num páginas en la impresora $printer\n" 

Construyen una cadena usando las variables numy printer.

Literales de cadena de varias líneas

También hay cadenas de varias líneas, que comienzan y terminan con una serie de tres comillas simples o dobles y funcionan como estos documentos en Perl y Ruby .

Un ejemplo simple con interpolación de variables (usando el formatmétodo) es:

print ( '''Estimado {destinatario} ,Deseo que te vayas de Sunnydale y nunca regreses.No del todo amor, {remitente} ''' . formato ( remitente = "Buffy, la cazavampiros" ,  destinatario = "Spike" ))

cuerdas crudas

Finalmente, todos los tipos de cadenas mencionados anteriormente vienen en variedades " sin formato " (que se indican colocando una r literal antes de la comilla inicial), que no realizan interpolación de barra invertida y, por lo tanto, son muy útiles para expresiones regulares ; compare "@-quoting" en C# . Las cadenas sin formato se incluyeron originalmente específicamente para expresiones regulares. Debido a las limitaciones del tokenizador, es posible que las cadenas sin formato no tengan una barra invertida al final. [13] Crear una cadena sin formato que contenga una ruta de Windows que termine con una barra invertida requiere cierta variedad de soluciones (comúnmente, usar barras diagonales en lugar de barras invertidas, ya que Windows acepta ambas).

Ejemplos incluyen:

>>> # Una ruta de Windows, incluso las cadenas sin formato no pueden terminar en una barra invertida >>> r "C:\Foo\Bar\Baz \" File "<stdin>" , línea 1 r "C:\Foo\Bar\Baz \" ^ SyntaxError : EOL al escanear la cadena literal  >>> dos_path  =  r "C:\Foo\Bar\Baz\ "  # evita el error agregando >>> dos_path . rstrip ()  # y eliminando el espacio final 'C:\\Foo\\Bar\\Baz\\'>>> quoted_dos_path  =  r '" {} "' . formato ( dos_path ) >>> quoted_dos_path '"C:\\Foo\\Bar\\Baz\\ "'>>> # Una expresión regular que coincide con una cadena entre comillas con posible barra invertida >>> re . match ( r '"(([^" \\ ]| \\ .)*)"' ,  quoted_dos_path ) . group ( 1 ) . rstrip () 'C:\\Foo\\Bar\\Baz\\'>>> code  =  'foo(2, bar)' >>> # Invierte los argumentos en una llamada de función de dos argumentos >>> re . sub ( r '\(([^,]*?),([^ ,]*?)\)' , r  ' (\2, \1)' ,  código ) 'foo(2, barra)' >> > # Tenga en cuenta que esto no funcionará si alguno de los argumentos tiene paréntesis o comas.

Concatenación de literales de cadena adyacentes

Los literales de cadena (que utilizan convenciones de comillas posiblemente diferentes) que aparecen de forma contigua y solo separados por espacios en blanco (incluidas las líneas nuevas) están permitidos y se agregan en una única cadena más larga. [14] Así

title  =  "Una buena acción: " \ 'Una historia natural del destornillador y el tornillo'

es equivalente a

title  =  "Una buena acción: una historia natural del destornillador y el tornillo"

Unicódigo

Desde Python 3.0, el juego de caracteres predeterminado es UTF-8 tanto para el código fuente como para el intérprete. En UTF-8, las cadenas Unicode se manejan como cadenas de bytes tradicionales. Este ejemplo funcionará:

s  =  "Γειά"  # Hola en letra griega ( s )

Números

Los literales numéricos en Python son del tipo normal, por ejemplo 0, -1, 3.4, 3.5e-8.

Python tiene números enteros de longitud arbitraria y aumenta automáticamente su tamaño de almacenamiento según sea necesario. Antes de Python 3, había dos tipos de números enteros: enteros tradicionales de tamaño fijo y enteros "largos" de tamaño arbitrario. La conversión a enteros "largos" se realizaba automáticamente cuando era necesario y, por lo tanto, el programador normalmente no tenía que conocer los dos tipos de integrales. En las versiones de idiomas más recientes, la distinción desaparece por completo y todos los números enteros se comportan como números enteros de longitud arbitraria.

Python admite números de coma flotante normales , que se crean cuando se usa un punto en un literal (p. ej. 1.1), cuando se usan un número entero y un número de coma flotante en una expresión o como resultado de algunas operaciones matemáticas ("división verdadera" a través de el /operador, o exponenciación con exponente negativo).

Python también admite números complejos de forma nativa. Los números complejos se indican con el sufijo Jo j, por ejemplo 3 + 4j.

Listas, tuplas, conjuntos, diccionarios.

Python tiene soporte sintáctico para la creación de tipos de contenedores.

Las listas (clase list) son secuencias mutables de elementos de tipos arbitrarios y se pueden crear con la sintaxis especial

lista_a  =  [ 1 ,  2 ,  3 ,  "un perro" ]

o usando la creación normal de objetos

una_segunda_lista  =  [] una_segunda_lista . agregar ( 4 ) una_segunda_lista . añadir ( 5 )

Las tuplas (clase tuple) son secuencias inmutables de elementos de tipos arbitrarios. También hay una sintaxis especial para crear tuplas.

una_tupla  =  1 ,  2 ,  3 ,  "cuatro" una_tupla  =  ( 1 ,  2 ,  3 ,  "cuatro" )

Aunque las tuplas se crean separando elementos con comas, la construcción completa suele estar entre paréntesis para aumentar la legibilidad. Una tupla vacía se indica con (), mientras que una tupla con un único valor se puede crear con (1,).

Los conjuntos (clase set) son contenedores mutables de elementos hash [15] de tipos arbitrarios, sin duplicados. Los elementos no están ordenados, pero los conjuntos admiten la iteración sobre los elementos. La sintaxis para la creación de conjuntos utiliza llaves.

algún_conjunto  =  { 0 ,  (),  Falso }

Los conjuntos de Python son muy parecidos a los conjuntos matemáticos y admiten operaciones como la intersección y unión de conjuntos . Python también incluye una frozensetclase para conjuntos inmutables; consulte Tipos de colección.

Los diccionarios (clase dict) son asignaciones mutables que vinculan claves y valores correspondientes. Python tiene una sintaxis especial para crear diccionarios ( {key: value})

a_dictionary  =  { "clave 1" :  "valor 1" ,  2 :  3 ,  4 :  []}

La sintaxis del diccionario es similar a la sintaxis establecida, la diferencia es la presencia de dos puntos. El literal vacío {}da como resultado un diccionario vacío en lugar de un conjunto vacío, que en su lugar se crea utilizando el constructor no literal: set().

Operadores

Aritmética

Python incluye los operadores +, -, *( /"división verdadera"), //( división de piso ), %( módulo ) y **( exponenciación ), con su precedencia matemática habitual .

En Python 3, x / yrealiza una "división verdadera", lo que significa que siempre devuelve un valor flotante, incluso si ambos xy yson números enteros que se dividen uniformemente.

>>> 4/2  2.0 

y //realiza división de enteros o división de piso , devolviendo el piso del cociente como un número entero.

En Python 2 (y la mayoría de los otros lenguajes de programación), a menos que se solicite explícitamente, x / yse realiza una división de enteros y se devuelve un valor flotante solo si alguna de las entradas es un valor flotante. Sin embargo, debido a que Python es un lenguaje de tipado dinámico, no siempre fue posible saber qué operación se estaba realizando, lo que a menudo generaba errores sutiles, lo que provocó la introducción del //operador y el cambio en la semántica del /operador en Python 3.

Operadores de comparación

Los operadores de comparación, es decir ==, !=, <, >, <=, >=, is, y [16]is not se utilizan en todo tipo de valores. Se pueden comparar números, cadenas, secuencias y asignaciones. En Python 3, los tipos dispares (como a y an ) no tienen un orden relativo consistente y los intentos de comparar estos tipos generan una excepción. Si bien era posible comparar tipos dispares en Python 2 (por ejemplo, si una cadena era mayor o menor que un número entero), el orden no estaba definido; Esto se consideró una peculiaridad del diseño histórico y finalmente se eliminó en Python 3.innot instrintTypeError

Las expresiones de comparación encadenadas como a < b < ctienen aproximadamente el significado que tienen en matemáticas, en lugar del significado inusual que se encuentra en C y lenguajes similares. Los términos se evalúan y comparan en orden. La operación tiene una semántica de cortocircuito , lo que significa que se garantiza que la evaluación se detendrá tan pronto como el veredicto sea claro: si a < bes falso, cnunca se evalúa porque la expresión ya no puede ser verdadera.

Para expresiones sin efectos secundarios, a < b < cequivale a a < b and b < c. Sin embargo, existe una diferencia sustancial cuando las expresiones tienen efectos secundarios. a < f(x) < bevaluará f(x)exactamente una vez, mientras que a < f(x) and f(x) < blo evaluará dos veces si el valor de aes menor que f(x)y una vez en caso contrario.

Operadores logicos

En todas las versiones de Python, los operadores booleanos tratan los valores cero o los valores vacíos como "", 0, None, 0.0, []y {}como falsos, mientras que en general tratan los valores no vacíos y distintos de cero como verdaderos. Los valores booleanos Truey Falsese agregaron al lenguaje en Python 2.2.1 como constantes (subclasificadas de 1y 0) y se cambiaron para que sean palabras clave completas en Python 3. Los operadores de comparación binaria como ==y >devuelven Trueo False.

Los operadores booleanos andy orutilizan una evaluación mínima . Por ejemplo, y == 0 or x/y > 100nunca generará una excepción de división por cero. Estos operadores devuelven el valor del último operando evaluado, en lugar de Trueo False. Por lo tanto, la expresión (4 and 5)se evalúa como 5y (4 or 5)se evalúa como 4.

Programación funcional

Como se mencionó anteriormente, otro punto fuerte de Python es la disponibilidad de un estilo de programación funcional . Como era de esperar, esto hace que trabajar con listas y otras colecciones sea mucho más sencillo.

Comprensiones

Una de esas construcciones es la lista de comprensión , que se puede expresar con el siguiente formato:

L  =  [ mapeo_expresión  para  elemento  en  lista_fuente  si  expresión_filtro ]

Usar la comprensión de listas para calcular las primeras cinco potencias de dos:

poderes_de_dos  =  [ 2 ** n  para  n  en  el rango ( 1 ,  6 )]

El algoritmo Quicksort se puede expresar de manera elegante (aunque ineficiente) usando listas por comprensión:

def  qsort ( L ):  if  L  ==  []:  return  []  pivot  =  L [ 0 ]  return  ( qsort ([ x  para  x  en  L [ 1 :]  if  x  <  pivot ])  +  [ pivot ]  +  qsort ([ x  para  x  en  L [ 1 :]  si  x  >=  pivote ]))

Python 2.7+ [17] también admite comprensión de conjuntos [18] y comprensión de diccionario. [19]

Funciones de primera clase

En Python, las funciones son objetos de primera clase que se pueden crear y transmitir dinámicamente.

El soporte limitado de Python para funciones anónimas es la lambdaconstrucción. Un ejemplo es la función anónima que eleva al cuadrado su entrada, llamada con el argumento 5:

f  =  lambda  x :  x ** 2 f ( 5 )

Las lambdas se limitan a contener una expresión en lugar de declaraciones , aunque el flujo de control aún se puede implementar de manera menos elegante dentro de lambda mediante el uso de cortocircuitos [20] y de manera más idiomática con expresiones condicionales. [21]

Cierres

Python ha admitido cierres léxicos desde la versión 2.2. A continuación se muestra una función de ejemplo que devuelve una función que se aproxima a la derivada de la función dada:

 derivada def ( f ,  dx ): """Devuelve una función que se aproxima a la derivada de f  usando un intervalo de dx, que debe ser apropiadamente pequeño.  """ función def ( x ): devuelve ( f ( x + dx ) - función de retorno f ( x )) / dx             

Sin embargo, la sintaxis de Python a veces lleva a los programadores de otros lenguajes a pensar que los cierres no son compatibles. El alcance de la variable en Python está implícitamente determinado por el alcance en el que se asigna un valor a la variable, a menos que el alcance se declare explícitamente con globalo nonlocal. [22]

Tenga en cuenta que la vinculación del cierre de un nombre a algún valor no es mutable desde dentro de la función. Dado:

>>> def  foo ( a ,  b ): ...  print ( f 'a: { a } ' ) ...  print ( f 'b: { b } ' ) ...  def  bar ( c ): .. .b  = c  ... imprimir ( f 'b*: { b } ' ) ... barra ( a ) ... imprimir ( f 'b : { b } ' ) ... >>> foo ( 1 , 2 ) a: 1 b: 2 b*: 1 b: 2     

y puede ver que b, como se ve desde el alcance del cierre, conserva el valor que tenía; el enlace modificado bdentro de la función interna no se propagó hacia afuera. La solución a esto es utilizar una nonlocal bdeclaración en bar. En Python 2 (que carece de nonlocal), la solución habitual es utilizar un valor mutable y cambiar ese valor, no el enlace. Por ejemplo, una lista con un elemento.

Generadores

Introducidos en Python 2.2 como una característica opcional y finalizados en la versión 2.3, los generadores son el mecanismo de Python para la evaluación diferida de una función que de otro modo devolvería una lista con un espacio prohibitivo o computacionalmente intensiva.

Este es un ejemplo para generar números primos de forma perezosa:

del  recuento de importaciones de itertools  def  generate_primes ( stop_at = Ninguno ):  primos  =  []  para  n  en  recuento ( inicio = 2 ):  si  stop_at  no es  Ninguno y n > stop_at : return # genera la excepción StopIteration compuesta = False para p en números primos : si no n % p : compuesto = Verdadero romper elif p ** 2 > n : romper si no es compuesto : primos . agregar ( n ) producir n                                    

Al llamar a esta función, el valor devuelto se puede iterar de forma muy parecida a una lista:

para  i  en  generate_primes ( 100 ):  # itera sobre los números primos entre 0 y 100  print ( i )para  i  en  generate_primes ():  # iterar sobre TODOS los primos indefinidamente  imprimir ( i )

La definición de un generador parece idéntica a la de una función, excepto que yieldse usa la palabra clave en lugar de return. Sin embargo, un generador es un objeto con estado persistente, que puede entrar y salir repetidamente del mismo ámbito. Luego se puede usar una llamada de generador en lugar de una lista u otra estructura sobre cuyos elementos se iterarán. Siempre que el forbucle del ejemplo requiere el siguiente elemento, se llama al generador y genera el siguiente elemento.

Los generadores no tienen que ser infinitos como en el ejemplo anterior de números primos. Cuando finaliza un generador, se genera una excepción interna que indica a cualquier contexto de llamada que no hay más valores. forEntonces terminará un bucle u otra iteración.

Expresiones generadoras

Introducidas en Python 2.4, las expresiones generadoras son el equivalente de evaluación diferida de las listas por comprensión. Usando el generador de números primos proporcionado en la sección anterior, podríamos definir una colección diferida, pero no del todo infinita.

desde  itertools  importar  isliceprimos_bajo_millones  =  ( i  para  i  en  generar_primos ()  si  i  <  1000000 ) dos_milésimo_prime  =  islice ( primos_bajo_millones ,  1999 ,  2000 ) . próximo ()

La mayor parte de la memoria y el tiempo necesarios para generar tantos números primos no se utilizarán hasta que se acceda al elemento necesario. Desafortunadamente, no puede realizar una indexación y división simples de generadores, sino que debe usar el módulo itertools o "hacer sus propios" bucles. Por el contrario, una lista por comprensión es funcionalmente equivalente, pero es codiciosa al realizar todo el trabajo:

primos_menos_millones  =  [ i  para  i  en  generar_primos ( 2000000 )  si  i  <  1000000 ] dos_milésimo_prime  =  primos_menos_millones [ 1999 ]

La comprensión de la lista creará inmediatamente una lista grande (con 78498 elementos, en el ejemplo, pero creando transitoriamente una lista de números primos menores de dos millones), incluso si nunca se accede a la mayoría de los elementos. La comprensión del generador es más parsimoniosa.

Diccionario y conjuntos por comprensión

Si bien las listas y los generadores tenían comprensiones/expresiones, en las versiones de Python anteriores a la 2.7, los otros tipos de colecciones integradas de Python (dictados y conjuntos) tuvieron que ser complicados al usar listas o generadores:

>>>  dict (( n ,  n * n )  para  n  en  el rango ( 5 )) { 0 :  0 ,  1 :  1 ,  2 :  4 ,  3 :  9 ,  4 :  16 }

Python 2.7 y 3.0 unificaron todos los tipos de colecciones mediante la introducción de diccionarios y conjuntos de comprensión, similares a las listas de comprensión:

>>>  [ n * n  para  n  en  el rango ( 5 ) ]  # comprensión de lista normal [ 0 ,  1 ,  4 ,  9 ,  16 ] >>> >>>  { n * n  para  n  en  el rango ( 5 )}  # conjunto comprensión { 0 ,  1 ,  4 ,  9 ,  16 } >>> >>>  { n :  n * n  para  n  en  el rango ( 5 )}  # dict comprensión { 0 :  0 ,  1 :  1 ,  2 :  4 ,  3 :  9 ,  4 :  16 }

Objetos

Python admite la mayoría de las técnicas de programación orientada a objetos (OOP). Permite el polimorfismo , no sólo dentro de una jerarquía de clases sino también mediante tipeo pato . Cualquier objeto se puede utilizar para cualquier tipo y funcionará siempre que tenga los métodos y atributos adecuados. Y todo en Python es un objeto, incluidas clases, funciones, números y módulos. Python también admite metaclases , una herramienta avanzada para mejorar la funcionalidad de las clases. Naturalmente, se admite la herencia , incluida la herencia múltiple . Python tiene un soporte muy limitado para variables privadas mediante la manipulación de nombres , que rara vez se utiliza en la práctica , ya que algunos consideran que la ocultación de información no es pitónica , ya que sugiere que la clase en cuestión contiene elementos internos poco estéticos o mal planificados. El eslogan "aquí todos somos usuarios responsables" se utiliza para describir esta actitud. [23]

Como ocurre con los módulos, las clases en Python no ponen una barrera absoluta entre la definición y el usuario, sino que dependen de la cortesía del usuario para no "irrumpir en la definición".

—  9. Clases, Tutorial de Python 2.6 (2013)

Las doctrinas de programación orientada a objetos , como el uso de métodos de acceso para leer miembros de datos, no se aplican en Python. Así como Python ofrece construcciones de programación funcional pero no intenta exigir transparencia referencial , ofrece un sistema de objetos pero no exige comportamiento OOP . Además, siempre es posible redefinir la clase usando propiedades (consulte Propiedades) de modo que cuando una determinada variable se establezca o recupere en el código de llamada, realmente invoque una llamada de función, por lo que spam.eggs = toastrealmente podría invocar spam.set_eggs(toast). Esto anula la ventaja práctica de las funciones de acceso y sigue siendo OOP porque la propiedad eggsse convierte en una parte legítima de la interfaz del objeto: no necesita reflejar un detalle de implementación.

En la versión 2.2 de Python, se introdujeron clases de "nuevo estilo". Con las clases de nuevo estilo, los objetos y tipos se unificaron, permitiendo la subclasificación de tipos. Incluso se pueden definir tipos completamente nuevos, con comportamiento personalizado para operadores infijos. Esto permite hacer muchas cosas radicales sintácticamente dentro de Python. También se adoptó un nuevo orden de resolución de métodos para herencia múltiple con Python 2.3. También es posible ejecutar código personalizado al acceder o configurar atributos, aunque los detalles de esas técnicas han evolucionado entre las versiones de Python.

Con declaración

La withdeclaración maneja recursos y permite a los usuarios trabajar con el protocolo Context Manager. [24]__enter__() Se llama a una función ( ) al entrar al alcance y a otra ( __exit__()) al salir. Esto evita olvidarse de liberar el recurso y también maneja situaciones más complicadas, como liberar el recurso cuando ocurre una excepción mientras está en uso. Los administradores de contexto se utilizan a menudo con archivos, conexiones de bases de datos, casos de prueba, etc.

Propiedades

Las propiedades permiten invocar métodos especialmente definidos en una instancia de objeto utilizando la misma sintaxis que se utiliza para el acceso a atributos. Un ejemplo de una clase que define algunas propiedades es:

clase  MiClase :  def  __init__ ( self ):  self . _a  =  Ninguno @property  def  a ( self ):  devuelve  self . _a @a . setter  # hace que la propiedad sea escribible  def  a ( self ,  value ):  self . _a  =  valor

Descriptores

Una clase que define uno o más de los tres métodos especiales __get__(self, instance, owner)se puede utilizar como descriptor. Crear una instancia de un descriptor como miembro de una segunda clase convierte a la instancia en una propiedad de la segunda clase. [25]__set__(self, instance, value)__delete__(self, instance)

Clase y métodos estáticos.

Python permite la creación de métodos de clase y métodos estáticos mediante el uso de decoradores @classmethod y . @staticmethodEl primer argumento de un método de clase es el objeto de clase en lugar de la autorreferencia a la instancia. Un método estático no tiene un primer argumento especial. Ni la instancia ni el objeto de clase se pasan a un método estático.

Excepciones

Python admite (y utiliza ampliamente) el manejo de excepciones como medio para probar condiciones de error y otros eventos "excepcionales" en un programa.

El estilo Python exige el uso de excepciones siempre que pueda surgir una condición de error. En lugar de probar el acceso a un archivo o recurso antes de usarlo, en Python es convencional seguir adelante e intentar usarlo, detectando la excepción si se rechaza el acceso.

Las excepciones también se pueden utilizar como un medio más general de transferencia de control no local, incluso cuando no se trata de un error. Por ejemplo, el software de listas de correo Mailman , escrito en Python, utiliza excepciones para salir de una lógica de manejo de mensajes profundamente anidada cuando se ha tomado la decisión de rechazar un mensaje o retenerlo para la aprobación del moderador.

Las excepciones se utilizan a menudo como alternativa al ifbloque -, especialmente en situaciones de subprocesos . Un lema comúnmente invocado es EAFP, o "Es más fácil pedir perdón que permiso", [26] que se atribuye a Grace Hopper . [27] [28] La alternativa, conocida como LBYL, o "Mira antes de saltar", prueba explícitamente las condiciones previas. [29]

En este primer ejemplo de código, siguiendo el enfoque LBYL, hay una verificación explícita del atributo antes del acceso:

if  hasattr ( spam ,  'huevos' ):  jamón  =  spam . huevos más :  handle_missing_attr ()

Este segundo ejemplo sigue el paradigma EAFP:

Pruebe :  ham  =  spam . huevos excepto  AttributeError :  handle_missing_attr ()

Estos dos ejemplos de código tienen el mismo efecto, aunque habrá diferencias de rendimiento. Cuando spamtiene el atributo eggs, la muestra EAFP se ejecutará más rápido. Cuando spamno tiene el atributo eggs(el caso "excepcional"), la muestra EAFP se ejecutará más lentamente. El generador de perfiles de Python se puede utilizar en casos específicos para determinar las características de rendimiento. Si los casos excepcionales son raros, entonces la versión EAFP tendrá un rendimiento promedio superior al de la alternativa. Además, evita toda la clase de vulnerabilidades de tiempo de verificación a tiempo de uso (TOCTTOU), otras condiciones de carrera , [28] [30] y es compatible con la escritura pato . Una desventaja de EAFP es que sólo se puede utilizar con declaraciones; una excepción no se puede capturar en una expresión generadora, comprensión de lista o función lambda.

Comentarios y cadenas de documentación

Python tiene dos formas de anotar código Python. Una es utilizar comentarios para indicar qué hace alguna parte del código. Los comentarios de una sola línea comienzan con el carácter almohadilla ( #) y continúan hasta el final de la línea. Los comentarios que abarcan más de una línea se logran insertando una cadena de varias líneas (con """o '''como delimitador en cada extremo) que no se usa en la asignación ni se evalúa de otra manera, sino que se ubica entre otras declaraciones.

Comentando un fragmento de código:

 sistema de importacióndef  getline ():  devuelve  sys . entrada estándar . readline ()  # Obtener una línea y devolverla

Comentando un fragmento de código con varias líneas:

def  getline (): """Esta función obtiene una línea y la devuelve.  Como demostración, esta es una cadena de documentación de varias líneas. Se puede acceder a esta cadena completa como getline.__doc__. " "  "  devuelve  sys.stdin.readline ( )

Las cadenas de documentos (cadenas de documentación), es decir, cadenas que se encuentran solas sin asignación como primera línea sangrada dentro de un módulo, clase, método o función, configuran automáticamente su contenido como un atributo llamado __doc__, cuyo objetivo es almacenar una descripción legible por humanos. del propósito, comportamiento y uso del objeto. La función incorporada helpgenera su salida en función de __doc__los atributos. Dichas cadenas se pueden delimitar con "o 'para cadenas de una sola línea, o pueden abarcar varias líneas si se delimitan con """o, '''que es la notación de Python para especificar cadenas de varias líneas. Sin embargo, la guía de estilo del idioma especifica que """se prefieren las comillas dobles triples () para cadenas de documentos de una o varias líneas. [31]

Cadena de documentación de una sola línea:

def  getline (): """Obtener una línea de stdin y devolverla.""" return sys . entrada estándar . línea de lectura ()   

Cadena de documentación de varias líneas:

def  getline (): """Obtiene una línea  de stdin  y la devuelve.  """ return sys . entrada estándar . línea de lectura ()   

Las cadenas de documentos pueden ser tan grandes como el programador quiera y contener saltos de línea . A diferencia de los comentarios, las cadenas de documentación son en sí mismas objetos de Python y forman parte del código interpretado que ejecuta Python. Eso significa que un programa en ejecución puede recuperar sus propias cadenas de documentación y manipular esa información, pero el uso normal es brindar a otros programadores información sobre cómo invocar el objeto que se documenta en la cadena de documentación.

Hay herramientas disponibles que pueden extraer las cadenas de documentación del código Python y generar documentación. También se puede acceder a la documentación de Docstring desde el intérprete con la help()función o desde el shell con el comando pydocpydoc .

El módulo estándar doctest utiliza interacciones copiadas de sesiones de shell de Python en cadenas de documentos para crear pruebas, mientras que el módulo docopt las usa para definir opciones de línea de comandos.

Anotaciones de funciones

Las anotaciones de funciones (sugerencias de tipo) están definidas en PEP 3107. [32] Permiten adjuntar datos a los argumentos y devolver una función. El comportamiento de las anotaciones no está definido por el lenguaje y se deja en manos de marcos de terceros. Por ejemplo, se podría escribir una biblioteca para manejar escritura estática: [32]

def  haul ( elemento :  transportable ,  * vargs :  PackAnimal )  ->  Distancia

Decoradores

Un decorador es cualquier objeto Python invocable que se utiliza para modificar una función, método o definición de clase. A un decorador se le pasa el objeto original que se está definiendo y devuelve un objeto modificado, que luego se vincula al nombre en la definición. Los decoradores de Python se inspiraron en parte en las anotaciones de Java y tienen una sintaxis similar; la sintaxis del decorador es puro azúcar sintáctico , utilizando @como palabra clave:

@viking_chorus def  menu_item ():  imprimir ( "spam" )

es equivalente a

def  elemento_menú ():  imprimir ( "spam" ) elemento_menú  =  coro_vikingo ( elemento_menú )

Los decoradores son una forma de metaprogramación ; potencian la acción de la función o método que decoran. Por ejemplo, en el siguiente ejemplo, viking_choruses posible menu_itemque se ejecute 8 veces (consulte el boceto de spam ) por cada vez que se llame:

def  viking_chorus ( myfunc ):  def  internal_func ( * args ,  ** kwargs ):  para  i  en  el rango ( 8 ):  myfunc ( * args ,  ** kwargs )  return  internal_func

Los usos canónicos de los decoradores de funciones son para crear métodos de clase o métodos estáticos , agregar atributos de funciones, rastrear , establecer condiciones previas y posteriores y sincronización , [33] pero se pueden usar para mucho más, incluida la eliminación de recursividad de cola , [34] memorización y incluso mejorando la escritura de otros decoradores. [35]

Los decoradores se pueden encadenar colocando varios en líneas adyacentes:

@invincible @favourite_colour ( "Azul" ) def  black_knight ():  pasar

es equivalente a

def  caballero_negro ():  pasar caballero_negro  =  invencible ( color_favorito ( "Azul" )( caballero_negro ))

o, utilizando variables intermedias

def  caballero_negro ():  pasar decorador_azul  =  color_favorito ( "Azul" ) decorado_por_azul  =  decorador_azul ( caballero_negro ) caballero_negro  =  invencible ( decorado_por_azul )

En el ejemplo anterior, la fábricafavourite_colour decoradora toma un argumento. Las fábricas de decoradores deben devolver un decorador, al que luego se llama con el objeto a decorar como argumento:

def  color_favorito ( color ):  def  decorador ( func ):  def  envoltorio ():  imprimir ( color )  func ()  devolver  envoltorio  devolver  decorador

Luego, esto decoraría la black_knightfunción de manera que el color, "Blue", se imprimiría antes de que black_knightse ejecute la función. El cierre garantiza que el argumento de color sea accesible para la función contenedora más interna incluso cuando se devuelve y sale del alcance, que es lo que permite a los decoradores trabajar.

A pesar del nombre, los decoradores de Python no son una implementación del patrón decorador . El patrón decorador es un patrón de diseño utilizado en lenguajes de programación orientados a objetos de tipo estático para permitir que se agregue funcionalidad a los objetos en tiempo de ejecución; Los decoradores de Python agregan funcionalidad a funciones y métodos en el momento de la definición y, por lo tanto, son una construcción de nivel superior que las clases de patrón decorador. El patrón decorador en sí es trivialmente implementable en Python, porque el lenguaje está escrito en pato y, por lo tanto, generalmente no se considera como tal. [ se necesita aclaración ]

huevos de Pascua

Los usuarios de lenguajes entre llaves , como C o Java , a veces esperan o desean que Python siga una convención delimitadora de bloques. La sintaxis de bloques delimitados por llaves ha sido solicitada repetidamente y rechazada constantemente por los desarrolladores principales. El intérprete de Python contiene un huevo de pascua que resume los sentimientos de sus desarrolladores sobre este tema. El código from __future__ import bracesgenera la excepción SyntaxError: not a chance. El __future__módulo normalmente se utiliza para proporcionar funciones de versiones futuras de Python.

Otro mensaje oculto, el Zen de Python (un resumen de la filosofía de diseño de Python ), se muestra al intentar import this.

El mensaje Hello world!se imprime cuando import __hello__se utiliza la declaración de importación. En Python 2.7, en lugar de Hello world!imprimir Hello world....

Al importar el antigravitymódulo, se abre un navegador web en xkcd comic 353 que muestra un uso ficticio humorístico de dicho módulo, con la intención de demostrar la facilidad con la que los módulos de Python permiten funciones adicionales. [36] En Python 3, este módulo también contiene una implementación del algoritmo "geohash", una referencia al cómic xkcd 426. [37]

Referencias

  1. ^ "La legibilidad cuenta". - PEP 20 - El Zen de Python Archivado el 5 de diciembre de 2014 en Wayback Machine.
  2. ^ "PEP 20 - El zen de Python". Fundación de software Python. 2004-08-23. Archivado desde el original el 3 de diciembre de 2008 . Consultado el 24 de noviembre de 2008 .
  3. ^ "2. Análisis léxico". Documentación de Python 3 . Fundación de software Python . Consultado el 11 de marzo de 2021 .
  4. ^ "2. Análisis léxico". Documentación de Python v2.7.18 . Fundación de software Python . Consultado el 11 de marzo de 2021 .
  5. ^ "Nuevas palabras clave". Documentación de Python v3.5 . Docs.python.org. Archivado desde el original el 18 de junio de 2016 . Consultado el 1 de junio de 2016 .
  6. ^ "2. Análisis léxico". Documentación de Python 3 . Fundación de software Python . Consultado el 22 de enero de 2022 .
  7. ^ "PEP 622 - Coincidencia de patrones estructurales". 2020-06-23 . Consultado el 22 de enero de 2022 .
  8. ^ "PEP 8 - Guía de estilo para código Python". Python.org . Consultado el 17 de marzo de 2021 .
  9. ^ Hoffa, Felipe (26 de julio de 2017). "400.000 repositorios de GitHub, mil millones de archivos, 14 terabytes de código: ¿espacios o pestañas?". Medio . Consultado el 11 de marzo de 2021 .
  10. ^ "Pestañas o espacios". ukupat.github.io . Consultado el 11 de marzo de 2021 .
  11. ^ "PEP 8 - Guía de estilo para código Python". Python.org . Consultado el 11 de marzo de 2021 .
  12. ^ "PEP 498 - Interpolación de cadenas literales". Novedades de Python 3.6 . 2016-12-23. Archivado desde el original el 30 de marzo de 2017 . Consultado el 29 de marzo de 2017 .
  13. ^ "2. Análisis léxico". Documentación de Python v2.7.5 . Docs.python.org. Archivado desde el original el 23 de octubre de 2012 . Consultado el 16 de agosto de 2013 .
  14. ^ "2. Análisis léxico". Documentación de Python v2.7.5 . Docs.python.org. Archivado desde el original el 23 de octubre de 2012 . Consultado el 16 de agosto de 2013 .
  15. ^ Los elementos hashable suelen ser inmutables, pero no necesariamente lo son por definición. Consulte python.org/3/glossary.htm
  16. ^ "6. Expresiones: documentación de Python 3.9.2". docs.python.org . Consultado el 17 de marzo de 2021 .
  17. ^ "Lanzamiento de Python 2.7.0". Archivado desde el original el 27 de enero de 2016 . Consultado el 19 de enero de 2016 .
  18. ^ "5. Estructuras de datos: documentación de Python 2.7.18". Archivado desde el original el 26 de enero de 2016 . Consultado el 19 de enero de 2016 .
  19. ^ "5. Estructuras de datos: documentación de Python 2.7.18". Archivado desde el original el 26 de enero de 2016 . Consultado el 19 de enero de 2016 .
  20. ^ David Mertz. "Programación funcional en Python". IBM DeveloperWorks. Archivado desde el original el 20 de febrero de 2007 . Consultado el 27 de agosto de 2007 .
  21. ^ "PEP 308 - Expresiones condicionales". Archivado desde el original el 13 de marzo de 2016 . Consultado el 14 de abril de 2016 .
  22. ^ La nonlocalpalabra clave fue adoptada por PEP 3104 Archivado el 2 de diciembre de 2014 en Wayback Machine.
  23. ^ "Guía de estilo de Python". docs.python-guide.org. Archivado desde el original el 9 de marzo de 2015 . Consultado el 8 de marzo de 2015 .
  24. ^ "PEP 343 - La" declaración "con". Archivado desde el original el 14 de diciembre de 2014 . Consultado el 15 de agosto de 2014 .
  25. ^ "Glosario: documentación de Python 3.9.2". docs.python.org . Consultado el 23 de marzo de 2021 .
  26. ^ EAFP Archivado el 26 de octubre de 2012 en Wayback Machine , Glosario de Python
  27. ^ Hamblen, Diane. "Sólo los límites de nuestra imaginación: una entrevista exclusiva con la RADM Grace M. Hopper". Revista de Tecnología de la Información del Departamento de la Marina. Archivado desde el original el 14 de enero de 2009 . Consultado el 31 de enero de 2007 .
  28. ^ ab Python en pocas palabras, Alex Martelli , p. 134
  29. ^ LBYL Archivado el 21 de enero de 2018 en Wayback Machine , Glosario de Python
  30. ^ Alex Martelli (19 de mayo de 2003). "EAFP contra LBYL". lista de correo de lista de Python. Archivado desde el original el 14 de julio de 2012 . Consultado el 18 de julio de 2011 .
  31. ^ "PEP 8 - Guía de estilo para código Python". Python.org . Consultado el 23 de marzo de 2021 .
  32. ^ ab "PEP 3107 - Anotaciones de funciones". Archivado desde el original el 6 de enero de 2015 . Consultado el 15 de agosto de 2014 .
  33. ^ "Decoradores de Python 2.4: reducción de la duplicación de código y consolidación del conocimiento". Dr. Dobb . 2005-05-01. Archivado desde el original el 6 de febrero de 2007 . Consultado el 8 de febrero de 2007 .
  34. ^ "Nuevo decorador de recursividad de cola". ASPN: Libro de cocina de Python . 2006-11-14. Archivado desde el original el 9 de febrero de 2007 . Consultado el 8 de febrero de 2007 .
  35. ^ "El módulo decorador". Archivado desde el original el 10 de febrero de 2007 . Consultado el 8 de febrero de 2007 .
  36. ^ cpython: el lenguaje de programación Python, Python, 15 de octubre de 2017, archivado desde el original el 15 de septiembre de 2017 , consultado el 15 de octubre de 2017
  37. ^ "Otro tesoro escondido. · python/cpython@b1614a7". GitHub . Consultado el 15 de octubre de 2017 .

enlaces externos


Error de cita: hay <ref group=note>etiquetas en esta página, pero las referencias no se mostrarán sin una {{reflist|group=note}}plantilla (consulte la página de ayuda ).