La sintaxis del lenguaje de programación Python es el conjunto de reglas que define 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 claras entre los lenguajes. Admite múltiples paradigmas de programación , incluida la programación estructurada y orientada a objetos y la programación funcional , y cuenta con un sistema de tipos dinámico y una gestión automática de la memoria.
La sintaxis de Python es simple y consistente, y se adhiere al principio de que "debe haber una (y preferiblemente solo una) manera obvia de hacerlo". El lenguaje incorpora estructuras y tipos de datos integrados, mecanismos de control de flujo, funciones de primera clase y módulos para una mejor reutilización y organización del código . Python también utiliza palabras clave en inglés donde otros lenguajes utilizan puntuación, lo que contribuye a su diseño visual despejado.
El lenguaje proporciona un manejo sólido de errores mediante excepciones e incluye un depurador en la biblioteca estándar para una resolución de problemas eficiente. La sintaxis de Python, diseñada para facilitar la lectura y el uso, lo convierte en una opción popular entre principiantes y profesionales por igual.
Python fue diseñado para ser un lenguaje muy legible . [1] Tiene un diseño visual relativamente despejado y utiliza palabras clave en inglés con frecuencia, mientras que otros lenguajes utilizan signos de puntuación . Python apunta a ser simple y consistente en el diseño de su sintaxis, encapsulado en el mantra "Debería haber una —y preferiblemente solo una— manera 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 ".
Python tiene 35 palabras clave o palabras reservadas ; no se pueden utilizar como identificadores . [3] [4]
and
as
assert
async
[nota 1]await
[nota 1]break
class
continue
def
del
elif
else
except
False
[nota 2]finally
for
from
global
if
import
in
is
lambda
None
nonlocal
[nota 3]not
or
pass
raise
return
True
[nota 2]try
while
with
yield
Además, Python también tiene 3 palabras clave blandas . A diferencia de las palabras clave duras habituales , las palabras clave blandas son palabras reservadas solo en los contextos limitados en los que interpretarlas como palabras clave tendría sentido sintáctico. Estas palabras se pueden usar como identificadores en otros lugares; puede definir una función o variable denominada match o case . [6] [7]
_
[nota 4]case
[nota 4]match
[nota 4]async
y await
se introdujeron en Python 3.5. [5]True
y False
se convirtieron en palabras clave en Python 3.0. Antes eran variables globales .nonlocal
se introdujo en Python 3.0.match
, case
y _
se introdujeron como palabras clave en Python 3.10.Python utiliza espacios en blanco para delimitar bloques de flujo de control (siguiendo la regla del lado opuesto ). 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 lenguajes denominados de "formato libre", que utilizan la estructura de bloques derivada de ALGOL , los bloques de código se separan con llaves ( { }
) o palabras clave. En la mayoría de las convenciones de codificación para estos lenguajes, los programadores suelen sangrar el código dentro de un bloque para diferenciarlo visualmente del código circundante.
Una función recursiva llamada , a la que se le pasa un único parámetro , , y si el parámetro es 0 llamará a una función diferente llamada y de lo contrario llamará a , pasando , y también se llamará a sí misma recursivamente, pasando como parámetro, podría implementarse de esta manera en Python:foo
x
bar
baz
x
x-1
def foo ( x ): si x == 0 : bar () de lo contrario : baz ( x ) foo ( x - 1 )
y podría escribirse así en C con el estilo de sangría K&R :
void foo ( int x ) { if ( x == 0 ) { bar (); } else { baz ( x ); foo ( x - 1 ); } }
Un código con sangría incorrecta podría ser malinterpretado por un lector humano de manera diferente a como lo sería interpretado por un compilador o intérprete. Por ejemplo, si la llamada de función foo(x - 1)
en la última línea del ejemplo anterior fue sangrada por error para que estuviera fuera del bloque if
/ :else
def foo ( x ): si x == 0 : bar () de lo contrario : baz ( x ) foo ( x - 1 )
Esto provocaría que la última línea se ejecute siempre, incluso cuando x
sea 0, lo que daría como resultado una recursión sin fin .
Si bien se aceptan los espacios y los caracteres de tabulación como formas de sangría y se puede usar cualquier múltiplo de espacios, se recomiendan los espacios [8] y se recomiendan 4 espacios (como en los ejemplos anteriores) y son, por lejos, los más utilizados. [9] [10] [ ¿ fuente poco confiable? ] Mezclar espacios y tabulaciones en líneas consecutivas no está permitido 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 los espacios y las tabulaciones.
Dado que Python es un lenguaje de tipado dinámico , los valores de Python, no las variables, son los que llevan la 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:
>>> alist = [ 'a' , 'b' , 'c' ] >>> def mi_función ( al ): ... al . append ( 'x' ) ... print ( al ) ... >>> mi_función ( alist ) [ 'a', 'b', 'c', 'x'] >>> alist [ 'a', 'b', 'c', 'x']
La función my_func
cambia el valor de alist
con el argumento formal al
, que es un alias de alist
. Sin embargo, cualquier intento de operar (asignar una nueva referencia de objeto a) en el alias en sí no tendrá ningún efecto en el objeto original. [ aclaración necesaria ]
>>> alist = [ 'a' , 'b' , 'c' ] >>> def my_func ( al ): ... # al.append('x') ... al = al + [ 'x' ] # se crea una nueva lista y se asigna a al, lo que significa que al ya no es un alias para alist ... print ( al ) ... >>> my_func ( alist ) ['a', 'b', 'c', 'x'] >>> print ( alist ) ['a', 'b', 'c']
En Python, los nombres accesibles que no son locales internos ni globales declarados son todos alias.
Entre los lenguajes de tipado dinámico, Python tiene una verificación de tipos moderada. La conversión implícita está definida para tipos numéricos (así como para booleanos ), por lo que se puede multiplicar de forma válida un número complejo por un 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.
Python tiene una amplia gama de tipos de datos básicos. Además de la aritmética convencional de números enteros y de punto 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 con cadenas 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 obligan a utilizar técnicas especiales en programas que modifican cadenas de forma intensiva, como unir matrices de caracteres en cadenas solo cuando es necesario.
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 manera que se pueda referenciar o indexar fácilmente . Las colecciones se presentan en dos formas básicas: secuencias y asignaciones .
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 (consulte a continuación). Las listas, por otro lado, son mutables; los elementos se pueden insertar, eliminar, modificar, agregar u ordenar en el lugar .
Por otro lado, las asignaciones son tipos (a menudo desordenados) implementados en forma de diccionarios que "asignan" un conjunto de claves inmutables a los elementos correspondientes (de forma muy similar a una función matemática). Por ejemplo, se podría definir un diccionario que tenga una cadena "toast"
asignada al entero 42
o viceversa. Las claves de un diccionario deben ser de un tipo Python inmutable, como un entero o una cadena, porque en el fondo se implementan a través de una función hash . Esto permite tiempos de búsqueda mucho más rápidos, pero requiere que las claves no cambien.
Los diccionarios son fundamentales para el funcionamiento interno de Python, ya que se encuentran en el núcleo de todos los objetos y clases: las asignaciones entre los nombres de las 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 de un __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 no indexada y desordenada que no contiene duplicados e implementa operaciones de teoría de conjuntos como unión , intersección , diferencia , diferencia simétrica y prueba de subconjuntos . Hay dos tipos de conjuntos: set
y frozenset
, la única diferencia es que set
es mutable y frozenset
es inmutable. Los elementos de un conjunto deben ser hashables. Así, por ejemplo, a frozenset
puede ser un elemento de a regular set
mientras que lo opuesto no es cierto.
Python también proporciona amplias capacidades de manipulación de colecciones, como verificación de contención incorporada y un protocolo de iteración genérico.
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 permite una introspección exhaustiva 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.
Python tiene varios tipos de literales de cadena .
Se pueden utilizar comillas simples o dobles para citar cadenas. A diferencia de los lenguajes de 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] ), utilizando el format
mé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 {} " . format ( num , impresora )) print ( "Acabo de imprimir {0} páginas en la impresora {1} " .format ( num , impresora )) print ( "Acabo de imprimir {num} páginas en la impresora {impresora} " . format ( 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 %(impresora)s " % { "num" : num , "impresora" : impresora })
son equivalentes a la declaración de Perl:
imprimir "Acabo de imprimir $num páginas en la impresora $printer\n"
Construyen una cadena utilizando las variables num
y printer
.
También hay cadenas de varias líneas, que comienzan y terminan con una serie de tres comillas simples o dobles y funcionan como aquí documentos en Perl y Ruby .
Un ejemplo simple con interpolación de variables (usando el format
método) es:
imprimir ( '''Estimado {destinatario} ,Deseo que te vayas de Sunnydale y nunca regreses.No es exactamente amor, {remitente} ''' . format ( remitente = "Buffy la cazavampiros" , destinatario = "Spike" ))
Finalmente, todos los tipos de cadenas mencionados anteriormente vienen en variedades " sin procesar " (indicadas colocando una r literal antes de la comilla de apertura), que no hacen interpolación de barra invertida y, por lo tanto, son muy útiles para expresiones regulares ; compare "@-quoting" en C# . Las cadenas sin procesar se incluyeron originalmente específicamente para expresiones regulares. Debido a las limitaciones del tokenizador, las cadenas sin procesar pueden no tener una barra invertida final. [13] La creación de una cadena sin procesar que contenga una ruta de Windows que termine con una barra invertida requiere alguna variedad de soluciones alternativas (comúnmente, usar barras diagonales en lugar de barras invertidas, ya que Windows acepta ambas).
Algunos ejemplos incluyen:
>>> # Una ruta de Windows, incluso las cadenas sin formato no pueden terminar en una barra invertida >>> r "C:\Foo\Bar\Baz \" Archivo "<stdin>" , línea 1 r "C:\Foo\Bar\Baz \" ^ SyntaxError : EOL mientras se escanea el literal de cadena >>> 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 ( ruta_dos ) >>> quoted_dos_path '"C:\\Foo\\Bar\\Baz\\ "'>>> # Una expresión regular que coincide con una cadena entre comillas con posible comillas de barra invertida >>> re . match ( r '"(([^" \\ ]| \\ .)*)"' , quoted_dos_path ) . group ( 1 ) . rstrip () 'C:\\Foo\\Bar\\Baz\\'>>> code = 'foo(2, bar)' >>> # Invertir los argumentos en una llamada de función de dos argumentos >>> re . sub ( r '\(([^,]*?),([^ ,]*?)\)' , r '(\2, \1)' , code ) 'foo(2, bar)' >>> # Tenga en cuenta que esto no funcionará si alguno de los argumentos tiene paréntesis o comas.
Se permiten literales de cadena (que posiblemente utilicen diferentes convenciones de comillas) que aparecen de forma contigua y solo separadas por espacios en blanco (incluidas las nuevas líneas) y se agregan en una única cadena más larga. [14] Por lo tanto,
título = "Una buena acción: " ' Una historia natural del destornillador y el tornillo'
es equivalente a
Título = "Una buena jugada: Una historia natural del destornillador y el tornillo"
Desde Python 3.0, el conjunto 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 )
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: los números enteros tradicionales de tamaño fijo y los números enteros "largos" de tamaño arbitrario. La conversión a números enteros "largos" se realizaba automáticamente cuando era necesario y, por lo tanto, el programador normalmente no tenía que estar al tanto de los dos tipos de números enteros. En las versiones más nuevas del lenguaje, la distinción ha desaparecido por completo y todos los números enteros se comportan como números enteros de longitud arbitraria.
Python admite números de punto flotante normales , que se crean cuando se utiliza un punto en un literal (por ejemplo, 1.1
), cuando se utilizan un número entero y un número de punto flotante en una expresión, o como resultado de algunas operaciones matemáticas ("división verdadera" a través del /
operador, o exponenciación con un exponente negativo).
Python también admite números complejos de forma nativa. Los números complejos se indican con el sufijo J
o , por ejemplo .j
3 + 4j
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
a_list = [ 1 , 2 , 3 , "un perro" ]
o utilizando la creación de objetos normal
una_segunda_lista = [ ] una_segunda_lista .append ( 4 ) una_segunda_lista .append ( 5 )
Las tuplas (clase tuple
) son secuencias inmutables de elementos de tipos arbitrarios. También existe una sintaxis especial para crear tuplas
a_tuple = 1 , 2 , 3 , "cuatro" a_tuple = ( 1 , 2 , 3 , "cuatro" )
Aunque las tuplas se crean separando los elementos con comas, la estructura completa suele estar entre paréntesis para facilitar su lectura. Una tupla vacía se denota con ()
, mientras que una tupla con un único valor se puede crear con (1,)
.
Los conjuntos (clase set
) son contenedores mutables de elementos que se pueden convertir en hashes [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 similares a los conjuntos matemáticos y admiten operaciones como la intersección y la unión de conjuntos . Python también cuenta con una frozenset
clase 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 del conjunto, la diferencia es la presencia de dos puntos. El literal vacío {}
genera un diccionario vacío en lugar de un conjunto vacío, que se crea mediante el constructor no literal: set()
.
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 / y
realiza una "división verdadera", lo que significa que siempre devuelve un punto flotante, incluso si x
y y
son números enteros que se dividen de manera uniforme.
>>> 4 / 2 2.0
y //
realiza una división entera o división de piso , devolviendo el piso del cociente como un entero.
En Python 2 (y la mayoría de los demás lenguajes de programación), a menos que se solicitara explícitamente, x / y
se realizaba una división de números enteros y se devolvía un valor de punto flotante solo si alguna de las entradas era un valor de punto flotante. Sin embargo, debido a que Python es un lenguaje de tipado dinámico, no siempre era 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.
Los operadores de comparación, es decir ==
, !=
, <
, >
, , <=
, >=
, is
, is not
, in
y not in
[16] se utilizan en todo tipo de valores. Se pueden comparar números, cadenas, secuencias y asignaciones. En Python 3, los tipos dispares (como a str
y an int
) no tienen un orden relativo consistente, y los intentos de comparar estos tipos generan una TypeError
excepción. Si bien era posible comparar tipos dispares en Python 2 (por ejemplo, si una cadena era mayor o menor que un entero), el orden no estaba definido; esto se consideró una peculiaridad de diseño histórica y finalmente se eliminó en Python 3.
Las expresiones de comparación encadenadas, como a < b < c
tienen aproximadamente el mismo 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 semántica de cortocircuito , lo que significa que se garantiza que la evaluación se detendrá tan pronto como un veredicto sea claro: si a < b
es falso, c
nunca se evalúa porque la expresión ya no puede ser verdadera.
Para expresiones sin efectos secundarios, a < b < c
es equivalente a a < b and b < c
. Sin embargo, existe una diferencia sustancial cuando las expresiones tienen efectos secundarios. a < f(x) < b
se evaluará f(x)
exactamente una vez, mientras que a < f(x) and f(x) < b
se evaluará dos veces si el valor de a
es menor que f(x)
y una vez en caso contrario.
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 o distintos de cero como verdaderos. Los valores booleanos True
y False
se agregaron al lenguaje en Python 2.2.1 como constantes (subclasificadas de 1
y 0
) y se cambiaron para que sean palabras clave completas en Python 3. Los operadores de comparación binaria como ==
y >
devuelven True
o False
.
Los operadores booleanos and
y or
utilizan una evaluación mínima . Por ejemplo, y == 0 or x/y > 100
nunca generarán una excepción de división por cero. Estos operadores devuelven el valor del último operando evaluado, en lugar de True
o False
. Por lo tanto, la expresión (4 and 5)
se evalúa como 5
, y (4 or 5)
se evalúa como 4
.
Como se mencionó anteriormente, otra fortaleza de Python es la disponibilidad de un estilo de programación funcional . Como es de esperar, esto hace que trabajar con listas y otras colecciones sea mucho más sencillo.
Una de estas construcciones es la comprensión de listas , que puede expresarse con el siguiente formato:
L = [ expresión_de_mapeo para el elemento en la lista_de_origen si expresión_de_filtro ]
Usando la comprensión de listas para calcular las primeras cinco potencias de dos:
potencias_de_dos = [ 2 ** n para n en el rango ( 1 , 6 )]
El algoritmo Quicksort se puede expresar de manera elegante (aunque ineficiente) utilizando listas por comprensión:
def qsort ( L ): si L == []: return [] pivot = L [ 0 ] return ( qsort ([ x para x en L [ 1 :] si x < pivot ]) + [ pivot ] + qsort ([ x para x en L [ 1 :] si x >= pivot ]))
Python 2.7+ [17] también admite comprensiones de conjuntos [18] y comprensiones de diccionarios. [19]
En Python, las funciones son objetos de primera clase que se pueden crear y pasar dinámicamente.
El soporte limitado de Python para funciones anónimas es la lambda
construcció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 todavía se puede implementar de forma menos elegante dentro de lambda mediante el uso de cortocircuitos, [20] y de forma más idiomática con expresiones condicionales. [21]
Python admite cierres léxicos desde la versión 2.2. A continuación, se muestra un ejemplo de función que devuelve una función que se aproxima a la derivada de la función dada:
def derived ( 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. " "" def function ( x ): return ( f ( x + dx ) -f ( x )) / dx return function
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 las variables en Python está determinado implícitamente por el alcance en el que se asigna un valor a la variable, a menos que el alcance se declare explícitamente con global
o nonlocal
. [22]
Tenga en cuenta que la vinculación del cierre de un nombre a un valor no es mutable desde dentro de la función. Dado:
>>> def foo ( a , b ): ... imprimir ( f'a : { a } ) ... imprimir ( f'b : { b } ) ... def bar ( c ) : ... b = c ... imprimir ( f'b *: { b } ) ... bar ( a ) ... imprimir ( f'b : { b } ) ... >>> foo ( 1,2 ) a :1 b : 2 b *:1 b : 2
y puedes ver que b
, como es visible desde el alcance del cierre, conserva el valor que tenía; el enlace modificado de b
dentro de la función interna no se propagó hacia afuera. La forma de evitar esto es usar una nonlocal b
declaración en bar
. En Python 2 (que carece nonlocal
de ), la solución alternativa habitual es usar un valor mutable y cambiar ese valor, no el enlace. Por ejemplo, una lista con un elemento.
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 perezosa de una función que de otro modo devolvería una lista con un uso prohibitivo del espacio o con un uso intensivo del cálculo.
Este es un ejemplo para generar de forma perezosa los números primos:
desde itertools importa el recuentodef generate_primes ( stop_at = None ): primes = [] para n en count ( start = 2 ): si stop_at no es None y n > stop_at : return # lanza la excepción StopIteration composite = False para p en primes : si no es n % p : composite = True break elif p ** 2 > n : break si no es composite : primes.append ( n ) yield n
Al llamar a esta función, el valor devuelto se puede iterar como si fuera una lista:
para i en generate_primes ( 100 ): # iterar sobre los primos entre 0 y 100 print ( i )para i en generate_primes (): # iterar sobre TODOS los primos indefinidamente print ( i )
La definición de un generador parece idéntica a la de una función, excepto que yield
se utiliza 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. Una llamada a un generador se puede utilizar en lugar de una lista u otra estructura cuyos elementos se iterarán. Siempre que el for
bucle del ejemplo requiere el siguiente elemento, se llama al generador y se obtiene el siguiente elemento.
Los generadores no tienen por qué ser infinitos, como en el ejemplo anterior de los números primos. Cuando un generador finaliza, se genera una excepción interna que indica a cualquier contexto de llamada que ya no hay más valores. for
A continuación, finalizará un bucle u otra iteración.
Introducidas en Python 2.4, las expresiones generadoras son el equivalente de evaluación diferida de las comprensiones de listas. Si utilizamos el generador de números primos proporcionado en la sección anterior, podríamos definir una colección diferida, pero no infinita.
desde itertools importar isliceprimos_menos_del_millón = ( i para i en generate_primes () si i < 1000000 ) dos_milésimo_primo = islice ( primos_menos_del_millón , 1999 , 2000 ) . next ()
La mayor parte de la memoria y el tiempo necesarios para generar esta cantidad de números primos no se utilizarán hasta que se acceda realmente al elemento necesario. Lamentablemente, no se puede realizar una indexación y segmentación sencilla de los generadores, sino que se debe utilizar el módulo itertools o crear bucles propios. Por el contrario, una comprensión de listas es funcionalmente equivalente, pero es voraz a la hora de realizar todo el trabajo:
primos_menos_del_millón = [ i para i en generar_primos ( 2000000 ) si i < 1000000 ] dos_milésimo_primo = primos_menos_del_millón [ 1999 ]
La comprensión de listas creará inmediatamente una lista grande (con 78498 elementos, en el ejemplo, pero creando transitoriamente una lista de números primos menores a dos millones), incluso si nunca se accede a la mayoría de los elementos. La comprensión de generadores es más parsimoniosa.
Si bien las listas y los generadores tenían comprensiones/expresiones, en versiones de Python anteriores a la 2.7 los otros tipos de colecciones integradas de Python (dictados y conjuntos) debían modificarse mediante 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 al introducir comprensiones de diccionarios y conjuntos, similares a las comprensiones de listas:
>>> [ n * n para n en rango ( 5 )] # comprensión de lista regular [ 0 , 1 , 4 , 9 , 16 ] >>> >>> { n * n para n en rango ( 5 )} # comprensión de conjunto { 0 , 1 , 4 , 9 , 16 } >>> >>> { n : n * n para n en rango ( 5 )} # comprensión de diccionario { 0 : 0 , 1 : 1 , 2 : 4 , 3 : 9 , 4 : 16 }
Python admite la mayoría de las técnicas de programación orientada a objetos (OOP). Permite el polimorfismo , no solo dentro de una jerarquía de clases sino también mediante tipado de pato . Cualquier objeto puede usarse para cualquier tipo, y funcionará siempre que tenga los métodos y atributos adecuados. Y todo en Python es un objeto, incluidas las 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 las variables privadas mediante la manipulación de nombres , que rara vez se usa en la práctica, ya que el ocultamiento de información es visto por algunos como poco pitónico , 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 sucede 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 de 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 un comportamiento de programación orientada a objetos . Además, siempre es posible redefinir la clase utilizando propiedades (ver Propiedades) de modo que cuando se establece o recupera una determinada variable en el código de llamada, en realidad invoca una llamada de función, de modo que spam.eggs = toast
podría realmente invocar spam.set_eggs(toast)
. Esto anula la ventaja práctica de las funciones de acceso y sigue siendo orientada a objetos porque la propiedad eggs
se 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 las clases de "nuevo estilo". Con las clases de nuevo estilo, se unificaron los objetos y los tipos, lo que permitió la subclasificación de tipos. Incluso se pueden definir tipos completamente nuevos, con un comportamiento personalizado para los operadores infijos. Esto permite realizar muchas cosas radicales sintácticamente dentro de Python. También se adoptó un nuevo orden de resolución de métodos para la 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.
La with
declaración maneja recursos y permite a los usuarios trabajar con el protocolo Context Manager. [24]__enter__()
Se llama a una función ( ) al ingresar al ámbito 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 Context Managers se usan a menudo con archivos, conexiones de bases de datos, casos de prueba, etc.
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 = value
Una clase que define uno o más de los tres métodos especiales __get__(self, instance, owner)
, __set__(self, instance, value)
, __delete__(self, instance)
se puede utilizar como descriptor. La creación de una instancia de un descriptor como miembro de una segunda clase hace que la instancia sea una propiedad de la segunda clase. [25]
Python permite la creación de métodos de clase y métodos estáticos mediante el uso de los decoradores @classmethod
y @staticmethod
. El 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.
Python admite (y utiliza ampliamente) el manejo de excepciones como un medio para probar condiciones de error y otros eventos "excepcionales" en un programa.
El estilo de 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, lo habitual en Python es simplemente intentar usarlo y capturar 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 salirse 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 una alternativa al if
bloque -, especialmente en situaciones con subprocesos . Un lema que se invoca con frecuencia 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:
si hasattr ( spam , 'huevos' ): jamón = spam.huevos de lo contrario : handle_missing_attr ( )
Esta segunda muestra sigue el paradigma EAFP:
Intente : jamón = spam.huevos excepto AttributeError : handle_missing_attr ( )
Estos dos ejemplos de código tienen el mismo efecto, aunque habrá diferencias de rendimiento. Cuando spam
tiene el atributo eggs
, la muestra de EAFP se ejecutará más rápido. Cuando spam
no tiene el atributo eggs
(el caso "excepcional"), la muestra de 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 de 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 el tipado de pato . Una desventaja de EAFP es que solo se puede utilizar con declaraciones; no se puede capturar una excepción en una expresión de generador, comprensión de lista o función lambda.
Python tiene dos formas de anotar el código. Una es mediante comentarios para indicar qué hace alguna parte del código. Los comentarios de una sola línea comienzan con el carácter numeral ( #
) 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:
importar sistemadef getline ( ) : return sys.stdin.readline () # Obtener una línea y devolverla
Comentar un fragmento de código con varias líneas:
def getline (): """Esta función obtiene una línea y la devuelve. A modo de demostración, esta es una cadena de documentación de varias líneas. Se puede acceder a esta cadena completa como getline.__doc__. """ return sys . stdin . readline ()
Las cadenas de documentación ( docstrings ), es decir, cadenas que se encuentran solas sin asignación como la primera línea sangrada dentro de un módulo, clase, método o función, establecen automáticamente su contenido como un atributo llamado __doc__
, que tiene como objetivo almacenar una descripción legible por humanos del propósito, comportamiento y uso del objeto. La función incorporada help
genera 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 para el lenguaje especifica que se prefieren las comillas dobles triples ( """
) tanto para cadenas de documentación de una sola línea como para cadenas de 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 . stdin . readline ()
Cadena de documentación de varias líneas:
def getline (): """Obtener una línea de stdin y devolverla. """ return sys . stdin . readline ()
Las cadenas de documentación pueden ser tan largas como desee el programador 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 Python ejecuta. Esto 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 brindarles a otros programadores información sobre cómo invocar el objeto que se documenta en la cadena de documentación.
Existen herramientas 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 las cadenas de documentación 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 documentación para crear pruebas, mientras que el módulo docopt las usa para definir opciones de línea de comandos.
Las anotaciones de funciones (tips) se definen en PEP 3107. [32] Permiten adjuntar datos a los argumentos y al retorno de una función. El comportamiento de las anotaciones no está definido por el lenguaje y se deja en manos de marcos de trabajo de terceros. Por ejemplo, se podría escribir una biblioteca para manejar tipado estático: [32]
def haul ( elemento : Haulable , * vargs : PackAnimal ) -> Distancia
Un decorador es cualquier objeto Python invocable que se utiliza para modificar una definición de función, método o 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 pura sintaxis simple , utilizando @
como palabra clave:
@viking_chorus def menu_item (): imprimir ( "spam" )
es equivalente a
def elemento_de_menu (): print ( "spam" ) elemento_de_menu = viking_chorus ( elemento_de_menu )
Los decoradores son una forma de metaprogramación ; mejoran la acción de la función o el método que decoran. Por ejemplo, en el ejemplo siguiente, viking_chorus
might cause menu_item
to be run 8 times (see Spam sketch) for every time it is called: (podría hacer que se ejecute 8 veces (consulte el esquema de Spam ) cada vez que se lo llama:)
def viking_chorus ( myfunc ): def función_interna ( * args , ** kwargs ): para i en rango ( 8 ): myfunc ( * args , ** kwargs ) return función_interna
Los usos canónicos de los decoradores de funciones son para crear métodos de clase o métodos estáticos , agregar atributos de función, rastrear , establecer condiciones previas y posteriores y sincronizar , [33] pero se pueden usar para mucho más, incluida la eliminación de la recursión de cola , [34] la memorización e incluso mejorar 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 (): pass caballero_negro = invencible ( color_favorito ( "Azul" )( caballero_negro ))
o bien, utilizando variables intermedias
def caballero_negro (): pass decorador_azul = color_favorito ( "Azul" ) decorador_por_azul = decorador_azul ( caballero_negro ) decorador_por_azul = invencible ( decorado_por_azul )
En el ejemplo anterior, la fábricafavourite_colour
de decoradores toma un argumento. Las fábricas de decoradores deben devolver un decorador, que luego se llama con el objeto que se va a decorar como argumento:
def favourite_colour ( color ): def decorador ( func ): def wrapper (): print ( color ) func () return wrapper return decorador
Esto decoraría la black_knight
función de modo que el color, "Blue"
, se imprima antes de que black_knight
se 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 ámbito, que es lo que permite que los decoradores funcionen.
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 tipado estático para permitir que se añada funcionalidad a los objetos en tiempo de ejecución; los decoradores de Python añaden funcionalidad a las funciones y métodos en el momento de la definición y, por lo tanto, son una construcción de nivel superior a las clases de patrón decorador. El patrón decorador en sí mismo es trivialmente implementable en Python, porque el lenguaje es de tipado pato y, por lo tanto, no suele considerarse como tal. [ aclaración necesaria ]
Los usuarios de lenguajes con llaves , como C o Java , a veces esperan o desean que Python siga una convención de delimitadores de bloques. La sintaxis de bloques delimitados por llaves ha sido solicitada repetidamente y rechazada sistemáticamente 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 braces
lanza la excepción SyntaxError: not a chance
. El __future__
módulo se utiliza normalmente para proporcionar funciones de futuras versiones 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 se imprime cuando se utiliza Hello world!
la declaración de importación . En Python 2.7, en lugar de , se imprime .import __hello__
Hello world!
Hello world...
Al importar el antigravity
módulo, se abre un navegador web en el cómic 353 de xkcd , que muestra un uso ficticio y humorístico de dicho módulo, con el fin de demostrar la facilidad con la que los módulos de Python permiten una funcionalidad adicional. [36] En Python 3, este módulo también contiene una implementación del algoritmo "geohash", una referencia al cómic 426 de xkcd . [37]
nonlocal
palabra clave fue adoptada por PEP 3104 Archivado el 2 de diciembre de 2014 en Wayback Machine.