stringtranslate.com

Sintaxis y semántica de Python

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

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 resolver problemas de manera eficiente. La sintaxis de Python, diseñada para facilitar su lectura y uso, lo convierte en una opción popular tanto entre principiantes como profesionales.

Filosofía de diseño

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

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

Notas
  1. ^ ab asyncy awaitse introdujeron en Python 3.5. [5]
  2. ^ ab Truey Falsese convirtieron en palabras clave en Python 3.0. Antes eran variables globales .
  3. ^ nonlocal se introdujo en Python 3.0.
  4. ^ abc match, casey _se introdujeron como palabras clave en Python 3.10.

Sangría

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:fooxbarbazxx-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 xsea 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.

Estructuras de datos

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

Tipos de base

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.

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 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 42o 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: sety frozenset, la única diferencia es que setes mutable y frozensetes inmutable. Los elementos de un conjunto deben ser hashables. Así, por ejemplo, a frozensetpuede ser un elemento de a regular setmientras 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.

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

Literales

Instrumentos de cuerda

Python tiene varios tipos de literales de cadena .

Literales de cadena normales

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 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 {} " . 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 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 aquí documentos en Perl y Ruby .

Un ejemplo simple con interpolación de variables (usando el formatmé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" ))

Cuerdas crudas

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.

Concatenación de literales de cadena adyacentes

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  =  "Un buen giro: " ' Una historia natural del destornillador y el tornillo'

es equivalente a

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

Unicode

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 )

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: 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 Jo , por ejemplo .j3 + 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

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

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 punto flotante, incluso si xy yson 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 / yse 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.

Operadores de comparación

Los operadores de comparación, es decir ==, !=, <, >, , <=, >=, is, is not, iny 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 stry an int) no tienen un orden relativo consistente, y los intentos de comparar estos tipos generan una TypeErrorexcepció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 < ctienen 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 < bes falso, cnunca se evalúa porque la expresión ya no puede ser verdadera.

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

Operadores lógicos

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 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án 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 5, y (4 or 5)se evalúa como 4.

Programación funcional

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.

Comprensiones

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]

Funciones de primera clase

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

Cierres

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 no se admiten los cierres. 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 globalo 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 bdentro de la función interna no se propagó hacia afuera. La forma de evitar esto es usar una nonlocal bdeclaración en bar. En Python 2 (que carece nonlocalde ), la solución alternativa habitual es usar 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 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 yieldse 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 forbucle 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. forA continuación, finalizará 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 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.

Diccionario y comprensión de conjuntos

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 }

Objetos

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 "interrumpir 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 = toastpodrí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 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 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.

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

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

Descriptores

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]

Clases y métodos estáticos

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.

Excepciones

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 ifbloque -, 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 spamtiene el atributo eggs, la muestra de EAFP se ejecutará más rápido. Cuando spamno 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.

Comentarios y cadenas de documentación

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 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 para el lenguaje especifica que se prefieren las comillas dobles triples ( """) tanto para cadenas de documentación de una sola línea como para las 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 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 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.

Anotaciones de funciones

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

Decoradores

Un decorador es cualquier objeto Python que se pueda llamar y que se utilice 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_chorusmight cause menu_itemse 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 ():  pasar 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_knightfunción de modo que el color, "Blue", se imprima 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 á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 ]

Huevos de Pascua

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 braceslanza 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 antigravitymódulo, se abre un navegador web en el cómic xkcd 353, 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 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". Python Software Foundation. 23 de agosto de 2004. 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 . Python Software Foundation . Consultado el 11 de marzo de 2021 .
  4. ^ "2. Lexical analysis". Python v2.7.18 documentation. Python Software Foundation. Retrieved 2021-03-11.
  5. ^ "New Keywords". Python v3.5 documentation. Docs.python.org. Archived from the original on 2016-06-18. Retrieved 2016-06-01.
  6. ^ "2. Lexical analysis". Python 3 documentation. Python Software Foundation. Retrieved 2022-01-22.
  7. ^ "PEP 622 -- Structural Pattern Matching". 2020-06-23. Retrieved 2022-01-22.
  8. ^ "PEP 8 -- Style Guide for Python Code". Python.org. Retrieved 2021-03-17.
  9. ^ Hoffa, Felipe (2017-07-26). "400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?". Medium. Retrieved 2021-03-11.
  10. ^ "Tabs or Spaces". ukupat.github.io. Retrieved 2021-03-11.
  11. ^ "PEP 8 -- Style Guide for Python Code". Python.org. Retrieved 2021-03-11.
  12. ^ "PEP 498 - Literal String Interpolation". What’s New In Python 3.6. 2016-12-23. Archived from the original on 2017-03-30. Retrieved 2017-03-29.
  13. ^ "2. Lexical analysis". Python v2.7.5 documentation. Docs.python.org. Archived from the original on 2012-10-23. Retrieved 2013-08-16.
  14. ^ "2. Lexical analysis". Python v2.7.5 documentation. Docs.python.org. Archived from the original on 2012-10-23. Retrieved 2013-08-16.
  15. ^ Hashable items are usually immutable, but not necessarily so by definition. See python.org/3/glossary.htm
  16. ^ "6. Expressions — Python 3.9.2 documentation". docs.python.org. Retrieved 2021-03-17.
  17. ^ "Python 2.7.0 Release". Archived from the original on 2016-01-27. Retrieved 2016-01-19.
  18. ^ "5. Data Structures — Python 2.7.18 documentation". Archived from the original on 2016-01-26. Retrieved 2016-01-19.
  19. ^ "5. Data Structures — Python 2.7.18 documentation". Archived from the original on 2016-01-26. Retrieved 2016-01-19.
  20. ^ David Mertz. "Functional Programming in Python". IBM developerWorks. Archived from the original on 2007-02-20. Retrieved 2007-08-27.
  21. ^ "PEP 308 -- Conditional Expressions". Archived from the original on 2016-03-13. Retrieved 2016-04-14.
  22. ^ The nonlocal keyword was adopted by PEP 3104 Archived 2014-12-02 at the 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ág. 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 v. LBYL". Lista de correo python-list. 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 de conocimientos". Dr. Dobb's . 2005-05-01. Archivado desde el original el 2007-02-06 . Consultado el 2007-02-08 .
  34. ^ "Nuevo decorador de recursión de cola". ASPN: Libro de recetas de Python . 2006-11-14. Archivado desde el original el 2007-02-09 . Consultado el 2007-02-08 .
  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, 2017-10-15, archivado desde el original el 2017-09-15 , consultado el 2017-10-15
  37. ^ "Otro tesoro escondido. · python/cpython@b1614a7". GitHub . Consultado el 15 de octubre de 2017 .

Enlaces externos