Funciones integradas de Python: una exploración completa
Python tiene muchas funciones integradas que puedes usar directamente sin importar nada. Estas funciones cubren una amplia variedad de tareas de programación comunes que incluyen realizar operaciones matemáticas, trabajar con tipos de datos integrados, procesar iterables de datos, manejar entradas y salidas en sus programas, trabajar con ámbitos y más.
En este tutorial podrás:
- Conozca las funciones integradas de Python
- Conozca los casos de uso comunes de las funciones integradas de Python
- Utilice estas funciones para resolver problemas prácticos
Para aprovechar al máximo este tutorial, deberá estar familiarizado con la programación de Python, incluidos temas como trabajar con tipos de datos integrados, funciones, clases, decoradores, ámbitos y el sistema de importación.
Funciones integradas en Python
Python tiene varias funciones disponibles para que las use directamente desde cualquier parte de su código. Estas funciones se conocen como funciones integradas y cubren muchos problemas de programación comunes, desde cálculos matemáticos hasta características específicas de Python.
Nota: Muchas de las funciones integradas de Python son clases con nombres de estilo de función. Buenos ejemplos son str
, tuple
, list
y dict
, que son clases que definen tipos de datos integrados. . Estas clases se enumeran en la documentación de Python como funciones integradas y las encontrará en este tutorial.
En este tutorial, aprenderá los conceptos básicos de las funciones integradas de Python. Al final, sabrá cuáles son sus casos de uso y cómo funcionan. Para comenzar, comenzará con las funciones integradas relacionadas con los cálculos matemáticos.
Uso de funciones integradas relacionadas con las matemáticas
En Python, encontrará algunas funciones integradas que se encargan de operaciones matemáticas comunes, como calcular el valor absoluto de un número, calcular potencias y más. Aquí hay un resumen de las funciones integradas relacionadas con las matemáticas en Python:
abs()
Calcula el valor absoluto de un número.
divmod()
Calcula el cociente y el resto de una división entera.
max()
Encuentra el mayor de los argumentos o elementos dados en un iterable
min()
Encuentra el más pequeño de los argumentos o elementos dados en un iterable
pow()
Eleva un número a una potencia
round()
Redondea un valor de punto flotante
sum()
Suma los valores en un iterable.
En las siguientes secciones, aprenderá cómo funcionan estas funciones y cómo usarlas en su código Python.
Obtener el valor absoluto de un número: abs()
El valor absoluto o módulo de un número real es su valor no negativo. En otras palabras, el valor absoluto es el número sin su signo. Por ejemplo, el valor absoluto de -5 es 5 y el valor absoluto de 5 también es 5.
Nota: Para obtener más información sobre abs()
, consulta el tutorial Cómo encontrar un valor absoluto en Python.
La función abs()
incorporada de Python le permite calcular rápidamente el valor absoluto o módulo de un número:
>>> from decimal import Decimal
>>> from fractions import Fraction
>>> abs(-42)
42
>>> abs(42)
42
>>> abs(-42.42)
42.42
>>> abs(42.42)
42.42
>>> abs(complex("-2+3j"))
3.605551275463989
>>> abs(complex("2+3j"))
3.605551275463989
>>> abs(Fraction("-1/2"))
Fraction(1, 2)
>>> abs(Fraction("1/2"))
Fraction(1, 2)
>>> abs(Decimal("-0.5"))
Decimal('0.5')
>>> abs(Decimal("0.5"))
Decimal('0.5')
En estos ejemplos, calcula el valor absoluto de diferentes tipos numéricos utilizando la función abs()
. Primero, se utilizan números enteros, luego números de punto flotante y complejos y, finalmente, números fraccionarios y decimales. En todos los casos, cuando llamas a la función con un valor negativo, el resultado final elimina el signo.
Como ejemplo práctico, supongamos que necesita calcular las ganancias y pérdidas totales de su empresa a partir de las transacciones de un mes:
>>> transactions = [-200, 300, -100, 500]
>>> incomes = sum(income for income in transactions if income > 0)
>>> expenses = abs(
... sum(expense for expense in transactions if expense < 0)
... )
>>> print(f"Total incomes: ${incomes}")
Total incomes: $800
>>> print(f"Total expenses: ${expenses}")
Total expenses: $300
>>> print(f"Total profit: ${incomes - expenses}")
Total profit: $500
En este ejemplo, para calcular los gastos, utiliza la función abs()
para obtener el valor absoluto de los gastos, lo que da como resultado un valor positivo.
Encontrar el cociente y el resto en la división: divmod()
Python proporciona una función incorporada llamada divmod()
que toma dos números como argumentos y devuelve una tupla con el cociente y el resto que resultan de la división entera de los números de entrada:
>>> divmod(8, 4)
(2, 0)
>>> divmod(6.5, 3.5)
(1.0, 3.0)
Con números enteros como argumentos, el resultado es el mismo que (a/b, a % b)
. Con números de punto flotante, el resultado es (q, a % b)
, donde q
suele ser math.floor(a/b)
, pero puede ser 1
menor que eso.
Como ejemplo práctico de cuándo usar esta función, digamos que desea codificar una función que toma un valor de tiempo en milisegundos y devuelve una cadena con el formato "00:00:00"
. Aquí hay una posible implementación usando la función divmod()
:
>>> def hh_mm_ss(milliseconds):
... seconds = round(milliseconds / 1000)
... minutes, seconds = divmod(seconds, 60)
... hours, minutes = divmod(minutes, 60)
... return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
...
>>> hh_mm_ss(10000)
'00:00:10'
>>> hh_mm_ss(68000)
'00:01:08'
>>> hh_mm_ss(3680000)
'01:01:20'
En esta función, primero convierte los milisegundos de entrada a segundos y redondea el resultado al número entero más cercano.
Luego, usas divmod()
para dividir el total de segundos entre 60 porque hay 60 segundos en un minuto. Este cálculo le proporciona los minutos y los segundos restantes. Finalmente, usas divmod()
nuevamente para dividir los minutos entre 60 porque hay 60 minutos en una hora. Esta vez, obtienes las horas y los minutos restantes.
Encontrar valores mínimos y máximos: min()
y max()
A veces, es necesario encontrar los valores menor y mayor en un iterable o en una serie de valores. Estos pueden ser cálculos comunes en programación y Python tiene funciones integradas para ellos.
Nota: Para obtener más información sobre las funciones min()
y max()
, consulte el código min()
de Python. > y max()
: tutorial sobre búsqueda de valores más pequeños y más grandes.
La función min()
le permite encontrar el valor mínimo en un iterable, mientras que la función max()
le ayuda a encontrar el valor máximo. Aquí está la firma de ambas funciones:
min(iterable, *[, default, key])
max(iterable, *[, default, key])
Ambas funciones toman un argumento requerido llamado iterable
y devuelven los valores mínimo y máximo, respectivamente. También toman dos argumentos opcionales de solo palabras clave:
default
Puede contener el valor que desea devolver si la entrada iterable está vacía
key
Acepta una función de un solo argumento para personalizar los criterios de comparación.
A continuación se muestran algunos ejemplos rápidos de cómo utilizar las funciones min()
y max()
con diferentes conjuntos de argumentos:
>>> min([1, 2, 3, 4])
1
>>> max([1, 2, 3, 4])
4
>>> min(1, 2, 3, 4)
1
>>> max(1, 2, 3, 4)
4
>>> min([], default=0)
0
>>> max([], default=0)
0
>>> min([-2, 3, 4, -5, 1], key=abs)
1
>>> max([-2, 3, 4, -5, 1], key=abs)
-5
En los dos primeros ejemplos, utiliza min()
y max()
con una lista de números. También puedes utilizar estas funciones con una serie de argumentos posicionales.
Luego, tiene dos ejemplos del uso del argumento default
para devolver un valor adecuado cuando la entrada iterable está vacía. Finalmente, tienes dos ejemplos del uso del argumento key
. En estos ejemplos, utiliza la función abs()
para proporcionar los criterios de comparación.
Poderes informáticos: pow()
Cuando necesite calcular potencias en su código, puede utilizar la función incorporada pow()
. Esta función toma un número y lo eleva a una potencia determinada. Aquí está la firma de la función:
pow(base, exp[, mod=None])
Cuando llamas a pow()
, obtienes base
elevado a la potencia de exp
. Con estos dos argumentos, pow()
es equivalente a algo como base**exp
:
>>> pow(2, 8)
256
>>> 2**8
256
Esta operación calcula 2
elevado a 8
, que es 256
. Esto es equivalente a una operación poderosa con el operador **
, que encontrará con mayor frecuencia en el código del mundo real.
El argumento mod
le permite hacer algo como pow(base, exp) % mod
pero calculado de manera más eficiente:
>>> import timeit
>>> base = 2
>>> exp = 1000000
>>> mod = 1000000
>>> timeit.timeit(
... "pow(base, exp, mod)", globals=globals(), number=10
... ) * 1000
0.021042011212557554
>>> timeit.timeit(
... "pow(base, exp) % mod", globals=globals(), number=10
... ) * 1000
61.956208024639636
En este ejemplo, utiliza la función timeit()
del módulo timeit
para medir la velocidad de cálculo. Luego, define algunas variables para realizar el cálculo. En la primera llamada a timeit()
, utiliza el argumento mod
. En la segunda llamada, utiliza el operador de módulo (%
).
Cuando comparas el consumo de tiempo resultante, puedes concluir que usar el argumento mod
es mucho más rápido que calcular la potencia y luego aplicar el operador de módulo como en pow(base, exp) % mod
.
Redondeo de números: round()
La función round()
incorporada de Python toma un argumento numérico y lo devuelve redondeado a un número determinado de dígitos.
Nota: Para obtener más información sobre el redondeo de números y la función round()
, consulte el tutorial Cómo redondear números en Python.
La firma de round()
se muestra en el siguiente código:
round(number[, ndigits])
En esta firma, number
suele ser un número de punto flotante, mientras que ndigits
es un argumento opcional que debe ser un número entero. Este último argumento definirá la precisión o el número de dígitos después del punto decimal.
A continuación se muestran algunos ejemplos:
>>> from math import pi
>>> pi
3.141592653589793
>>> round(pi, 2)
3.14
>>> round(pi, 4)
3.1416
>>> round(pi, 6)
3.141593
En estos ejemplos, utiliza la constante pi
del módulo matemático y la función round()
para expresar el número con diferente precisión.
Cuando usas round()
con un solo argumento, puedes obtener resultados sorprendentes:
>>> round(1.5)
2
>>> round(2.5)
2
En estos dos ejemplos, la función round()
redondea 1,5
hasta 2
y 2,5
hacia abajo hasta 2
. Esto se debe a que round()
redondea al múltiplo más cercano de 10
a la potencia menos ndigits
. Si dos múltiplos son igualmente cercanos, el redondeo se realiza hacia la opción par. Esta estrategia de redondear de mitad a par ayuda a mitigar el sesgo de redondeo. Es por eso que 2.5
se redondea a 2
en lugar de 3
.
Calcular totales: sum()
La función sum()
incorporada de Python proporciona una forma pitónica eficiente de sumar una lista de valores numéricos, que también es un paso intermedio común en muchos cálculos. Entonces sum()
es una herramienta bastante útil para un programador de Python.
Nota: Para profundizar en cómo usar sum()
, consulta el tutorial sum()
de Python: The Pythonic Way to Sum Values.
La función sum()
le permite sumar una serie de valores. Su firma es la siguiente:
sum(iterable[, start=0])
Puede llamar a sum()
con los dos argumentos siguientes:
iterable
Un argumento obligatorio que puede contener cualquier iterable de Python.
start
Un argumento opcional que puede contener un valor inicial.
Cuando llamas a sum()
, la función agrega internamente start
más los valores en iterable
. Los elementos de la entrada iterable
suelen ser valores numéricos. Sin embargo, también puedes utilizar listas o tuplas. El argumento start
puede aceptar un número, una lista o una tupla, dependiendo de lo que contenga su iterable
.
Aquí hay algunos ejemplos de cómo usar sum()
con diferentes entradas:
>>> sum([])
0
>>> sum([1, 2, 3, 4, 5])
15
>>> sum([1, 2, 3, 4, 5], 100) # As a positional argument
115
>>> sum([1, 2, 3, 4, 5], start=100) # As a keyword argument
115
>>> num_lists = [[1, 2, 3], [4, 5, 6]]
>>> sum(num_lists, start=[])
[1, 2, 3, 4, 5, 6]
>>> num_tuples = ((1, 2, 3), (4, 5, 6))
>>> sum(num_tuples, start=())
(1, 2, 3, 4, 5, 6)
Cuando llamas a sum()
con un iterable vacío, obtienes 0
como resultado porque ese es el valor predeterminado de start
. Llamar a la función con una lista de valores devuelve la suma total de los valores proporcionados.
Si desea utilizar un valor start
distinto de 0
, puede proporcionarlo como argumento posicional o de palabra clave. Sin embargo, este último enfoque es más legible.
Los dos últimos ejemplos muestran que también puedes usar sum()
para concatenar listas y tuplas. Tenga en cuenta que para que este truco funcione, debe configurar start
en el objeto apropiado. Si desea concatenar listas, entonces start
debe contener una lista, y así sucesivamente. Aunque este truco funciona, la práctica no es eficiente ni común. En su lugar, deberías utilizar el operador más (+
) para concatenaciones regulares.
Un ejemplo clásico de uso de sum()
es cuando necesitas calcular la media o el promedio de varios valores numéricos. En esta situación, es necesario sumar los datos de entrada como paso intermedio. He aquí un ejemplo:
def mean(values):
try:
return sum(values) / len(values)
except ZeroDivisionError:
raise ValueError("mean() arg shouldn't be empty") from None
En esta función mean()
, utiliza sum()
para sumar los valores de entrada y luego divide el resultado por el número de valores en los datos de entrada.
Creación y manipulación de tipos de datos básicos
Python tiene varias funciones integradas que le permiten manipular tipos de datos básicos, como números enteros y de punto flotante, cadenas y valores booleanos. A continuación se muestra un resumen de las funciones integradas que le ayudan a procesar tipos de datos básicos:
int()
Construye un objeto entero a partir de un número o cadena
bin()
Convierte un número entero en una cadena binaria
oct()
Convierte un número entero en una cadena octal
hex()
Convierte un número entero en una cadena hexadecimal
float()
Construye un objeto de punto flotante a partir de un número o cadena
complex()
Construye un número complejo a partir de argumentos.
str()
Crea un objeto de cadena
repr()
Crea una representación de cadena de un objeto fácil de usar para desarrolladores.
bool()
Convierte un argumento en un valor booleano
ord()
Busca el punto de código entero de un carácter.
chr()
Busca el carácter del punto de código entero dado
bytes()
Crea un objeto
bytes
(similar abytearray
, pero inmutable)bytearray()
Crea un objeto de la clase
bytearray
En las siguientes secciones, aprenderá los conceptos básicos para trabajar con estas funciones y cómo usarlas en su código Python.
Representación de números enteros: int()
, bin()
, oct()
y hex()
Los números enteros son bastante útiles en programación. Python tiene un tipo de datos incorporado llamado int
que representa números enteros. Cuando se trabaja con números enteros, a veces es necesario expresarlos en diferentes bases como 2
, 8
o 16
. Es posible que también necesite convertir cadenas u otros tipos numéricos a números enteros.
Para la última tarea, puede utilizar la función incorporada int()
. A continuación se muestran algunos ejemplos de su uso:
>>> int()
0
>>> int(42.42)
42
>>> int("42")
42
>>> int("42.42")
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: '42.42'
>>> int("one")
Traceback (most recent call last):
...
ValueError: invalid literal for int() with base 10: 'one'
Sin argumento, int()
devuelve 0
. Este comportamiento es especialmente útil cuando necesita una función de fábrica para clases como defaultdict
del módulo collections
. Con números de punto flotante, int()
simplemente elimina la parte decimal y devuelve la parte completa. Finalmente, con una cadena como argumento, int()
devuelve el número entero correspondiente sólo si la cadena representa un número entero válido.
También puedes usar int()
para convertir una representación de cadena binaria, octal o hexadecimal en un número entero:
>>> int("0b10", base=2)
2
>>> int("0o10", base=8)
8
>>> int("0x10", base=16)
16
En el primer ejemplo, utiliza int()
para convertir una cadena que representa un número en formato binario a su entero decimal equivalente. Tenga en cuenta que para que esta operación funcione, debe establecer el argumento base
en la base adecuada, que es 2
para números binarios. A continuación, realiza conversiones similares con cadenas octales y hexadecimales. Nuevamente, debe establecer base
en el valor apropiado.
Las funciones bin()
, oct()
y hex()
le permiten realizar la operación opuesta. Con ellos, puedes convertir un número entero dado en su representación binaria, octal o hexadecimal:
>>> bin(42)
'0b101010'
>>> oct(42)
'0o52'
>>> hex(42)
'0x2a'
En estos ejemplos, utiliza un número entero como argumento para bin()
, oct()
y hex()
. Como resultado, obtiene la representación de cadena del valor de entrada en formato binario, octal y hexadecimal, respectivamente.
Manipulación de otros números: float()
y complex()
Python tiene tipos básicos integrados para representar números de punto flotante y complejos. Estos tipos tienen funciones integradas asociadas para fines de conversión. Entonces, para números de punto flotante, tienes la función float()
, y para números complejos tienes complex()
.
Nota: Para profundizar en los números complejos y la función complex()
, consulta el tutorial Simplificar números complejos con Python.
Aquí están las firmas de ambas funciones:
float(number=0.0)
complex(real=0, imag=0)
complex(string)
La función float()
toma un único argumento que representa un valor numérico. Este argumento acepta números o cadenas que representan números válidos:
>>> float()
0.0
>>> float(42)
42.0
>>> float("42")
42.0
>>> float("3.14")
3.14
>>> float("one")
Traceback (most recent call last):
...
ValueError: could not convert string to float: 'one'
Sin argumentos, float()
devuelve 0.0
. Con números enteros, devuelve el número de punto flotante equivalente con 0
como parte decimal. Con cadenas que representan números, float()
devuelve el número de punto flotante equivalente. Sin embargo, falla si la cadena de entrada no representa un valor numérico válido.
La función complex()
le permite trabajar con números complejos. Esta función tiene dos firmas diferentes. La primera firma tiene dos argumentos:
real
La parte real del número.
imag
La parte imaginaria del número.
Estos argumentos aceptan valores numéricos, como números enteros o de punto flotante. Así es como funciona esta variación de complex()
:
>>> complex(3, 6)
(3+6j)
>>> complex(1, 0)
(1+0j)
>>> complex(0, 1)
1j
>>> complex(3.14, -2.75)
(3.14-2.75j)
Puede llamar a complex()
con valores numéricos, lo que da como resultado un número complejo. Tenga en cuenta que Python usa un j
para definir la parte imaginaria.
La segunda firma de complex()
toma un único argumento que debería ser una cadena:
>>> complex("3+6j")
(3+6j)
>>> complex("1+0j")
(1+0j)
>>> complex("1j")
1j
>>> complex("3.14-2.75j")
(3.14-2.75j)
Cuando usa cadenas para crear números complejos con complex()
, debe asegurarse de que la cadena de entrada tenga un formato válido. Debe estar formado por la parte real, el signo y la parte imaginaria. No puede agregar espacios para separar estos componentes.
Construyendo y representando cadenas: str()
y repr()
Cuando se trata de crear y trabajar con cadenas de Python, hay que considerar dos funciones integradas fundamentales:
str()
repr()
Con la función str()
, puede crear nuevas cadenas o convertir objetos existentes en cadenas:
>>> str()
''
>>> str(42)
'42'
>>> str(3.14)
'3.14'
>>> str([1, 2, 3])
'[1, 2, 3]'
>>> str({"one": 1, "two": 2, "three": 3})
"{'one': 1, 'two': 2, 'three': 3}"
>>> str({"A", "B", "C"})
"{'B', 'C', 'A'}"
En el primer ejemplo, usas str()
sin un argumento para crear una cadena vacía. En los otros ejemplos, obtienes cadenas con representaciones fáciles de usar de los objetos de entrada.
Para un caso de uso práctico, digamos que tiene una lista de valores numéricos y desea unirlos usando el método str.join()
, que solo acepta iterables de cadenas. En este caso, puedes hacer algo como lo siguiente:
>>> "-".join(str(value) for value in [1, 2, 3, 4, 5])
'1-2-3-4-5'
En este ejemplo, utiliza una expresión generadora para convertir cada número a su representación de cadena antes de llamar a .join()
. De esta manera, evita recibir un error en su código.
Por su parte, la función incorporada repr()
le brinda una representación fácil de usar para el desarrollador del objeto en cuestión:
>>> repr(42)
'42'
>>> repr(3.14)
'3.14'
>>> repr([1, 2, 3])
'[1, 2, 3]'
>>> repr({"one": 1, "two": 2, "three": 3})
"{'one': 1, 'two': 2, 'three': 3}"
>>> repr({"A", "B", "C"})
"{'B', 'C', 'A'}"
Para los tipos integrados, la representación de cadena que se obtiene con repr()
es la misma que se obtiene con la función str()
.
Nota: Detrás de la función str()
, tienes el método especial .__str__()
. De manera similar, detrás de repr()
, tienes el método .__repr__()
. Para obtener más información sobre estos métodos especiales, consulte ¿Cuándo debería utilizar .__repr__()
frente a .__str__()
en Python? tutorial.
Para ver la diferencia entre str()
y repr()
, considere el siguiente ejemplo que utiliza el módulo datetime
:
>>> import datetime
>>> today = datetime.datetime.now()
>>> repr(today)
'datetime.datetime(2024, 7, 1, 12, 38, 53, 180208)'
>>> str(today)
'2024-07-01 12:38:53.180208'
El método repr()
le proporciona una representación de cadena fácil de usar para desarrolladores del objeto datetime
. Idealmente, debería poder recrear el objeto utilizando esta representación. En otras palabras, debería poder copiar y pegar la representación resultante para recrear el objeto. Es por eso que se dice que esta representación de cadena es amigable para los desarrolladores.
Por el contrario, la representación de cadena que se obtiene al llamar a str()
debe ser legible e informativa para los usuarios finales.
Procesamiento de valores booleanos: bool()
La función bool()
incorporada de Python le permite determinar el valor de verdad de cualquier objeto de Python. Es una función predicada porque siempre devuelve True
o False
. Para determinar si un objeto es falso, en otras palabras, si bool()
devuelve False
cuando se aplica al objeto, Python usa lo siguiente reglas internas:
- Constantes definidas como falsas:
Ninguna
yFalse
- El cero de cualquier tipo numérico:
0
,0.0
,0j
,Decimal(0)
,Fracción (0, 1)
- Secuencias y colecciones vacías:
''
,()
,[]
,{}
,set( )
,rango(0)
El resto de los objetos se consideran veraces en Python. Los objetos personalizados se consideran veraces de forma predeterminada a menos que proporcionen un método especial .__bool__()
que defina un comportamiento diferente.
Nota: Para obtener más información sobre la lógica y los valores booleanos, consulte el tutorial Booleanos de Python: use valores de verdad en su código.
A continuación se muestran algunos ejemplos de cómo funciona bool()
:
>>> bool()
False
>>> bool(0)
False
>>> bool(42)
True
>>> bool(0.0)
False
>>> bool(3.14)
True
>>> bool("")
False
>>> bool("Hello")
True
>>> bool([])
False
>>> bool([1, 2, 3])
True
En el primer ejemplo, llamas a bool()
sin un argumento y obtienes False
como resultado. En el resto de los ejemplos, puede confirmar que Python aplica consistentemente las reglas enumeradas anteriormente. En la práctica, sólo necesitarás usar bool()
cuando tu código requiera explícitamente un valor booleano en lugar de un objeto diferente.
Como ejemplo del uso de bool()
, digamos que tiene la siguiente implementación de una estructura de datos de pila:
class Stack:
def __init__(self, items=None):
self.items = list(items) if items is not None else []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def __bool__(self):
return bool(self.items)
En este ejemplo, su clase Stack
implementa el método especial .__bool__()
para admitir operaciones booleanas en sus objetos. Este método garantiza que cuando un objeto Stack
determinado está vacío, la función bool()
devuelve False
y True
en caso contrario. . He aquí un ejemplo:
>>> from stack import Stack
>>> stack = Stack()
>>> bool(stack)
False
>>> stack.push(4)
>>> bool(stack)
True
En este fragmento de código, primero crea una pila vacía. Cuando pasas este objeto a bool()
, obtienes False
. Luego, inserta un valor en la pila y llama a bool()
nuevamente. Esta vez obtienes True
porque la pila ya no está vacía.
Cadenas de codificación: ord()
y chr()
La codificación de caracteres es un tema importante en la mayoría de los lenguajes de programación. En Python, las cadenas utilizan los caracteres Unicode establecidos de forma predeterminada. Cada carácter Unicode tiene un punto de código asociado, que es un número entero. Para obtener el punto de código de un carácter determinado, puede utilizar la función incorporada ord()
:
>>> ord("A")
65
>>> ord("Z")
90
>>> ord("x")
120
>>> ord("ñ")
241
>>> ord("&")
38
Cada carácter Unicode tiene un punto de código asociado que identifica de forma única el carácter en la tabla Unicode. En estos ejemplos, utiliza la función para obtener el punto de código de algunos caracteres.
En la práctica, puede utilizar la función ord()
para implementar técnicas criptográficas básicas, ordenar cadenas o caracteres, validar caracteres de entrada, etc. Aquí hay un ejemplo rápido de una función que solo verifica si todos los caracteres en una cadena son letras mayúsculas del alfabeto inglés:
>>> def is_uppercase(text):
... for char in text:
... if not (65 <= ord(char) <= 90):
... return False
... return True
...
>>> is_uppercase("HELLO")
True
>>> is_uppercase("Hello")
False
En esta función, utiliza ord()
para determinar si los caracteres en una cadena están entre 65
y 90
, que es el intervalo de código puntos para letras mayúsculas, de la A a la Z, en la tabla Unicode.
A veces, es posible que necesites determinar el punto de código que identifica un carácter Unicode determinado. En esta situación, puede utilizar la función incorporada chr()
:
>>> chr(65)
'A'
>>> chr(90)
'Z'
>>> chr(120)
'x'
>>> chr(241)
'ñ'
>>> chr(38)
'&'
La función chr()
realiza la operación opuesta a ord()
. Le permite encontrar el punto de código asociado con un carácter específico.
Las funciones ord()
y chr()
son en cierto modo complementarias y, por lo tanto, probablemente las encontrará utilizadas juntas.
Creando Bytes y Bytearrays: bytes()
y bytearray()
Los bytes y las matrices de bytes de Python son tipos integrados que Python proporciona de forma inmediata para manipular datos binarios, codificar y decodificar texto, procesar la entrada y salida de archivos y comunicarse a través de redes.
El tipo de datos bytes
es inmutable, mientras que el tipo bytearray
es mutable. Para crear objetos derivados de estos tipos de datos, puede utilizar las funciones integradas bytes()
y bytearray()
.
Las funciones bytes()
y bytearray()
tienen las siguientes firmas:
bytes(source=b"")
bytes(source, encoding)
bytes(source, encoding, errors)
bytearray(source=b"")
bytearray(source, encoding)
bytearray(source, encoding, errors)
Ambas funciones tienen tres firmas diferentes. La primera firma de ambas funciones acepta un literal bytes
como argumento. Estos literales son similares a los literales de cadena, pero comienzan con b
y solo aceptan caracteres ASCII.
Aquí hay un resumen de los argumentos y su significado:
source
Un literal
bytes
o una cadenaencoding
La codificación de caracteres que se utilizará para decodificar
source
si contiene una cadenaerrors
Un controlador para errores de codificación y decodificación.
El argumento encoding
solo es necesario si el argumento source
es una cadena, en cuyo caso, debe proporcionar la codificación adecuada para que Python pueda convertir la cadena en bytes.
Finalmente, los argumentos errors
también son opcionales y deben contener uno de los siguientes controladores de errores:
"strict"
Genera una excepción
UnicodeDecodeError
oUnicodeEncodeError
cuando aparecen problemas de codificación."ignore"
Ignora los caracteres que no se pueden codificar.
"replace"
Reemplaza los caracteres que no se pueden codificar con un signo de interrogación (
?
)"xmlcharrefreplace"
Reemplaza los caracteres que no se pueden codificar con una referencia de caracteres XML
"backslashreplace"
Reemplaza los caracteres que no se pueden codificar con las secuencias de escape de barra invertida de Python
Al elegir los controladores de errores adecuados, puede configurar una buena estrategia para aquellas situaciones en las que llama a las funciones bytes()
y bytearray()
con datos erróneos.
A continuación se muestran algunos ejemplos del uso de las funciones bytes()
y bytearray()
:
>>> bytes()
b''
>>> bytes(b"Using ASCII characters or bytes \xc3\xb1")
b'Using ASCII characters or bytes \xc3\xb1'
>>> bytes("Using non-ASCII characters: ñ Ł", encoding="utf-8")
b'Using non-ASCII characters: \xc3\xb1 \xc5\x81'
>>> bytearray()
bytearray(b'')
>>> bytearray(b"Using ASCII characters or bytes \xc3\xb1")
bytearray(b'Using ASCII characters or bytes \xc3\xb1')
>>> bytearray("Using non-ASCII characters: ñ Ł", encoding="utf-8")
bytearray(b'Using non-ASCII characters: \xc3\xb1 \xc5\x81')
En estos ejemplos, crea objetos bytes
y bytearray
utilizando literales bytes
y cadenas con la codificación correcta como argumento. Tenga en cuenta que puede llamar a la función bytes()
sin argumentos para crear un objeto bytes
vacío.
Ahora considere los siguientes ejemplos que muestran cómo utilizar controladores de errores:
>>> bytes(
... "Using non-ASCII characters with the ASCII encoding: ñ Ł",
... encoding="ascii"
... )
Traceback (most recent call last):
...
UnicodeEncodeError: 'ascii' codec can't encode character '\xf1'
in position 52: ordinal not in range(128)
>>> bytes(
... "Using non-ASCII characters with the ASCII encoding: ñ Ł",
... encoding="ascii",
... errors="ignore"
... )
b'Using non-ASCII characters with the ASCII encoding: '
>>> bytes(
... "Using non-ASCII characters with the ASCII encoding: ñ Ł",
... encoding="ascii",
... errors="replace"
... )
b'Using non-ASCII characters with the ASCII encoding: ? ?'
>>> bytes(
... "Using non-ASCII characters with the ASCII encoding: ñ Ł",
... encoding="ascii",
... errors="xmlcharrefreplace"
... )
b'Using non-ASCII characters with the ASCII encoding: ñ Ł'
>>> bytes(
... "Using non-ASCII characters with the ASCII encoding: ñ Ł",
... encoding="ascii",
... errors="backslashreplace"
... )
b'Using non-ASCII characters with the ASCII encoding: \\xf1 \\u0141'
En estos ejemplos, solo usas bytes()
porque bytearray()
funcionaría de manera similar. La única diferencia es que bytes()
devuelve objetos inmutables mientras que bytearray()
devuelve objetos mutables.
Estos ejemplos utilizan caracteres que no son ASCII con codificación ASCII, lo que provocará errores de codificación que deberá solucionar. El valor predeterminado del argumento errors
es "strict"
. Es por eso que obtienes una excepción UnicodeEncodeError
en el primer ejemplo anterior.
Luego configura errors
en "ignore"
para que Python ignore cualquier error de codificación. En este caso, se eliminan los caracteres ñ
y Ł
. Si configura errors
en "replace"
, entonces ñ
y Ł
se reemplazan cada uno con un signo de interrogación.
El uso de "xmlcharrefreplace"
como controlador de errores hace que Python reemplace los caracteres ñ
y Ł
con sus respectivas referencias de caracteres XML. Finalmente, usar "backslashreplace"
escapa de los caracteres problemáticos usando la secuencia de escape apropiada.
Crear tipos de datos de colección
Una característica fundamental de Python es el rico conjunto de tipos de datos de recopilación integrados en el lenguaje. Tendrá varias funciones integradas que le permitirán manipular estos tipos de datos, que incluyen listas, tuplas, diccionarios, conjuntos y bytes.
A continuación se muestra un resumen de las funciones integradas que le ayudan a procesar los tipos de datos de recopilación:
list()
Crea un objeto
list
a partir de un iterabletuple()
Crea un objeto
tuple
a partir de un iterabledict()
Crea un objeto
dict
a partir de una serie de pares clave-valor o argumentos de palabras claveset()
Crea un objeto
set
a partir de un iterablefrozenset()
Crea un objeto
frozenset
a partir de un iterable
En las siguientes secciones, aprenderá los conceptos básicos para trabajar con estas funciones y usarlas para crear y manipular colecciones en su código Python.
Creando listas y tuplas: list()
y tuple()
La list
de Python es un tipo de datos integrado fundamental con un impresionante conjunto de características. Las listas son mutables y le permiten organizar y manipular de manera eficiente datos que pueden ser heterogéneos pero que normalmente son homogéneos. Por ejemplo, puede utilizar una lista para almacenar una columna de una tabla de base de datos.
Nota: Para obtener más información sobre cómo trabajar con listas y la función list()
, consulta el tutorial list
Tipo de datos de Python: un análisis profundo con ejemplos. .
De manera similar, la tupla
de Python es otro tipo integrado. A diferencia de las listas, las tuplas son inmutables. Puede utilizarlos para organizar datos que pueden ser homogéneos pero que normalmente son heterogéneos. Por ejemplo, puedes utilizar una tupla para almacenar una fila de una tabla de base de datos.
Nota: Para obtener más información sobre cómo trabajar con tuplas y la función tuple()
, consulta el tutorial tuple
Tipo de datos de Python: un análisis profundo con ejemplos. .
Las funciones integradas list()
y tuple()
de Python te permiten crear objetos list
y tuple
.
La función list()
toma un iterable como argumento y devuelve un objeto list
creado a partir de los datos de entrada. Entonces, su firma se parece a la siguiente:
list([iterable])
Tenga en cuenta que los corchetes alrededor de iterable
significan que el argumento es opcional, por lo que los corchetes no forman parte de la sintaxis.
Nota: En la práctica, list()
es un constructor de clases en lugar de una función. Sin embargo, la documentación de Python lo llama función.
A continuación se muestran algunos ejemplos del uso de list()
para crear objetos list
:
>>> list()
[]
>>> list("Hello")
['H', 'e', 'l', 'l', 'o']
>>> list((1, 2, 3, 4, 5))
[1, 2, 3, 4, 5]
>>> list({"circle", "square", "triangle", "rectangle", "pentagon"})
['square', 'rectangle', 'triangle', 'pentagon', 'circle']
>>> list({"name": "John", "age": 30, "city": "New York"})
['name', 'age', 'city']
>>> list({"name": "John", "age": 30, "city": "New York"}.keys())
['name', 'age', 'city']
>>> list({"name": "John", "age": 30, "city": "New York"}.values())
['John', 30, 'New York']
>>> list({"name": "John", "age": 30, "city": "New York"}.items())
[('name', 'John'), ('age', 30), ('city', 'New York')]
Cuando llamas a list()
sin un argumento, creas una nueva lista vacía. Cuando usas una cadena como argumento, creas una lista de caracteres. Cuando usas una tupla, la conviertes en una lista.
Nota: En la mayoría de los casos, utilizará un par de llaves cuadradas, []
, para crear una lista vacía. Sin embargo, en algunas situaciones, usar list()
puede ser más legible o explícito.
La función list()
incluso acepta conjuntos, pero debes recordar que los conjuntos son estructuras de datos desordenadas, por lo que no podrás predecir el orden final de los elementos en la lista resultante.
Cuando se trata de utilizar diccionarios con list()
, tienes cuatro posibilidades. Puede crear una lista de claves usando el diccionario directamente o usando su método .keys()
. Si desea crear una lista de valores, puede utilizar el método .values()
. Finalmente, si desea crear una lista de pares clave-valor, puede utilizar el método .items()
.
Las listas tienen muchos casos de uso en el código Python. Son flexibles, potentes y llenos de funciones, por lo que los encontrará en casi todos los fragmentos de código Python.
Las tuplas se utilizan habitualmente para almacenar datos heterogéneos e inmutables. La función tuple()
le permite crear tuplas sobre la marcha. Aquí está la firma:
tuple([iterable])
Los corchetes alrededor de iterable
significan que el argumento es opcional, por lo que los corchetes no forman parte de la sintaxis.
Considere los siguientes ejemplos del uso de tuple()
en su código:
>>> tuple()
()
>>> tuple("Hello")
('H', 'e', 'l', 'l', 'o')
>>> tuple(["Jane Doe", 25, 1.75, "Canada"])
('Jane Doe', 25, 1.75, 'Canada')
>>> tuple({
... "manufacturer": "Ford",
... "model": "Mustang",
... "color": "Blue",
... }.values())
('Ford', 'Mustang', 'Blue')
Puedes usar tuple()
sin argumentos para crear una tupla vacía. Esto será más legible que usar un par de paréntesis vacíos ()
. Cuando pasas una cadena a tuple()
, obtienes una tupla de caracteres.
En el tercer ejemplo, utiliza tuple()
para convertir una lista de datos heterogéneos en una tupla, que sería una estructura de datos más apropiada para almacenar este tipo de datos. Finalmente, usas los valores de un diccionario para construir una tupla.
Al igual que las listas, las tuplas son bastante útiles en Python. Los verá utilizados en muchos casos de uso, especialmente en aquellas situaciones en las que necesita almacenar datos heterogéneos e inmutables.
Construyendo diccionarios: dict()
Los diccionarios son una estructura de datos integrada fundamental en Python. Están en todas partes y son una parte central del propio idioma. Encontrará muchos casos de uso para diccionarios en su código. En cuanto a otras colecciones integradas, Python también tiene una función integrada que le permite crear diccionarios: la función dict()
.
Nota: Para obtener más información sobre los diccionarios y la función dict()
, consulte el tutorial Diccionarios en Python.
La función dict()
tiene las siguientes firmas:
dict(**kwargs)
dict(mapping, **kwargs)
dict(iterable, **kwargs)
Todas estas firmas aceptan lo que se conoce como argumentos de palabras clave (**kwargs
) o argumentos con nombre. La segunda firma toma un mapeo, que puede ser otro diccionario. Finalmente, la tercera firma acepta un iterable de pares clave-valor, que puede ser una lista de tuplas de dos elementos, por ejemplo.
A continuación se muestran algunos ejemplos rápidos del uso de la función dict()
de diferentes maneras:
>>> dict()
{}
>>> jane = dict(name="Jane", age="30", country="Canada")
>>> jane
{'name': 'Jane', 'age': '30', 'country': 'Canada'}
>>> dict(jane, job="Python Dev")
{'name': 'Jane', 'age': '30', 'country': 'Canada', 'job': 'Python Dev'}
>>> dict([("name", "Jane"), ("age", 30), ("country", "Canada")])
{'name': 'Jane', 'age': 30, 'country': 'Canada'}
Nuevamente, al crear un diccionario vacío, puede usar la función dict()
sin argumentos. Esto es menos común que usar un par de llaves {}
, pero nuevamente, puede ser más legible y explícito en algunos contextos.
Luego, crea un diccionario jane
utilizando argumentos de palabras clave. Esta es una forma limpia y elegante de crear diccionarios en Python.
El tercer ejemplo muestra cómo se puede combinar una asignación con argumentos de palabras clave para crear un nuevo objeto de diccionario. Finalmente, en el cuarto ejemplo, crea un nuevo diccionario a partir de una lista de tuplas.
Creación de conjuntos y conjuntos congelados: set()
y frozenset()
El set
de Python es un tipo de datos integrado para crear colecciones de objetos únicos y hashable, normalmente llamados elementos o miembros. En Python, los conjuntos admiten las operaciones definidas para conjuntos matemáticos, incluidas unión, diferencia, diferencia simétrica y otras.
Python tiene dos tipos de conjuntos:
set
frozenset
La diferencia entre estos dos tipos de datos es que los objetos set
son mutables y los objetos frozenset
son inmutables.
Nota: Para obtener más información sobre los conjuntos y la función set()
, consulte el tutorial Conjuntos en Python.
Al igual que con otros tipos de datos, Python también proporciona funciones integradas para crear conjuntos y conjuntos congelados. Tendrás las funciones set()
y frozenset()
, respectivamente. La firma de estas funciones se muestra a continuación:
set([iterable])
frozenset([iterable])
Nuevamente, los corchetes indican que la entrada iterable es opcional. Ahora consulte los siguientes ejemplos de creación de conjuntos y conjuntos congelados:
>>> set()
set()
>>> frozenset()
frozenset()
>>> set(["square", "rectangle", "triangle", "pentagon", "circle"])
{'square', 'triangle', 'circle', 'rectangle', 'pentagon'}
>>> frozenset(["square", "rectangle", "triangle", "pentagon", "circle"])
frozenset({'square', 'triangle', 'circle', 'rectangle', 'pentagon'})
>>> set(("red", "green", "blue", "red"))
{'green', 'red', 'blue'}
>>> frozenset(("red", "green", "blue", "red"))
frozenset({'green', 'red', 'blue'})
Cuando llamas a set()
y frozenset()
sin argumentos, creas un conjunto vacío o un conjunto congelado, respectivamente. En el caso de conjuntos, no tiene un literal que pueda usar para crear un conjunto vacío porque un par de llaves ({}
) definen un diccionario vacío. Entonces, para crear un conjunto vacío, debes usar la función set()
.
En el resto de los ejemplos, se utilizan iterables, como listas y tuplas, para crear conjuntos y conjuntos congelados. Es importante tener en cuenta que cuando el iterable de entrada tiene elementos repetidos, el conjunto final tendrá una única instancia del elemento repetido. Además, los conjuntos son estructuras de datos desordenadas, por lo que no podrás predecir el orden final de los elementos en el conjunto resultante al proporcionar una lista.
Procesamiento de iterables e iteradores
Los iteradores e iterables de Python son dos herramientas diferentes pero relacionadas que resultan útiles cuando necesitas iterar sobre un flujo de datos o una colección de datos. Los iteradores potencian y controlan el proceso de iteración, mientras que los iterables normalmente contienen datos que se pueden iterar sobre un valor a la vez.
Python tiene varias funciones integradas que puede utilizar para trabajar con iterables e iteradores. Aquí hay un resumen de estas funciones:
len()
Calcula la longitud de un objeto de tamaño.
reversed()
Construye un iterador inverso
sorted()
Crea una lista ordenada a partir de un iterable.
all()
Comprueba si todos los elementos de un iterable son verdaderos.
any()
Comprueba si algún elemento de un iterable es verdadero.
range()
Genera un rango de valores enteros.
enumerate()
Crea un iterador de tuplas que contienen índices y valores de un iterable.
slice()
Crea un objeto
slice
zip()
Crea un iterador que agrega elementos de iterables.
iter()
Construye un objeto iterador
next()
Recupera el siguiente elemento de un iterador.
filter()
Filtra elementos de un iterable.
map()
Aplica una función a cada elemento de un iterable.
En las siguientes secciones, aprenderá sobre todas estas funciones integradas y cómo pueden resultar útiles al procesar iterables e iteradores en su código Python.
Determinar el número de artículos en un contenedor: len()
Una de las operaciones más comunes que realizará en colecciones es determinar la cantidad de elementos almacenados en una secuencia o colección existente. Para completar esta tarea, Python tiene la función len()
incorporada.
Nota: Para obtener más información sobre la función len()
, consulte el tutorial Uso de la función len()
en Python.
La función len()
toma un único argumento, que puede ser una secuencia, como una cadena, una tupla o una lista. También puede ser una colección, como un diccionario, un conjunto o un conjunto congelado. La función devuelve la longitud o el número de elementos del objeto de entrada.
A continuación se muestran algunos ejemplos del uso de len()
con diferentes objetos:
>>> len("Python")
6
>>> len(("Jane Doe", 25, 1.75, "Canada"))
4
>>> len([1, 2, 3, 4, 5])
5
>>> len({"green", "red", "blue"})
3
>>> len({"name": "Jane", "age": 30, "country": "Canada"})
3
En el primer ejemplo, usa len()
para obtener el número de caracteres en una cadena. Luego, usa la función para determinar la longitud de una tupla, una lista y un conjunto. Finalmente, usas len()
con un diccionario como argumento. En este caso, obtiene la cantidad de pares clave-valor en el diccionario de entrada.
Tenga en cuenta que len()
devuelve 0
cuando lo llama con contenedores vacíos:
>>> len("")
0
>>> len(())
0
>>> len([])
0
En estos ejemplos, utiliza len()
con una cadena, tupla y una lista vacías. En todos los casos, obtienes 0
como resultado.
La función len()
puede resultar útil en varias situaciones. Un ejemplo común es cuando necesitas calcular el promedio de una serie de valores numéricos:
>>> grades = [90, 97, 100, 87]
>>> sum(grades) / len(grades)
93.5
En este ejemplo, len()
le proporciona el número de valores en la lista de calificaciones. Luego, utiliza este valor para calcular la calificación promedio.
Invertir y ordenar iterables: reversed()
y sorted()
Invertir y ordenar los valores en un iterable es otra operación útil en programación. Debido a que estas operaciones son tan comunes, Python tiene funciones integradas para ellas. Cuando desee revertir un iterable, puede utilizar la función incorporada reversed()
.
Nota: Para profundizar en las listas inversas con la función reversed()
, consulte Listas inversas de Python: más allá de .reverse()
y < código>invertido() tutorial.
La función reversed()
toma un iterable como argumento y devuelve un iterador que produce los elementos en orden inverso:
>>> reversed([0, 1, 2, 3, 4, 5])
<list_reverseiterator object at 0x107062b30>
>>> list(reversed([0, 1, 2, 3, 4, 5]))
[5, 4, 3, 2, 1, 0]
En este ejemplo, llamas a reversed()
con una lista de números. La función devuelve un iterador inverso. Para mostrar su contenido, puede utilizar la función list()
para crear una lista a partir del iterador.
Nota: Convertir iteradores en listas es un caso de uso común para la función list()
, especialmente cuando se depura o se trabaja de forma interactiva.
De manera similar, cuando necesite ordenar los valores en un iterable, puede usar la función sorted()
. Esta función tiene la siguiente firma:
sorted(iterable, key=None, reverse=False)
El primer argumento es un objeto iterable, como una cadena, una lista, una tupla o un diccionario. Luego, tiene los argumentos key
y reverse
, que tienen los siguientes significados:
key
Especifica una función de un argumento que extrae una clave de comparación de cada elemento en el iterable de entrada.
reverse
Es un valor booleano que le permite ordenar los elementos en orden inverso si lo configura en
True
Es importante tener en cuenta que el argumento key
acepta objetos de función. En otras palabras, funciones sin paréntesis de llamada.
Nota: Para obtener más información sobre la función sorted()
, consulte Cómo utilizar sorted()
y .sort().
en el tutorial de Python.
A continuación se muestran algunos ejemplos del uso de sorted()
con diferentes contenedores integrados como argumentos:
>>> sorted("bdeac")
['a', 'b', 'c', 'd', 'e']
>>> sorted([4, 2, 7, 5, 1, 6, 3])
[1, 2, 3, 4, 5, 6, 7]
>>> sorted([4, 2, 7, 5, 1, 6, 3], reverse=True)
[7, 6, 5, 4, 3, 2, 1]
A diferencia de reversed()
, la función sorted()
siempre devuelve un objeto de lista en lugar de un iterador. En el primer ejemplo, utiliza una cadena como argumento para sorted()
y obtiene una lista de caracteres en orden alfabético. Debajo del capó, Python usa el punto de código Unicode del carácter para comparar cadenas.
Nota: Para profundizar en la clasificación de cadenas, consulte el tutorial Cómo ordenar cadenas Unicode alfabéticamente en Python.
En el tercer ejemplo, establece el argumento reverse
en True
y obtiene la lista de números ordenados en orden inverso.
Finalmente, el argumento key
puede resultar útil en varias situaciones. Un caso de uso común para este argumento es cuando necesita ordenar elementos que también son contenedores. A continuación se muestra un ejemplo de cómo ordenar una lista de tuplas de dos valores:
>>> points = [(1, 2), (3, 1), (4, 0), (2, 1)]
>>> sorted(points, key=lambda point: point[0])
[(1, 2), (2, 1), (3, 1), (4, 0)]
>>> sorted(points, key=lambda point: point[1])
[(4, 0), (3, 1), (2, 1), (1, 2)]
En la primera línea resaltada, utiliza una función lambda
que toma un punto como argumento y devuelve su primera coordenada. Este ejemplo produciría el mismo resultado si llamas a sorted()
sin key
debido a la forma en que Python compara tuplas. En la segunda línea resaltada, la función lambda
devuelve la segunda coordenada. Estas funciones proporcionan claves de comparación para los procesos de clasificación.
Entonces, en el primer ejemplo, ordenas los puntos por su primera coordenada, mientras que en el segundo ejemplo, ordenas los puntos por su segunda coordenada.
Determinar el valor de verdad de los elementos en Iterables: all()
y any()
A veces, es posible que necesites determinar si todos los elementos de un iterable son verdaderos. Para hacer esto, Python tiene la función all()
incorporada. En otras ocasiones, es posible que necesites averiguar si al menos un elemento de un iterable es verdadero. Para este propósito, Python tiene la función any()
incorporada.
La firma de all()
y any()
se muestra a continuación:
all(iterable)
any(iterable)
Ambas funciones toman un iterable de objetos como argumento. La función all()
devuelve True
cuando todos los elementos del iterable de entrada son verdaderos y False
cuando al menos un elemento es falso.
Nota: Para obtener más información sobre la función all()
, consulta el tutorial all()
de Python: comprueba la veracidad de tus iterables.
A continuación se muestran algunos ejemplos de cómo funciona all()
:
>>> all([1, 2, 3, 4])
True
>>> all([1, 2, 3, 4, 0])
False
>>> all(["Hello", ""])
False
>>> all(["Hello", "World"])
True
En los dos primeros ejemplos, utiliza all()
con una lista de números. La primera lista contiene valores enteros diferentes de 0
, que Python considera verdaderos. Entonces, all()
devuelve Verdadero
. Luego, en el segundo ejemplo, agrega un 0
a la lista y all()
devuelve False
porque este valor se considera falso en Python. .
En los dos últimos ejemplos, utiliza una lista de cadenas. Python considera falsa una cadena vacía, por lo que all()
devuelve False
. Finalmente, pasa una lista con dos cadenas no vacías y all()
vuelve a ejecutar True
.
Puede encontrar varios casos de uso para all()
en código del mundo real. Quizás pasar una expresión generadora como argumento a all()
sea una de las formas más poderosas de usar la función. Por ejemplo, digamos que desea determinar si todos los números de una lista están en un intervalo determinado. En esta situación, puede utilizar all()
como en el siguiente código:
>>> numbers = [10, 5, 6, 4, 7, 8, 18]
>>> # Between 0 and 10
>>> all(0 <= x <= 10 for x in numbers)
False
>>> # Between 0 and 20
>>> all(0 <= x <= 20 for x in numbers)
True
En la primera línea resaltada, utiliza una expresión generadora como argumento para all()
. El generador comprueba si los números están entre 0
y 10
y genera valores booleanos según el resultado de la condición.
La función all()
comprueba si todos los valores generados son True
. Si ese es el caso, obtendrás True
. Por otro lado, si al menos uno de los valores generados es False
, entonces obtendrás False
.
A diferencia de all()
, la función any()
devuelve True
si al menos un elemento es verdadero y False
. > si todos los elementos son falsos. Por lo tanto, puedes usar any()
cuando necesites determinar si al menos un elemento en un iterable es verdadero.
Nota: Para obtener más información sobre la función any()
, consulte el tutorial Cómo utilizar any()
en Python.
Aquí hay un par de ejemplos del uso de any()
en Python:
>>> any([0, 0.0, False, "", []])
False
>>> any([0, 0.0, False, "", [], 42])
True
En el primer ejemplo, todos los objetos en la lista de entrada son falsos según las reglas internas de Python para determinar el valor de verdad de un objeto. Como todos los objetos son falsos, any()
devuelve False
. En el segundo ejemplo, agrega el número 42
al final de la lista de entrada. Debido a que 42
es verdadero, any()
devuelve True
.
Nuevamente, al igual que all()
, la función any()
puede brillar cuando la usas con una expresión generadora que verifica alguna condición. Por ejemplo, digamos que desea saber si al menos una letra de un texto determinado está en mayúscula. En esta situación, puede hacer algo como lo siguiente:
>>> any(letter.isupper() for letter in "hello, world!")
False
>>> any(letter.isupper() for letter in "Hello, World!")
True
En estos ejemplos, utiliza el método str.isupper()
para determinar si una letra está en mayúscula. Este método devuelve True
o False
, por lo que obtienes un iterable de valores booleanos. El trabajo de any()
es determinar si alguno de estos valores es verdadero.
En el primer ejemplo, no tienes letras mayúsculas, por lo que any()
devuelve False
. En el segundo ejemplo, tiene una H
mayúscula, por lo que any()
devuelve True
.
Creando rangos de valores enteros: range()
A veces, es necesario crear rangos numéricos para representar una serie de valores enteros en un intervalo determinado. Por lo general, necesita que los números sean consecutivos, pero es posible que también desee que no sean secuenciales.
Por ejemplo, puedes crear un rango de valores que contenga todos los dígitos usando una lista de Python:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Este enfoque funcionará si su rango es relativamente pequeño como el de este ejemplo. Sin embargo, ¿qué pasa si su rango necesita tener un millón de valores? Construir ese tipo de rango con una lista sería una tarea difícil. Hay una mejor manera.
Python tiene la función range()
incorporada para facilitar la creación de rangos numéricos:
>>> range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1_000_000)
range(0, 1000000)
>>> list(range(1_000_000))
[1, 2, 3,
...,
999998, 999999]
La función range()
devuelve un objeto range
en lugar de una lista. Si desea verificar los valores en un rango concreto, puede envolverlo en una llamada a list()
, como lo hizo en el segundo ejemplo. Ahora tienes una lista de dígitos.
En el tercer ejemplo, crea un rango con un millón de números enteros desde 0
hasta 999999
. Si quieres verlo en acción, pásalo a list()
. ¡Obtendrás una ventana de terminal llena de números!
Nota: Para profundizar en el trabajo con rangos y la función range()
, consulte el tutorial Python range()
: Representar rangos numéricos.
La función incorporada range()
tiene las siguientes firmas:
range(stop)
range(start, stop, step=1)
Tiene una variante de la función de un argumento y de tres argumentos. Esto es lo que significa cada argumento:
start
Mantiene el valor inicial en el rango. El valor predeterminado es
0
y está incluido en el rango.stop
Contiene el valor en el que se detiene el rango. Es un argumento obligatorio y su valor no está incluido en el rango.
step
Mantiene el paso a través de sucesivos valores. Es un argumento opcional cuyo valor predeterminado es
1.
Hasta ahora, has utilizado la variación de un argumento, que comienza el rango en 0
y construye un rango de números enteros consecutivos. Aquí hay un par de ejemplos que muestran la variación de tres argumentos:
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(10, 101, 10))
[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
Tenga en cuenta que en la variación de tres argumentos, el tercer argumento es opcional. Esto significa que puede llamar a la función con dos argumentos y confiar en el valor predeterminado de step
, que es 1
. Eso es lo que haces en el primer ejemplo, que construye un rango de números enteros consecutivos desde 1
hasta 11
. Nuevamente, 11
no está incluido en el rango final porque es el valor en el que range()
deja de emitir valores.
En el segundo ejemplo, crea un rango
que comienza en 10
y llega hasta 101
con un paso de 10
.
También puede utilizar valores negativos para los argumentos de range()
. Un caso de uso común para esto es cuando necesita crear rangos de números negativos y rangos que cuentan hacia atrás:
>>> list(range(-10, 0))
[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1]
>>> list(range(100, 0, -10))
[100, 90, 80, 70, 60, 50, 40, 30, 20, 10]
En este ejemplo, el primer rango
contiene números negativos consecutivos desde -10
hasta 0
. El segundo rango
cuenta hacia atrás desde 100
hasta 0
con un paso de -10
.
Los rangos pueden resultar útiles en varias situaciones. Un buen caso de uso para un rango es cuando necesita realizar una operación un número determinado de veces:
>>> for _ in range(3):
... print("Beep")
...
Beep
Beep
Beep
Este bucle se ejecuta tres veces e imprime un mensaje en la pantalla. Sin embargo, el bucle no necesita utilizar la variable de bucle en su cuerpo. Por lo tanto, se utiliza un guión bajo para indicar que se trata de una variable desechable.
Un mal uso común de los objetos range
en Python es usarlos como una forma de recorrer un iterable existente:
>>> letters = ["a", "b", "c", "d"]
>>> for index in range(len(letters)):
... print(index, letters[index])
...
0 a
1 b
2 c
3 d
Este tipo de bucle for
no es el mejor ejemplo de una construcción Pythonic. Utiliza range()
para recorrer las letras con índices numéricos. En la siguiente sección, aprenderá sobre la forma Pythonic de escribir este tipo de bucle.
Enumerar elementos en bucles: enumerate()
Un bucle Pythonic for
itera sobre los elementos en un iterable sin considerar el índice en el que se encuentra un elemento determinado o el orden en el que se procesaron los elementos. Descubrirá que la mayoría de los bucles for
de Python se verán así:
>>> colors = ["red", "orange", "yellow", "green"]
>>> for color in colors:
... print(color)
...
red
orange
yellow
green
Esta forma de escribir bucles en Python es explícita e intuitiva, lo que afecta profundamente la legibilidad del bucle. Sin embargo, a veces necesitarás una forma de acceder al índice donde se encuentra un elemento determinado en el iterable de entrada.
A menudo, cuando comienzas con Python y necesitas acceder a índices en un bucle, puedes terminar escribiendo un bucle como el siguiente:
>>> for index in range(len(colors)):
... print(index, colors[index])
...
...
0 red
1 orange
2 yellow
3 green
4 blue
5 indigo
6 violet
Este tipo de bucle funciona. Sin embargo, no es lo que se puede llamar un bucle Pythonic. Utiliza un par de trucos para imitar de alguna manera la iteración sobre índices. Python ofrece una mejor herramienta para hacer esto, y esa herramienta es la función incorporada enumerate()
.
Nota: Para profundizar en el uso de la función enumerate()
, consulta el tutorial enumerate()
de Python: simplifica los bucles que necesitan contadores.
Así es como escribirás el bucle anterior usando la función enumerate()
:
>>> for index, color in enumerate(colors):
... print(index, color)
...
0 red
1 orange
2 yellow
3 green
4 blue
5 indigo
6 violet
Este bucle es legible y explícito. La función enumerate()
toma un iterable como argumento y genera tuplas de dos elementos que contienen un índice entero y el elemento asociado.
Aquí está la firma de la función:
enumerate(iterable, start=0)
El primer argumento es un objeto iterable. El segundo argumento, start
, le brinda la opción de definir un valor inicial para la enumeración. El valor predeterminado es 0
porque ese es el valor inicial habitual de los índices en la programación. Sin embargo, en algunas situaciones, puede resultar conveniente utilizar un punto de partida diferente, como 1
.
Para ilustrar cómo utilizar el argumento start
, digamos que está creando una aplicación de interfaz de usuario basada en texto (TUI) y desea mostrar un menú con algunas opciones. Las opciones deben tener un número asociado para que el usuario pueda elegir la acción deseada. En esta situación, puede utilizar enumerate()
como en el siguiente código:
>>> def list_menu(options):
... print("Main Menu:")
... for index, option in enumerate(options, start=1):
... print(f"{index}. {option}")
...
>>> list_menu(["Open", "Save", "Settings", "Quit"])
Main Menu:
1. Open
2. Save
3. Settings
4. Quit
Desde la perspectiva del usuario final, comenzar la lista del menú en 1
es el camino natural a seguir. Puede lograr este efecto configurando start
en 1
en la llamada a enumerate()
. Ahora, el menú comienza en 1
en lugar de 0
.
Extracción de sectores o porciones de secuencias: slice()
Cuando trabaja con Python, es posible que necesite extraer una parte o un segmento de una secuencia existente, como una cadena, una lista o una tupla. Para hacer esto, normalmente usa el operador de corte ([]
). Sin embargo, también puede utilizar la función incorporada slice()
. La función slice()
tiene las siguientes firmas:
slice(stop)
slice(start, stop, step=None)
La función slice()
devuelve un objeto slice
que representa el conjunto de índices especificados por range(start, stop, step)
. Los argumentos aquí tienen un significado similar al de la función range()
:
start
Mantiene el valor inicial en el sector. El valor predeterminado es
Ninguno
, que indica el inicio de la secuencia.stop
Contiene el valor en el que se detiene el corte. Es un argumento obligatorio y su valor no está incluido en el segmento. Cuando se establece en
Ninguno
, significa el final de la secuencia (len(sequence)
).step
Mantiene el paso a través de sucesivos valores. Es un argumento opcional cuyo valor predeterminado es
Ninguno
, lo que significa un paso de1
.
Los sectores no representan rangos numéricos sino conjuntos de índices. Puede utilizar estos índices para extraer una parte de una lista. A continuación se muestran algunos ejemplos:
>>> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> even = numbers[slice(1, None, 2)]
>>> even
[2, 4, 6, 8]
>>> odd = numbers[slice(None, None, 2)]
>>> odd
[1, 3, 5, 7, 9]
En el primer segmento, comienza en 1
y sube hasta el final de la lista con un paso de 2
. Este segmento le brinda una lista de números pares. En el segundo ejemplo, comienza al principio de la lista y sube hasta el final de la lista con un paso de 2
. Con este segmento, obtienes una lista de números impares.
Tenga en cuenta que en la mayoría del código Python, no verá ni utilizará slice()
como lo hizo en el ejemplo anterior. En la mayoría de los casos, utilizará el operador de división, [start:stop:step]
. Así es como se ve esto con este operador:
>>> even = numbers[1::2]
>>> even
[2, 4, 6, 8]
>>> odd = numbers[::2]
>>> odd
[1, 3, 5, 7, 9]
En estos ejemplos, utiliza el operador de división para obtener los números pares e impares de su lista original. Tenga en cuenta que omitir un índice determinado hace que ese índice dependa de su valor predeterminado. Por ejemplo, cuando no proporciona un índice start
, el valor predeterminado es el principio de la lista.
Comprimir iterables para iteración paralela: zip()
La función zip()
incorporada de Python le permite iterar sobre múltiples iterables en paralelo. Esta función crea un iterador que agregará elementos de dos o más iterables, generando tuplas de valores.
Nota: Para obtener más información sobre la función zip()
, consulte el tutorial Uso de la función zip()
de Python para iteración paralela.
Aquí está la firma de la función zip()
incorporada:
zip(*iterables, strict=False)
Esta función toma un número indefinido de iterables como argumentos y produce tuplas de elementos bajo demanda. Las tuplas contendrán un elemento de cada entrada iterable, lo que las hace ideales para iteraciones paralelas.
Aquí hay algunos ejemplos rápidos:
>>> letters = ["a", "b", "c"]
>>> numbers = [1, 2, 3]
>>> operators = ["*", "/", "+"]
>>> for characters in zip(letters, numbers, operators):
... print(characters)
...
('a', 1, '*')
('b', 2, '/')
('c', 3, '+')
>>> for l, n, o in zip(letters, numbers, operators):
... print(f"{l} {n} {o}")
...
a 1 *
b 2 /
c 3 +
En el primer bucle, utiliza una única variable de bucle para almacenar cada tupla que obtiene de zip()
. La primera tupla contiene los primeros elementos de cada iterable de entrada. La segunda tupla contiene los segundos elementos, y así sucesivamente. En el segundo bucle, utiliza tres variables de bucle para descomprimir los elementos de cada tupla generada.
Un buen caso de uso de zip()
es cuando tienes dos listas y quieres crear un diccionario a partir de ellas. Considere el siguiente ejemplo:
>>> keys = ["name", "age", "country"]
>>> values = ["Jane", "30", "Canada"]
>>> dict(zip(keys, values))
{'name': 'Jane', 'age': '30', 'country': 'Canada'}
En este ejemplo, combina dos listas existentes usando zip()
y pasa las tuplas resultantes a la función dict()
para crear un diccionario.
El argumento strict
de zip()
se agregó en Python 3.10 y es un argumento de solo palabras clave que proporciona una forma segura de manejar iterables de longitud desigual. El valor predeterminado del argumento es False
, lo que significa que zip()
solo generará tantas tuplas como elementos en el iterable más corto.
Si establece strict
en True
, obtendrá una excepción ValueError
cuando los iterables de entrada no tengan la misma longitud:
>>> list(zip(range(5), range(100)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
>>> list(zip(range(5), range(100), strict=True))
Traceback (most recent call last):
...
ValueError: zip() argument 2 is longer than argument 1
En el primer argumento, confía en el valor predeterminado de strict
y obtiene cinco tuplas porque el rango más corto solo tiene cinco valores. En el segundo ejemplo, establece strict
en True
. Esta vez, obtiene un error porque los rangos de entrada no tienen la misma cantidad de valores.
Construyendo y consumiendo iteradores: iter()
y next()
En Python, los iteradores implementan el patrón de diseño de iteradores, que le permite atravesar un contenedor y acceder a sus elementos. El patrón iterador desacopla los algoritmos de iteración de los contenedores, como listas, tuplas, diccionarios y conjuntos.
Nota: Para obtener más información sobre iteradores e iterables, consulte el tutorial Iteradores e iterables en Python: ejecutar iteraciones eficientes.
Python tiene dos funciones integradas que pueden ayudarte cuando trabajas con iteradores. La función iter()
le permite crear un iterador a partir de un iterable, y la función next()
le permite consumir un iterador un elemento a la vez.
Considere el siguiente ejemplo de juguete:
>>> colors = ["red", "orange", "yellow", "green"]
>>> colors_it = iter(colors)
>>> colors_it
<list_iterator object at 0x10566a170>
>>> next(colors_it)
'red'
>>> next(colors_it)
'orange'
>>> next(colors_it)
'yellow'
>>> next(colors_it)
'green'
>>> next(colors_it)
Traceback (most recent call last):
...
StopIteration
En este ejemplo, utiliza la función iter()
para crear un objeto iterador a partir de una lista de colores existente. A diferencia de los iterables, los iteradores admiten la función next()
. Cuando llamas a esta función con un iterador como argumento, obtienes el primer elemento en la primera llamada. Cuando vuelves a llamar a la función, obtienes el segundo elemento, y así sucesivamente.
Cuando recorre todos los elementos del iterador, next()
genera una excepción StopIteration
. Python utiliza internamente esta excepción para detener el proceso de iteración en un bucle for
o una comprensión. Tenga en cuenta que puede atravesar un iterador sólo una vez. Después de eso, el iterador se agotará o se consumirá.
Aquí están las firmas de iter()
:
iter(iterable)
iter(object, sentinel)
En la primera firma, iterable
representa cualquier tipo iterable. En la segunda firma, el argumento object
debe ser invocable. Ya has visto la primera firma en acción. Ahora es el momento de echar un vistazo rápido a la segunda firma.
Para ilustrar con un ejemplo, supongamos que está trabajando en una aplicación de interfaz de línea de comandos (CLI) y desea tomar la entrada del usuario hasta que ingrese la palabra "done"
. Así es como puedes hacer esto usando la función iter()
:
>>> def read_user_input():
... print("Enter word (type 'done' to finish):")
... for word in iter(input, "done"):
... print(f"Processing word: '{word}'")
...
>>> read_user_input()
Enter word (type 'done' to finish):
Python
Processing word: 'Python'
Programming
Processing word: 'Programming'
Iterators
Processing word: 'Iterators'
done
En la línea resaltada, usa iter()
con dos argumentos. Para el primer argumento, utiliza la función incorporada input()
, que le permite recibir información del usuario. Tenga en cuenta que no llama a la función sino que la pasa como un objeto de función.
Luego, tienes la palabra "done"
, que funciona como centinela. En otras palabras, iter()
llamará a input()
por usted y generará una excepción StopIteration
si su valor de retorno coincide con la palabra centinela.
Cuando llamas a la función, se te pide que ingreses una palabra, luego el código procesa la palabra y te permite ingresar otra palabra. Estas acciones se repiten hasta que ingresas tu centinela, la palabra "done"
.
Cuando se trata de la función next()
, también tendrás dos firmas diferentes que se parecen a esta:
next(iterator)
next(iterator, default)
Nuevamente, has visto cómo usar next()
con un iterable como argumento único. Ahora puedes concentrarte en usar la segunda firma. En este caso, tiene un segundo argumento llamado default
. Este argumento le permite proporcionar el valor que desea devolver cuando el iterable de entrada se agote o se acaben sus datos:
>>> count_down = iter([3, 2, 1])
>>> next(count_down, 0)
3
>>> next(count_down, 0)
2
>>> next(count_down, 0)
1
>>> next(count_down, 0)
0
>>> next(count_down, 0)
0
En este ejemplo, crea un iterador a partir de una lista de números. Luego, usa next()
para consumir el iterador un número a la vez. Después de que next()
haya consumido todo el iterador, obtendrás 0
como resultado porque ese es el valor que pasaste a default
, el segundo argumento posicional. . Las llamadas sucesivas a la función también devolverán 0
.
Iterables de filtrado y mapeo: filter()
y map()
¿Has oído hablar de la programación funcional? Es un paradigma de programación en el que un programa está dominado por llamadas a funciones puras, que son funciones cuyos valores de salida dependen únicamente de sus valores de entrada sin ningún efecto secundario observable.
Python no es lo que se podría llamar un lenguaje de programación funcional. Sin embargo, tiene un par de funciones integradas que son herramientas funcionales clásicas. Estas herramientas son las funciones integradas filter()
y map()
.
Puede utilizar la función filter()
para extraer valores de iterables, lo que se conoce como operación de filtrado.
Nota: Para profundizar en el uso de la función filter()
, consulta el tutorial filter()
de Python: extraer valores de iterables.
La firma de filter()
se parece a esto:
filter(function, iterable)
El primer argumento, function
, debe ser una función de un solo argumento, mientras que el segundo argumento puede ser cualquier iterable de Python. Aquí hay una breve descripción de estos argumentos:
function
Un predicado o función con valor booleano que acepta un solo argumento.
iterable
Un iterable de Python
El argumento function
es una función de decisión, también conocida como función de filtrado. Proporciona los criterios para decidir si se mantiene un valor determinado.
En la práctica, filter()
aplica function
a todos los elementos en iterable
. Luego, crea un iterador que produce solo los elementos que cumplen con los criterios que verifica function
. En otras palabras, produce los elementos que hacen que function
devuelva True
.
La función filter()
le permite procesar iterables sin un bucle formal. A continuación se muestra un ejemplo del uso de filter()
para extraer números pares de una lista de valores:
>>> numbers = [1, 3, 10, 45, 6, 50]
>>> list(filter(lambda n: n % 2 == 0, numbers))
[10, 6, 50]
En este ejemplo, la función lambda
toma un número entero y devuelve True
si el valor de entrada es un número par y False
en caso contrario. La llamada a filter()
aplica esta función lambda
a los valores en numbers
y filtra los números impares, devolviendo los números pares. Tenga en cuenta que utiliza la función list()
para crear una lista a partir del iterador que devuelve filter()
.
Nota: Las funciones anónimas son herramientas comunes en la programación funcional. Python le permite crear este tipo de función usando la palabra clave lambda
. Para obtener más información sobre ellos, consulte Cómo utilizar las funciones Lambda de Python.
Otra herramienta fundamental en la programación funcional es reduce()
, que solía ser una función incorporada, pero ahora está disponible en el módulo functools
. Eche un vistazo a reduce()
de Python: del estilo funcional al pitónico para obtener más información.
La función map()
es otra herramienta común en la programación funcional. Esta función le permite aplicar una función de transformación a todos los valores en un iterable.
Nota: Para obtener más información sobre la función map()
, consulta el tutorial map()
de Python: procesamiento de iterables sin bucle.
El map()
de Python tiene la siguiente firma:
map(function, iterable, *iterables)
La función map()
aplica function
a cada elemento en iterable
en un bucle y devuelve un nuevo iterador que produce elementos transformados a pedido.
Aquí hay un resumen de los argumentos y sus significados:
function
Una función de Python que toma una cantidad de argumentos igual a la cantidad de entradas. iterables
iterable
Un argumento obligatorio que puede contener cualquier iterable de Python.
*iterables
Un número variable de iterables de Python.
El argumento function
es lo que se llama una función de transformación. Aplica una transformación específica a sus argumentos y devuelve un valor transformado.
Para ilustrar cómo funciona map()
, digamos que tiene dos listas. La primera lista contiene una serie de valores que desea utilizar como base en los cálculos de potencia. La segunda lista contiene los exponentes que deseas aplicar a cada base. Puedes usar la función map()
para procesar estas listas y obtener un iterador de poderes:
>>> bases = [8, 5, 2]
>>> exponents = [2, 3, 4]
>>> list(map(pow, bases, exponents))
[64, 125, 16]
En este ejemplo, utiliza la función incorporada pow()
como primer argumento de map()
. Como ya aprendiste, pow()
toma una base y un exponente como argumentos y devuelve la potencia. Luego, pasas las bases y los exponentes a map()
para que calcule las potencias deseadas.
Procesamiento de entrada y salida
Si necesita recibir información del usuario o archivos y presentar la salida al usuario, entonces debe saber que el lenguaje tiene algunas funciones integradas que pueden ayudarlo con estas tareas:
input()
Lee la entrada de la consola.
open()
Abre un archivo y proporciona acceso a un objeto de archivo.
print()
Imprime en una secuencia de texto o en la consola.
format()
Convierte un valor en una representación formateada
En las siguientes secciones, profundizará en el uso de estas funciones para procesar operaciones de entrada y salida en su código Python.
Aceptar información del usuario: input()
Recibir información de sus usuarios es una operación común en aplicaciones CLI y de interfaz basada en texto (TUI). Python tiene una función incorporada que está específicamente dirigida a este tipo de operación. La función se llama convenientemente input()
.
Nota: Para profundizar en el uso de la función input()
, consulta el tutorial Cómo leer la entrada del usuario desde el teclado en Python.
La función incorporada input()
lee la entrada del usuario y la toma como una cadena. Aquí está la firma de la función:
input([prompt])
Los corchetes alrededor de prompt
son una indicación de que este argumento es opcional. Este argumento le permite proporcionar un mensaje para solicitar al usuario la entrada requerida o deseada.
Como ejemplo del uso de input()
, digamos que desea crear un juego de adivinanzas de números. El juego pedirá al usuario que ingrese un número del 1 al 10 y verifique si el valor ingresado coincide con un número secreto.
Aquí está el código del juego:
from random import randint
LOW, HIGH = 1, 10
secret_number = randint(LOW, HIGH)
clue = ""
while True:
guess = input(f"Guess a number between {LOW} and {HIGH} {clue} ")
number = int(guess)
if number > secret_number:
clue = f"(less than {number})"
elif number < secret_number:
clue = f"(greater than {number})"
else:
break
print(f"You guessed it! The secret number is {number}")
En este código, define un bucle infinito en el que solicita al usuario que adivine ingresando un número entre 1 y 10. La primera línea del bucle es una llamada al input()
integrado. función. Ha utilizado un mensaje descriptivo para informar a los usuarios qué hacer.
Continúe y ejecute el script desde su línea de comando para probarlo:
$ python guess.py
Guess a number between 1 and 10 2
Guess a number between 1 and 10 (greater than 2) 3
Guess a number between 1 and 10 (greater than 3) 8
Guess a number between 1 and 10 (less than 8) 6
You guessed it! The secret number is 6
¡Fresco! Su juego le pide al usuario que ingrese un número, lo compara con el número secreto y les permite saber cuándo adivinan correctamente. La función input()
juega un papel central en el flujo del juego, permitiéndote obtener y procesar la entrada del usuario.
Abrir archivos: open()
Leer y escribir en archivos son tareas de programación comunes. En Python, puede utilizar la función incorporada open()
para estos fines. Normalmente se utiliza la función open()
en una declaración with
.
Como ejemplo rápido, supongamos que tiene un archivo de texto con el siguiente contenido:
apple
banana
cherry
orange
mango
Quiere abrir el archivo y leer su contenido mientras lo imprime en la pantalla. Para hacer esto, puede utilizar el siguiente código:
>>> with open("fruits.txt") as file:
... print(file.read())
...
apple
banana
cherry
orange
mango
En esta instrucción with
, llamas a open()
con el nombre del archivo como argumento. Esta llamada abre el archivo para su lectura. La función open()
devuelve un objeto de archivo, que la instrucción with
asigna a las variables file
con as
especificador.
Nota: Para obtener más información sobre cómo trabajar con archivos, consulte el tutorial Lectura y escritura de archivos en Python (Guía).
La función open()
tiene la siguiente firma:
open(
file,
mode="r",
buffering=-1,
encoding=None,
errors=None,
newline=None,
closefd=True,
opener=None,
)
La función puede tomar hasta ocho argumentos. El primer argumento,
Argument | Description | Comment |
---|---|---|
file |
A path-like object holding the path to the target file | It’s a required argument. |
mode |
A string that specifies the mode in which you want to open the file | It defaults to "r" , which is the reading mode. You’ll learn about the available modes in a moment. |
buffering |
An integer that sets the buffering policy | You can pass 0 to switch buffering off, which is only possible in binary mode. You can use 1 to select line buffering, which is only usable in text mode. Finally, you can use an integer greater than 1 to indicate the size in bytes of a fixed-size chunk buffer. |
encoding |
The name of the encoding used to decode or encode the file | You can only use this argument in text mode. |
errors |
A string that specifies how encoding and decoding errors are to be handled | You can only use this argument in text mode. It can take one of the following values: "strict" , "ignore" , "replace" , "surrogateescape" , "xmlcharrefreplace" , "backslashreplace" , or "namereplace" . These values have similar meanings to those you learned in the section about the ord() and chr() functions. |
newline |
A string that determines how to parse newline characters from the stream | It can be None , "" , "\n" , "\r" , or "\r\n" . |
closefd |
A Boolean value that defines whether you want to close a file descriptor | It can be False when you provide a file descriptor instead of a filename and want the descriptor to remain open when the file is closed. Otherwise, it must be True . |
opener |
A callable that you use as a custom opener for the target file | The opener must return an open file descriptor. |
En este tutorial, no cubrirá todos estos argumentos. En su lugar, aprenderá acerca de dos de los argumentos más utilizados, que son mode
y encoding
.
Aquí hay una lista de valores mode
permitidos:
"r"
Abre el archivo para lectura y es el valor predeterminado.
"w"
Abre el archivo para escribir, truncando el archivo primero
"x"
Abre el archivo para creación exclusiva, fallando si el archivo ya existe
"a"
Abre el archivo para escribir, agregando los nuevos datos al final del archivo si ya existe.
"b"
Abre el archivo en modo binario.
"t"
Abre el archivo en modo texto, que es el modo predeterminado.
"+"
Abre el archivo para actualizar, lo que permite operaciones de lectura y escritura.
En esta tabla, los valores "b"
y "t"
definen dos modos genéricos para archivos binarios y de texto, respectivamente. Puede combinar estos dos modos con otros modos. Por ejemplo, el modo "wb"
le permite escribir datos binarios en un archivo, el modo "rt"
le permite leer datos basados en texto de un archivo y pronto.
Tenga en cuenta que "t"
es el modo predeterminado. Entonces, si configura el modo en "w"
, Python asume que desea escribir texto en el archivo de destino.
Aquí hay un fragmento de código que escribe texto en un archivo en su directorio de trabajo:
>>> with open("hello.txt", "w") as file:
... file.write("Hello, World!")
...
13
En este ejemplo, abre un archivo llamado hello.txt
para poder escribir texto en él. En el bloque de código de la instrucción with
, llama al método .write()
en el objeto de archivo para escribir algo de texto. Tenga en cuenta que el método devuelve el número de bytes escritos. Por eso aparece 13
en la pantalla.
Después de ejecutar el código, tendrá el archivo hello.txt
en su directorio de trabajo. Continúe y ábralo para comprobar su contenido.
Puede experimentar con otros modos y tener una idea de cómo funcionan para poder usarlos de forma segura en su código. ¡Toma esto como un ejercicio práctico!
Usar el argumento encoding
es otro requisito típico cuando se trabaja con archivos de texto. En esta situación, se recomienda indicar explícitamente la codificación de texto que está utilizando en su código. La codificación UTF-8 es un ejemplo común de un valor que pasarías a encoding
:
>>> with open("hello.txt", "w", encoding="utf-8") as file:
... file.write("Hello, Pythonista!")
...
13
>>> with open("hello.txt", "r", encoding="utf-8") as file:
... print(file.read())
...
Hello, Pythonista!
En este ejemplo, utiliza la codificación UTF-8 para escribir y leer desde un archivo de texto. Tenga en cuenta que debe utilizar explícitamente el nombre del argumento para proporcionar el valor de codificación. Esto se debe a que el siguiente argumento en la lista es buffering
en lugar de encoding
, y si no usa el nombre explícito, obtendrá un TypeError excepción.
Imprimir texto en la pantalla u otra salida: print()
Otro requisito común que surge cuando se crean aplicaciones CLI o TUI es mostrar información en la pantalla para informar al usuario sobre el estado de la aplicación. En este caso, puede utilizar la función print()
incorporada, que es una herramienta fundamental en la programación de Python.
Nota: Para profundizar en el uso de la función print()
, consulte el tutorial Su guía para la función print()
de Python.
La función print()
tiene la siguiente firma:
print(*objects, sep=" ", end="\n", file=None, flush=False)
Llamar a print()
imprimirá los objetos de entrada en la pantalla de forma predeterminada. Puede utilizar el resto de los argumentos para modificar el funcionamiento de la función. Aquí hay un resumen de los argumentos y su significado:
*objects
Un número arbitrario de objetos Python
sep
La cadena que desea utilizar para separar los objetos de entrada entre sí
end
La cadena que se utilizará después del último objeto de entrada.
file
El objeto de archivo abierto donde desea escribir los objetos de entrada
flush
Un valor booleano que define si desea vaciar el búfer de salida.
Cuando llamas a print()
, toma los objetos
de entrada, los convierte en cadenas, los une usando sep
y agrega end.
. Si llama a print()
sin argumentos, entonces imprime end
. Tenga en cuenta que los argumentos sep
, end
, file
y flush
son argumentos de palabras clave.
A continuación se muestran algunos ejemplos de cómo utilizar la función print()
:
>>> print()
>>> print("Hello")
Hello
>>> print("Hello", "Pythonista!")
Hello Pythonista!
>>> print("Hello", "Pythonista!", sep="\t")
Hello Pythonista!
>>> print("Hello", "Pythonista!", sep="\t", end=" 👋\n")
Hello Pythonista! 👋
Cuando llamas a print()
sin argumentos, end
se imprime en la pantalla. Este argumento por defecto es un carácter de nueva línea, así que eso es lo que obtienes. Con un objeto como argumento, el objeto se imprime, seguido de un carácter de nueva línea. Con varios objetos como argumentos, los argumentos se unen mediante sep
y se agrega una nueva línea al final.
También puedes modificar el valor de end
y hacer que Python imprima algo diferente al final de tu salida.
El argumento file
por defecto es la salida estándar, que es su pantalla. La secuencia sys.stdout
proporciona este valor predeterminado. Sin embargo, puede redirigir la salida a un objeto de archivo de su preferencia:
>>> with open("hello.txt", mode="w") as text_file:
... print("Hello, World!", file=text_file)
...
Este fragmento de código anulará el archivo hello.txt
existente de la sección anterior y escribirá la frase "Hello, World!"
en él.
Finalmente, tiene el argumento flush
que tiene que ver con el almacenamiento en búfer de datos. De forma predeterminada, Python almacena las llamadas a print()
en un búfer de datos RAM. Esto permite a Python realizar menos llamadas al sistema para operaciones de escritura agrupando caracteres en el búfer y escribiéndolos todos a la vez con una sola llamada al sistema.
Puede establecer el argumento flush
en True
si desea que la salida de su código se muestre en tiempo real. Si mantiene flush
en su valor predeterminado de False
, entonces Python almacenará en el buffer la salida, y esa salida solo se mostrará una vez que el buffer de datos esté lleno o cuando finalice su programa. ejecución.
Nota: Para profundizar en cómo vaciar la salida de print()
, consulte el tutorial Cómo vaciar la salida de la función de impresión de Python.
Un buen ejemplo del uso de flush
es cuando necesita crear una barra de progreso para una aplicación CLI. Considere la siguiente función:
def progress(percent=0, width=30):
end = "" if percent < 100 else "\n"
left = width * percent // 100
right = width - left
print(
"\r[",
"#" * left,
" " * right,
"]",
f" {percent:.0f}%",
sep="",
end=end,
flush=True,
)
Esta función genera una barra de progreso horizontal aprovechando el argumento flush
. Así es como puedes usarlo en tu código:
>>> from time import sleep
>>> from progress import progress
>>> for percent in range(101):
... sleep(0.2)
... progress(percent)
...
[########### ] 38%
Este bucle llama a progress()
con valores de progreso hipotéticos sucesivos. El resultado de cada llamada se vacía y la barra de progreso se muestra en la misma línea.
Formato de cadenas: format()
Python tiene un par de herramientas útiles para la interpolación y el formato de cadenas, incluidas f-strings y el método str.format()
. Estas herramientas aprovechan el minilenguaje de formato de cadenas de Python, que le permite formatear bien sus cadenas utilizando una sintaxis dedicada.
La función incorporada format()
es otra herramienta que puede utilizar para formatear valores. La función tiene la siguiente firma:
format(value, format_spec="")
La función convierte value
en una representación formateada. Para definir el formato deseado, puede utilizar el argumento format_spec
, que acepta una cadena que sigue la sintaxis definida en el minilenguaje de formato de cadenas. El argumento format_spec
por defecto es una cadena vacía, lo que hace que la función devuelva el valor tal como se pasó.
Considere los siguientes ejemplos de uso de la función format()
:
>>> import math
>>> from datetime import datetime
>>> format(math.pi, ".4f") # Four decimal places
'3.1416'
>>> format(math.pi, "e") # In scientific notation
'3.141593e+00'
>>> format(1000000, ",.2f") # Thousand separators
'1,000,000.00'
>>> format("Header", "=^30") # Centered and filled
'============Header============'
>>> format(datetime.now(), "%a %b %d, %Y") # Date
'Mon Jul 1, 2024'
En estos ejemplos, ha utilizado varios especificadores de formato diferentes. El especificador ".4f"
formatea el valor de entrada como un número de punto flotante con cuatro decimales. El especificador "e"
le permite formatear el valor de entrada utilizando notación científica.
Nota: Para obtener más información sobre los especificadores de formato, consulte el tutorial Minilenguaje de formato de Python para cadenas ordenadas.
Con el especificador de formato ",.2f"
, puede formatear un número usando comas como separadores de miles y con dos decimales, que es un formato apropiado para valores de moneda. Luego, usa el especificador "=^30"
para formatear la cadena "Header"
centrada en un ancho de 30
caracteres usando el signo igual. como personaje de relleno. Finalmente, usas "%a %b %d, %Y"
para formatear una fecha.
Trabajar con clases, objetos y atributos
Python admite programación orientada a objetos (OOP) con clases, tipos, herencia y muchas otras características relacionadas. En Python todo es un objeto. Entonces, el paradigma de programación orientada a objetos es fundamental para el lenguaje mismo.
Tendrás varias funciones integradas que te ayudarán con diferentes tareas relacionadas con clases, tipos, atributos, métodos, herencia y otros conceptos relacionados con la programación orientada a objetos.
Aquí hay un resumen de las funciones integradas relacionadas con la programación orientada a objetos de Python:
property()
Devuelve el valor de una propiedad de una clase.
classmethod()
Devuelve un método de clase
staticmethod()
Devuelve un método estático
getattr()
Devuelve el valor de un atributo con nombre de un objeto.
setattr()
Establece el valor de un atributo con nombre de un objeto.
delattr()
Elimina un atributo de un objeto.
hasattr()
Devuelve
True
si un objeto tiene un atributo determinadotype()
Devuelve el tipo de un objeto o permite crear nuevas clases dinámicamente
isinstance()
Determina si un objeto es una instancia de una clase determinada.
issubclass()
Determina si una clase es una subclase de una clase determinada.
callable()
Devuelve
True
si un objeto parece ser invocablesuper()
Devuelve un objeto proxy que delega llamadas a métodos a una clase principal o hermana
object()
Crea un nuevo objeto sin características
En las siguientes secciones, aprenderá sobre todas estas funciones y cómo usarlas en su código Python orientado a objetos.
Propiedades del edificio: property()
La función property()
incorporada de Python le permite crear atributos administrados en sus clases. Los atributos administrados, también conocidos como propiedades, tienen un valor asociado y una implementación interna o comportamiento similar a una función.
Para ilustrar esto con un ejemplo, digamos que desea crear una clase Point
. En Python, comenzarás con algo como lo siguiente:
>>> class Point:
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> point = Point(42, 21)
>>> point.x
42
>>> point.y
21
>>> point.x = 0
>>> point.x
0
En esta clase, define dos atributos, .x
y .y
, para representar las coordenadas del punto. Puede acceder y actualizar los atributos directamente utilizando la notación de puntos. Entonces, de ahora en adelante, ambos atributos son parte de la API pública de su clase.
Ahora, digamos que necesita agregar alguna lógica de validación además de .x
y .y
. Por ejemplo, es posible que necesite validar los valores de entrada para ambos atributos. ¿Cómo harías eso? En lenguajes de programación como Java o C++, usarías los métodos getter y setter, que traducidos a Python pueden verse así:
class Point:
def __init__(self, x, y):
self.set_x(x)
self.set_y(y)
def get_x(self):
return self._x
def set_x(self, x):
self._x = self.validate(x)
def get_y(self):
return self._y
def set_y(self, y):
self._y = self.validate(y)
def validate(self, value):
if not isinstance(value, int | float):
raise ValueError("coordinates must be numbers")
return value
En esta nueva implementación de Point
, ha convertido .x
y .y
en atributos no públicos anteponiendo guiones bajos a sus nombres, lo que ahora son ._x
y ._y
. Luego, define los métodos getter y setter para ambos atributos. En los métodos de establecimiento, .set_x()
y .set_y()
, se inserta la lógica de validación definida en el método .validate()
.
Ahora, debes usar la clase como en el siguiente código:
>>> from point_v1 import Point
>>> point = Point(42, 21)
>>> point.get_x()
42
>>> point.get_y()
21
>>> point.set_x(0)
>>> point.get_x()
0
>>> point.set_y("7")
Traceback (most recent call last):
...
ValueError: coordinates must be numbers
Tu clase funciona de manera diferente después de la actualización. En lugar de acceder directamente a los atributos .x
y .y
, debe utilizar los métodos getter y setter. La lógica de validación funciona, lo cual es genial, pero has roto la API de tu clase. Sus usuarios no podrán hacer algo como lo siguiente:
>>> point.x
Traceback (most recent call last):
...
AttributeError: 'Point' object has no attribute 'x'
Los usuarios antiguos de su clase se sorprenderán de que su código no funcione después de actualizar a su nueva versión de Point
. Entonces, ¿cómo se puede evitar este tipo de problemas? El enfoque Pythonic consiste en convertir atributos públicos en propiedades en lugar de utilizar métodos getter y setter.
Puede utilizar la función incorporada property()
para realizar esta conversión. Así es como puedes mantener la API de tu clase Point
sin cambios:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = self.validate(value)
@property
def y(self):
return self._y
@y.setter
def y(self, value):
self._y = self.validate(value)
def validate(self, value):
if not isinstance(value, int | float):
raise ValueError("coordinates must be numbers")
return value
Punto
ahora se ve un poco diferente. No tiene métodos getter y setter formales. En cambio, tiene algunos métodos decorados con @property
. Sí, la función incorporada property()
se utiliza principalmente como decorador.
Los métodos que decoras con @property
son equivalentes a los métodos getter. Mientras tanto, los métodos que decoras con el nombre del getter más .setter()
son equivalentes a los métodos setter. Lo bueno de las propiedades es que aún puedes usar los atributos como atributos normales:
>>> from point_v2 import Point
>>> point = Point(42, 21)
>>> point.x
42
>>> point.y
21
>>> point.x = 0
>>> point.x
0
>>> point.x = "7"
Traceback (most recent call last):
...
ValueError: coordinates must be numbers
Al convertir atributos regulares en propiedades, puede agregarles un comportamiento similar a una función sin perder la capacidad de usarlos como atributos regulares. Las propiedades le evitan introducir cambios importantes en la API pública de su código, para que no rompa el código de sus usuarios.
Creación de clases y métodos estáticos: classmethod()
y staticmethod()
Las clases le permiten definir piezas de código reutilizables que encapsulan datos y comportamiento en una sola entidad. Por lo general, los datos se almacenan en atributos, que son variables definidas dentro de las clases. Cuando se trata de comportamientos, usarás métodos, que son funciones definidas en clases.
En Python, tienes tres tipos diferentes de métodos:
- Métodos de instancia, que toman el objeto actual como primer argumento.
- Métodos de clase, que toman la clase actual como primer argumento.
- Métodos estáticos, que no toman ni la instancia actual ni la clase actual como argumentos
Los métodos de instancia deben tomar la instancia actual como argumento. Por convención, este argumento se llama self
en Python.
Para crear un método de clase, necesita decorar el método con el decorador @classmethod
. De manera similar, para crear un método estático, debe decorar el método con el decorador @staticmethod
. Ambos decoradores son parte de las funciones integradas de Python.
Un caso de uso común para los métodos de clase es proporcionar múltiples constructores para una clase. Para ilustrar cómo escribir un método de clase, digamos que desea una clase Point
que pueda construir utilizando coordenadas cartesianas o polares. En esta situación, puede hacer algo como lo siguiente:
import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def from_polar(cls, distance, angle):
return cls(
x=distance * math.cos(math.radians(angle)),
y=distance * math.sin(math.radians(angle)),
)
En este ejemplo, el método .from_polar()
es un método de clase. Toma la clase actual como primer argumento, que normalmente se llama cls
por convención. El método devuelve una nueva instancia de la clase calculando las coordenadas cartesianas a partir de las coordenadas polares.
Así es como puedes utilizar este método en la práctica:
>>> from point import Point
>>> point = Point.from_polar(20, 15)
>>> point.y
5.176380902050415
>>> point.x
19.318516525781366
En este fragmento de código, crea una nueva instancia Point
utilizando el método de clase .from_polar()
. En el ejemplo, llama al método en la clase en lugar de en una instancia para indicar que se trata de un método de clase. También puedes llamar a un método de clase en una instancia de su clase contenedora.
El tercer tipo de método es el método estático. Un método estático no toma la instancia o clase actual como argumento. Estos métodos son como funciones regulares que decides incluir en una clase determinada por conveniencia. Funcionalmente, también podrían definirse como funciones regulares en un módulo.
Por ejemplo, considere la siguiente clase Formatter
:
class Formatter:
@staticmethod
def as_currency(value):
return f"${value:,.2f}"
@staticmethod
def as_percent(value):
return f"{value:.2%}"
Esta clase define dos métodos estáticos. El primer método toma un valor numérico y lo formatea como valor de moneda. El segundo método toma un valor numérico y lo expresa como porcentaje. Podría haber definido estos métodos como funciones regulares a nivel de módulo. Sin embargo, los ha definido en una clase como una forma de agruparlos convenientemente según cómo se utilizarán.
Puede utilizar esta clase como en los siguientes ejemplos:
>>> from formatting import Formatter
>>> Formatter.as_currency(1000)
'$1,000.00'
>>> Formatter.as_percent(0.75)
'75.00%'
>>> formatter = Formatter()
>>> formatter.as_currency(1000)
'$1,000.00'
>>> formatter.as_percent(0.8)
'80.00%'
Puede utilizar métodos estáticos llamándolos a la clase o a una de sus instancias. En este ejemplo, la clase Formatter
funciona como un espacio de nombres donde defines métodos relacionados para mayor comodidad. Sin embargo, puede obtener el mismo resultado definiendo los métodos como funciones a nivel de módulo.
Gestión de atributos: getattr()
, setattr()
y delattr()
A veces, es posible que necesites acceder, configurar o eliminar atributos de tus objetos en Python. En la mayoría de los casos, puede realizar estas operaciones directamente utilizando la notación de puntos, el operador de asignación y la instrucción del
.
En otras situaciones, sólo conoces los nombres de los atributos en tiempo de ejecución, por lo que no puedes acceder a ellos con la sintaxis normal. En estos casos, puede utilizar las funciones integradas getattr()
, setattr()
y delattr()
. Estas funciones tienen las siguientes firmas:
getattr(object, name)
getattr(object, name, default)
setattr(object, name, value)
delattr(object, name)
En todos los casos, el argumento object
debe tomar una instancia de una clase existente. De manera similar, name
debe ser el nombre de un atributo o método como una cadena.
En la segunda firma de getattr()
, el argumento default
es un valor opcional que obtendrá si el atributo deseado no existe en el objeto de destino.
En la firma de setattr()
, el argumento value
debe contener el nuevo valor que desea asignar a un argumento determinado.
Para ilustrar cómo funcionan estas funciones, considere la siguiente clase:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
Esta clase tiene dos atributos de instancia, .name
y .age
. A continuación se explica cómo puede acceder, configurar o eliminar los atributos utilizando sus nombres como cadenas:
>>> from person import Person
>>> jane = Person("Jane", 25)
>>> getattr(jane, "name")
'Jane'
>>> getattr(jane, "age")
25
En estos ejemplos, utiliza getattr()
para recuperar los valores almacenados en .name
y .age
. El primer argumento de esta función es el objeto del que necesita recuperar un atributo. El segundo argumento es el nombre del atributo como una cadena.
Ahora diga que desea actualizar la edad de Jane. Puedes hacer esto usando la función setattr()
:
>>> setattr(jane, "age", 26)
>>> jane.age
26
Luego, utiliza la función setattr()
para asignar un nuevo valor al atributo .age
. Esta función toma tres argumentos: el objeto, el nombre del atributo y el nuevo valor.
Finalmente, puedes usar la función incorporada delattr()
para eliminar un atributo de un objeto determinado:
>>> delattr(jane, "age")
>>> jane.age
Traceback (most recent call last):
...
AttributeError: 'Person' object has no attribute 'age'
La función delattr()
toma el objeto como primer argumento y el nombre del atributo como segundo argumento. Después de llamar a la función, intentar acceder a .age
generará una excepción AttributeError
.
Nota: Para obtener más información sobre cómo eliminar objetos en Python, consulte el tutorial del
de Python: eliminar referencias de ámbitos y contenedores.
En la práctica, las funciones integradas getattr()
, setattr()
y delattr()
resultan útiles cuando es necesario manipular atributos. usando sus nombres como cadenas. Por ejemplo, digamos que desea crear una clase FileProcessor
para leer y escribir archivos CSV y JSON. En esta situación, puede tener clases dedicadas para procesar cada tipo de archivo:
import csv
import json
class CSVProcessor:
def __init__(self, filename):
self.filename = filename
def read(self):
with open(self.filename, encoding="utf-8", newline="") as file:
return list(csv.DictReader(file))
def write(self, data):
with open(
self.filename, mode="w", encoding="utf-8", newline=""
) as file:
writer = csv.DictWriter(file, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
class JSONProcessor:
def __init__(self, filename):
self.filename = filename
def read(self):
with open(self.filename, encoding="utf-8") as file:
return json.load(file)
def write(self, data):
with open(self.filename, mode="w", encoding="utf-8") as file:
json.dump(data, file, indent=2)
En este archivo processors.py
, define dos clases que pueden procesar archivos CSV y JSON, respectivamente. Ambas clases tienen los métodos .read()
y .write()
. Estas clases se ven bien, pero ahora necesitas hacerlas utilizables desde tu clase FileProcessor
.
Para escribir la clase FileProcessor
, puedes utilizar una técnica llamada delegación, que consiste en evaluar el atributo o método de un objeto en el contexto de otro objeto. Así es como puedes hacer esto en Python:
# ...
class FileProcessor:
def __init__(self, filename, processor):
self.filename = filename
self.processor = processor(filename)
def __getattr__(self, attr):
return getattr(self.processor, attr)
En esta clase, usted define el método especial .__getattr__()
. Este método admite operaciones de acceso a atributos en clases de Python. En la definición del método, utiliza la función getattr()
para acceder a atributos y métodos desde el objeto procesador proporcionado.
En la práctica, se utiliza la combinación del método .__getattr__()
y la función getattr()
para implementar la delegación. La clase FileProcessor
delega el procesamiento de archivos a la clase de procesador concreta que usted pasa durante la creación de instancias.
Así es como puedes usar la clase FileProcessor
en tu código:
>>> from processors import FileProcessor
>>> file_proc = FileProcessor("products.csv", CSVProcessor)
>>> file_proc.read()
[
{'product': 'Laptop', 'price': '1200', 'sold_units': '30'},
{'product': 'Phone', 'price': '700', 'sold_units': '50'},
{'product': 'Tablet', 'price': '450', 'sold_units': '100'},
{'product': 'Desktop', 'price': '1000', 'sold_units': '20'},
{'product': 'Monitor', 'price': '300', 'sold_units': '50'}
]
En este código, crea una instancia FileProcessor
para procesar un archivo CSV con CSVProcessor
. Aunque la instancia no tiene un método .read()
, puedes llamar al método debido a la técnica de delegación que se basa en la función getattr()
.
Comprobando atributos: hasattr()
Otra función integrada estrechamente relacionada con atributos y métodos es la función hasattr()
. Esta función le permite verificar si un objeto determinado tiene un determinado atributo o método. La función tiene la siguiente firma:
hasattr(object, name)
En esta firma, el argumento object
puede tomar cualquier objeto de Python, mientras que el argumento name
debe contener el nombre de un atributo como una cadena. Esta función es un predicado que devuelve True
si el objeto tiene un atributo con el nombre proporcionado y False
en caso contrario.
En la práctica, puede utilizar esta función para comprobar si un objeto tiene un atributo o método determinado antes de intentar utilizarlo. Por ejemplo, digamos que tiene las siguientes clases:
class Duck:
def fly(self):
print("The duck is flying")
def swim(self):
print("The duck is swimming")
class Pigeon:
def fly(self):
print("The pigeon is flying")
Estas clases representan dos aves diferentes. Ambas aves son capaces de volar, pero sólo el pato es capaz de nadar. Ahora digamos que desea usarlos en un bucle como el siguiente:
>>> from birds import Duck, Pigeon
>>> birds = [Duck(), Pigeon()]
>>> for bird in birds:
... bird.fly()
... bird.swim()
...
The duck is flying
The duck is swimming
The pigeon is flying
Traceback (most recent call last):
...
AttributeError: 'Pigeon' object has no attribute 'swim'
Este bucle funciona para la instancia de Duck
. Sin embargo, genera una excepción AttributeError
cuando llamas a .swim()
en una instancia de Pigeon
porque la clase no tiene este método. Para evitar este error, puede utilizar la función hasattr()
para comprobar si el método existe antes de llamarlo:
>>> for bird in birds:
... bird.fly()
... if hasattr(bird, "swim"):
... bird.swim()
...
The duck is flying
The duck is swimming
The pigeon is flying
Su código no falla ahora porque ha utilizado la función hasattr()
para asegurarse de que el pájaro actual tenga el método .swim()
antes de llamarlo.
Creación y verificación de tipos: type()
, isinstance()
y issubclass()
Python es un lenguaje de tipado dinámico, lo que significa que Python verifica los tipos solo mientras se ejecuta el código, y el tipo de una variable puede cambiar a lo largo de su vida. Debido a esta característica del lenguaje, es posible que necesites verificar explícitamente el tipo de un objeto antes de usarlo para que tu código no falle.
Nota: Debido a que Python es un lenguaje de escritura dinámica, se prefiere el estilo de escritura pato a la verificación de tipos explícita. Para obtener más información sobre la escritura de pato, consulte el tutorial Escritura de pato en Python: escritura de código flexible y desacoplado.
Para conocer el tipo de un objeto determinado, puede utilizar la función incorporada type()
:
>>> type(42)
<class 'int'>
>>> type(2.75)
<class 'float'>
>>> type("Hello")
<class 'str'>
Cuando llamas a type()
con cualquier clase de Python como argumento, obtienes el tipo del objeto, al que también puedes llamar la clase del objeto. En este ejemplo, llamas a type()
con un número entero como argumento y obtienes la clase int
como respuesta. Luego, usas type()
con un número de punto flotante y obtienes la clase float
, y así sucesivamente.
Si desea verificar el tipo de un objeto con type()
, puede hacer algo como lo siguiente:
>>> type(42) == int
True
>>> type(42) == float
False
Esta forma de usar type()
funciona. Sin embargo, no es el enfoque recomendado. Aprenderá más sobre la verificación de tipos en un momento. Por ahora, seguirás aprendiendo los conceptos básicos de type()
. Para comenzar, aquí están las firmas de la función:
type(object)
type(name, bases, dict, **kwds)
Ya has utilizado la primera firma. En esta firma, el argumento object
representa cualquier objeto de Python.
La segunda firma es un poco más complicada. Utilizará esta firma para crear nuevas clases dinámicamente en lugar de determinar el tipo de objeto. Aquí hay un resumen de los argumentos y su significado:
name
El nombre de la clase.
base
Una tupla que contiene las clases base.
dict
Un diccionario de atributos y métodos definidos en el cuerpo de la clase.
**kwds
Argumentos de palabras clave adicionales que se pasan al constructor de metaclase
Cuando usas type()
con estos argumentos, puedes crear clases dinámicamente. De esta manera, type()
es una forma dinámica de la declaración class
. Considere el siguiente ejemplo de juguete:
>>> def greet(self):
... print("Hello, World!")
...
>>> DemoClass = type("DemoClass", (), {"value": 42, "greet": greet})
>>> DemoClass.value
42
>>> instance = DemoClass()
>>> instance.value
42
>>> instance.greet()
Hello, World!
>>> dir(instance)
[
'__class__',
'__delattr__',
'__dict__',
...
'greet',
'value'
]
En este ejemplo rápido, utiliza type()
para crear una clase de demostración que hereda automáticamente de object
porque la tupla base
está vacía. La nueva clase tendrá un método llamado .greet()
, que habrás definido de antemano. También tiene un atributo de clase llamado .value
que estableces en 42
.
Para los atributos, debe proporcionar el nombre del atributo como una cadena y el valor del atributo. Para los métodos, debe proporcionar el nombre del método como una cadena y un objeto de método, que es un método sin paréntesis de llamada. Tenga en cuenta que los métodos de instancia como .greet()
deben tomar el objeto actual como argumento, al que normalmente llama self
.
Para ver un ejemplo más realista, supongamos que desea escribir una función que le permita crear clases dinámicamente a partir de diferentes esquemas de datos. En esta situación, puede hacer algo como lo siguiente:
def create_class(name, custom_members):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def __repr__(self):
return f"{name}({self.__dict__})"
class_members = {
"__init__": __init__,
"__repr__": __repr__,
}
class_members.update(custom_members)
return type(name, (), class_members)
En este código, creas una función que toma dos argumentos. El primer argumento, name
, debe ser una cadena que proporcione un nombre de clase válido. El segundo argumento, custom_members
, debería ser un diccionario de atributos y métodos.
Luego, define una función interna llamada .__init__()
, que usará como inicializador de clase. La función .__repr__()
le permitirá proporcionar una representación de cadena para los objetos de su clase.
A continuación, crea un diccionario para incluir las funciones como métodos para su clase y actualiza el diccionario con el contenido de class_members
, que debe provenir del usuario.
Finalmente, utiliza la función type()
para generar la clase con el nombre proporcionado y el diccionario de miembros. A continuación se muestran un par de ejemplos de cómo utilizar esta función:
>>> from factory import create_class
>>> User = create_class("User", {"name": "", "age": 0, "email": ""})
>>> Product = create_class(
... "Product", {"name": "", "price": 0.0, "units": 0}
... )
>>> john = User(name="John", age=30, email="john@example.com")
>>> table = Product(name="Table", price=200.0, units=5)
>>> john.name
'John'
>>> john.age
30
>>> john.email
'john@example.com'
>>> table.name
'Table'
>>> table.price
200.0
>>> table.units
5
En este fragmento de código, primero crea dos clases usando create_class()
. La primera clase representa a los usuarios y la segunda representa los productos. Ambos tienen diferentes conjuntos de atributos de instancia.
Luego, crea instancias concretas de cada clase con valores adecuados para los atributos. Finalmente, accede a los atributos utilizando la notación de puntos. ¡Genial! Tus clases funcionan como se esperaba.
La función type()
es una gran herramienta para crear clases dinámicamente. Aunque también puede utilizar esta función para comprobar el tipo de un objeto, la herramienta recomendada para la comprobación explícita de tipos es la función incorporada isinstance()
porque tiene en cuenta las subclases.
La firma para isinstance()
es como la siguiente:
isinstance(object, classinfo)
En esta firma, object
representa cualquier objeto de Python que le interese. El argumento classinfo
es la clase o clases con las que desea comparar. Este argumento puede ser un objeto de clase única, una tupla de objetos de clase o un tipo de unión.
Considere los siguientes ejemplos en los que utiliza isinstance()
para comprobar valores numéricos:
>>> isinstance(42, int)
True
>>> isinstance(42.0, (int, float))
True
>>> isinstance(42.0, int | float)
True
En el primer ejemplo, utiliza isinstance()
para comprobar si 42
es una instancia de la clase int
. En el segundo ejemplo, utiliza isinstance()
para comprobar si 42.0
es una instancia de int
o float
. . En este ejemplo, utiliza una tupla de clases para proporcionar el argumento classinfo
.
Finalmente, en el tercer ejemplo, realiza la misma verificación que en el segundo ejemplo. Esta vez, utiliza el carácter de barra vertical (|
) para crear un tipo de unión con int
y float
. Tenga en cuenta que isinstance()
es una función predicada que devuelve True
si el objeto de entrada es una instancia de una de las clases proporcionadas.
La función isinstance()
también considera subclases. Por ejemplo, la clase bool
es una subclase de int
, por lo que si comparas una instancia de bool
con int
, entonces obtendrás True
como resultado:
>>> isinstance(False, int)
True
>>> type(False) == int
False
Debido a que bool
es una subclase de int
, la función isinstance()
devuelve True
cuando compara un valor booleano con la clase int
. Tenga en cuenta que si intenta hacer una verificación similar con type()
, obtendrá False
porque type()
no considera subclases.
Hay otra función incorporada que puede resultar útil para la verificación de tipos. La función se llama issubclass()
y verifica si una clase determinada es una subclase de otra clase:
>>> issubclass(int, object)
True
>>> issubclass(bool, int)
True
>>> issubclass(int, float)
False
En el primer ejemplo, verifica si la clase int
es una subclase de object
. En este caso, obtienes True
porque todas las clases de Python derivan de object
. Luego, verificas si bool
es una subclase de int
, lo cual también es cierto, como ya aprendiste.
En el ejemplo final, usas issubclass()
para comprobar si int
es una subclase de float
, que es False
>.
La firma de issubclass()
es la siguiente:
issubclass(class, classinfo)
En este caso, el argumento class
es la clase que desea verificar, mientras que el argumento classinfo
funciona igual que en isinstance()
.
Comprobando objetos invocables: callable()
Un invocable en Python es cualquier objeto al que puedas llamar usando un par de paréntesis y una serie de argumentos si es necesario. En Python, los objetos invocables incluyen funciones, clases, métodos, instancias de clases con un método .__call__()
, cierres y funciones generadoras.
A veces, es posible que necesites saber si un objeto es invocable antes de llamarlo en tu código. Para hacer esto, puede usar la función incorporada callable()
, que toma un objeto como argumento y devuelve True
si el objeto parece ser invocable. De lo contrario, devuelve False
.
A continuación se muestran algunos ejemplos del uso de callable()
con algunos objetos integrados:
>>> callable(abs)
True
>>> callable(int)
True
>>> callable(list)
True
>>> callable(True)
False
>>> callable(None)
False
En los primeros tres ejemplos, los argumentos de callable()
son todos funciones, por lo que obtienes True
como resultado. En los dos últimos ejemplos, utiliza los objetos True
y None
como argumentos. Estos objetos no son invocables, por lo que obtienes False
como resultado.
Como ejemplo práctico, digamos que necesita crear una aplicación que procese comandos. Cada comando debe poder invocarse; de lo contrario, no será válido. Para comprobar esta condición, puede utilizar callable()
. Aquí hay una implementación de juguete:
class CommandProcessor:
def __init__(self):
self.commands = {}
def register_command(self, command):
if not callable(command):
raise ValueError("command is not callable")
self.commands[command.__name__] = command
def execute_command(self, name, *args, **kwargs):
if (command := self.commands.get(name)) is None:
raise ValueError(f"command '{name}' not found")
return command(*args, **kwargs)
En esta clase, el método .register_command()
usa callable()
para verificar si el comando de entrada es un objeto invocable. Si ese es el caso, entonces registra el comando como válido. A continuación, tiene el método .execute_command()
que ejecuta el comando como invocable.
A continuación se muestra un ejemplo de cómo utilizar esta clase:
>>> from commands import CommandProcessor
>>> command_processor = CommandProcessor()
>>> def add(a, b):
... return a + b
...
>>> command_processor.register_command(add)
>>> command_processor.execute_command("add", 1, 2)
3
>>> subtract = 3 - 2
>>> command_processor.register_command(subtract)
Traceback (most recent call last):
...
ValueError: command is not callable
En este ejemplo, creará una instancia CommandProcessor
para procesar comandos. Luego, escribes add()
para usarlo como comando. Debido a que add()
es un objeto invocable, puede registrarlo como un comando válido y ejecutarlo con el método .execute_command()
.
Finalmente, define la variable resta
para contener el resultado de una operación de resta. Esta variable no se puede llamar. Por lo tanto, obtienes una excepción ValueError
al registrarlo como un comando.
Accediendo a los miembros de los padres: super()
Cuando trabajas con herencia en clases de Python, a menudo necesitarás acceder a los atributos o métodos de una clase principal en una subclase. La forma Pythonic de hacer esto es utilizar la función incorporada super()
.
Nota: Para obtener más información sobre super()
, consulte el tutorial Cómo potenciar sus clases con Python super()
.
Un caso de uso común para super()
es cuando necesita crear una subclase de una clase existente y necesita una forma adecuada de inicializar los atributos de la clase principal. Considere las siguientes clases que representan un rectángulo y un cuadrado:
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return 2 * (self.length + self.width)
class Square(Rectangle):
def __init__(self, side):
super().__init__(side, side)
En este código, define una clase Rectangle
con dos atributos, .length
y .width
. También tiene dos métodos para calcular el área y el perímetro del rectángulo. A continuación, define la clase Square
. Dado que un cuadrado es un tipo de rectángulo con lados iguales, tiene sentido crear Square
como una subclase de Rectangle
y reutilizar la funcionalidad que ya implementó.
En el constructor Square()
, solo necesita un único argumento para representar la longitud del lado. Puede usar este argumento para inicializar la clase principal usando super()
como lo hizo en la línea resaltada. La función super() le da acceso a la clase principal Rectangle
. Una vez que tenga acceso a la clase, puede llamar a su método .__init__()
para inicializar los atributos .length
y .width
con el valor. del
Construyendo objetos genéricos: object()
En Python, cada clase hereda implícitamente de la clase object
, que está integrada en el lenguaje. En otras palabras, la clase object
es la clase base para cada clase en Python:
>>> issubclass(int, object)
True
>>> issubclass(float, object)
True
>>> issubclass(bool, object)
True
>>> issubclass(dict, object)
True
>>> class DemoClass:
... pass
...
>>> issubclass(DemoClass, object)
True
No importa si la clase que estás considerando es una clase integrada o personalizada, hereda de object
.
En algunas situaciones, es posible que desee crear instancias de la clase object
. Para hacer esto, puede usar la función incorporada object()
, que en realidad es un constructor de clases en lugar de una función, pero la documentación de Python la incluye entre sus funciones incorporadas.
La función object()
no toma ningún argumento y devuelve un nuevo objeto sin características, que tiene los métodos que son comunes a todos los objetos de Python. A diferencia de los objetos normales, el objeto que se obtiene al llamar a object()
no tiene un atributo .__dict__
, por lo que no puedes agregar atributos dinámicamente a este tipo de objeto. :
>>> obj = object()
>>> dir(obj)
[
'__class__',
'__delattr__',
'__dir__',
...
'__str__',
'__subclasshook__'
]
>>> obj.attr = "Some value"
Traceback (most recent call last):
...
AttributeError: 'object' object has no attribute 'attr'
En este ejemplo, crea un nuevo objeto sin características llamando a object()
. Con la función incorporada dir()
, puede enumerar todos los métodos y atributos que proporciona este objeto. Finalmente, si intenta agregar un atributo a su objeto sin características de forma dinámica, obtendrá una excepción AttributeError
.
En la práctica, puede utilizar la función object()
cuando desee crear valores centinela únicos. Un valor centinela es un marcador único que puede utilizar para indicar la ausencia de un valor. También puede utilizarlo como condición para detener algoritmos iterativos o recursivos.
Para ilustrar cómo utilizar object()
para crear un valor centinela, considere la siguiente clase Circle
:
from time import sleep
SENTINEL = object()
class Circle:
def __init__(self, radius):
self.radius = radius
self._diameter = SENTINEL
@property
def diameter(self):
if self._diameter is SENTINEL:
sleep(0.5) # Simulate a costly computation
self._diameter = self.radius * 2
return self._diameter
En esta clase, tiene un atributo .radius
que toma un valor en el momento de la creación de instancias. Luego, tiene un atributo no público llamado ._diameter
que inicializa con la constante SENTINEL
. Para crear esta constante, utiliza la función object()
.
Finalmente, tiene la propiedad .diameter
, que calcula el diámetro a partir del radio proporcionado. En este ejemplo, utiliza sleep()
del módulo time
para simular que encontrar el diámetro es una operación costosa. Debido al costo de cálculo, decide almacenar en caché el diámetro para que se calcule una sola vez durante la vida del objeto.
Para comprobar si el diámetro ya se calculó, compare su valor actual con la constante SENTINEL
. En este ejemplo, también podrías haber usado Ninguno
como valor centinela porque es poco probable que el diámetro de un círculo tome un valor nulo. Sin embargo, cuando Ninguno
puede ser un valor válido para el atributo en cuestión, entonces object()
puede ser el camino a seguir.
Trabajar con ámbitos de Python
Python, como muchos otros lenguajes de programación, gestiona el concepto de ámbitos. El alcance rige cómo se buscan las variables y los nombres en su código. Determina la visibilidad de una variable o nombre dentro del código.
El alcance depende del lugar donde creas esa variable. Los alcances de Python siguen una regla conocida como regla LEGB. Las letras de este acrónimo significan ámbitos local, enclosing, global e integrado, y esta regla Resume los cuatro ámbitos que encontrarás en Python.
Nota: Para profundizar en los alcances de Python, consulte el tutorial Alcance de Python y regla LEGB: resolución de nombres en su código.
Encontrará dos funciones integradas que están estrechamente relacionadas con los ámbitos en Python. Estas funciones se enumeran en la siguiente tabla:
locals()
Actualiza y devuelve un diccionario que representa la tabla de símbolos local actual.
globals()
Devuelve un diccionario que representa la tabla de símbolos global actual.
En las siguientes secciones, aprenderá los conceptos básicos de estas funciones y cómo usarlas en su código Python para administrar algunos aspectos de sus alcances de nombres.
Inspeccionar y actualizar un ámbito local: locals()
El alcance local es el alcance de la función porque comprende el cuerpo de la función. Cada vez que llamas a una función, Python crea un nuevo alcance local para esa función. De forma predeterminada, los argumentos y nombres que asignas en el cuerpo de una función existen solo dentro del alcance local que Python crea cuando llamas a la función. Cuando la función regresa, el alcance local desaparece y los nombres se olvidan.
Si alguna vez necesita inspeccionar el estado de su alcance local actual, puede usar la función incorporada locals()
:
>>> def add(a, b):
... result = a + b
... print(locals())
... return result
...
>>> add(2, 5)
{'a': 2, 'b': 5, 'result': 7}
7
En esta función, tomas dos argumentos, a
y b
. Estos argumentos son locales para add()
, lo que significa que solo puedes acceder a ellos y usarlos dentro de la función. Luego, crea una variable local llamada result
, que utiliza como variable temporal para almacenar los resultados del cálculo. La llamada a locals()
devuelve un diccionario que contiene los nombres y valores de todas estas variables.
Tenga en cuenta que locals()
toma la información del alcance solo hasta el punto en el que la llama:
>>> def add(a, b):
... print(locals())
... result = a + b
... return result
...
>>> add(2, 5)
{'a': 2, 'b': 5}
7
En esta variación de add()
, llamas a locals()
al comienzo de la función. Entonces, solo obtienes los argumentos en el diccionario de resultados. Esto se debe a que cuando llamas a locals()
, la variable result
aún no se ha definido.
Inspeccionar y actualizar el alcance global: globals()
El alcance global es otro alcance importante en Python. Es el alcance a nivel de módulo y le permite definir variables o nombres globales. Puede acceder y modificar nombres globales desde cualquier lugar de su código.
Para inspeccionar y actualizar las variables y nombres que se encuentran en su alcance global actual, puede utilizar la función incorporada globals()
. Por ejemplo, cuando inicia una nueva sesión REPL y llama a globals()
, obtiene un resultado como el siguiente:
>>> globals()
{
'__name__': '__main__',
'__doc__': None,
...
'__builtins__': <module 'builtins' (built-in)>
}
De forma predeterminada, cuando inicia una sesión REPL, el intérprete carga varios nombres y objetos en su ámbito global. Por ejemplo, el objeto __name__
contiene el nombre del módulo actual, que es "__main__"
cuando estás en un módulo ejecutable. Si está en un módulo importado, esta variable contendrá el nombre del módulo.
Luego, tiene el nombre __doc__
, que contendrá la cadena de documentación del módulo, si se proporciona. También tendrás varios otros nombres. Finalmente, tiene el nombre __builtins__
, que contiene el espacio de nombres donde se definen los nombres integrados. Este es un módulo especial que incluye todas las funciones integradas cubiertas en este tutorial y varios otros objetos integrados, como excepciones.
Si comienza a definir variables y funciones en su sesión REPL, estos nombres se agregarán al diccionario que devuelve globals()
:
>>> language = "Python"
>>> number = 42
>>> def greet():
... print("Hello, World!")
...
>>> class Demo:
... pass
...
>>> globals()
{
...
'__builtins__': <module 'builtins' (built-in)>,
'language': 'Python',
'number': 42,
'greet': <function greet at 0x100984040>,
'Demo': <class '__main__.Demo'>
}
En este ejemplo, define dos variables, una función y una clase. Cuando llamas a globals()
, obtienes los nombres de todos esos objetos al final del diccionario resultante.
El diccionario que devuelve globals()
es un diccionario grabable. Puede aprovechar esta función cuando necesite modificar o actualizar el contenido del alcance global manualmente. Un caso de uso común para esta función es cuando necesita cargar parámetros de configuración desde un archivo.
Por ejemplo, digamos que tiene el siguiente archivo JSON con algunos valores de configuración para su conexión de base de datos:
{
"DATABASE_URL": "postgres://user:pass@localhost/dbname",
"DEBUG_MODE": true,
"MAX_CONNECTIONS": 10
}
Debe escribir una función que cargue este archivo y agregue los parámetros de configuración proporcionados a su alcance global actual. Aquí hay una posible implementación de esta función:
import json
def load_config(config_file):
with open(config_file) as file:
config = json.load(file)
globals().update(config)
En esta función, primero abre el archivo de configuración y carga su contenido en un diccionario llamado config
. Luego, actualiza el diccionario que globals()
devuelve con el contenido de config
.
Así es como funciona la función anterior:
>>> from config import load_config
>>> load_config("config.json")
>>> globals()
{
...
'DATABASE_URL': 'postgres://user:pass@localhost/dbname',
'DEBUG_MODE': True,
'MAX_CONNECTIONS': 10
}
>>> MAX_CONNECTIONS
10
Después de llamar a load_config()
con el archivo config.json
como argumento, obtendrás los parámetros de configuración cargados como constantes en tu alcance global. Ahora puedes usar estas constantes directamente en tu código.
Introspección de objetos
En programación, la introspección de tipos es la capacidad de un programa de inspeccionar el tipo y las propiedades de un objeto en tiempo de ejecución. Todo en Python es un objeto, por lo que poder examinar tipos y propiedades en tiempo de ejecución es un activo valioso.
Aquí hay algunas funciones integradas que le permiten realizar algún tipo de introspección de tipos en Python:
id()
Devuelve la identidad de un objeto.
dir()
Devuelve una lista de nombres en el ámbito local actual o una lista de atributos de objeto
vars()
Devuelve el atributo
__dict__
para un módulo, clase u objeto.
En las siguientes secciones, aprenderá cómo funcionan estas funciones y cómo puede usarlas en el código para realizar una introspección de tipos. Para comenzar, comenzará con la función id()
.
Conocer la identidad de un objeto: id()
En Python, cada objeto individual tiene una identidad asociada. Esta identidad es un número entero único y constante que identifica el objeto durante su vida. Dos objetos con tiempos de vida que no se superponen pueden tener la misma identidad.
Si alguna vez necesita conocer la identidad de un objeto determinado, puede utilizar la función id()
con el objeto como argumento:
>>> id(42)
4315605776
>>> id("Python")
4315120464
>>> def greet():
... print("Hello, World!")
...
>>> id(greet)
4307259040
>>> class Demo:
... pass
...
>>> id(Demo)
4892672720
Cuando llamas a id()
con cualquier objeto Python como argumento, obtienes un número que es la identidad del objeto. En la implementación CPython de Python, la identidad de un objeto es también la dirección de memoria donde vive ese objeto.
Conocer la identidad de un objeto puede ser de gran ayuda al depurar su código. Por ejemplo, digamos que desea escribir código que calcule valores individuales a partir de una especie de secuencia de Fibonacci. Puedes hacer esto de muchas maneras. Sin embargo, piensa en usar una clase con instancias invocables y un atributo de instancia que le permita almacenar en caché los valores ya calculados.
Aquí hay una posible implementación de esta clase:
class Fibonaccish:
def __init__(self, initial_value=1):
self._cache = [0, initial_value]
def __call__(self, index):
if index < len(self._cache):
fib_number = self._cache[index]
print(f"{index} {fib_number} id = {id(fib_number)}")
else:
fib_number = self(index - 1) + self(index - 2)
self._cache.append(fib_number)
return fib_number
En el método inicializador de Fibonaccish
, usted define una lista para contener el caché de los valores calculados. Luego, define el método especial .__call__()
, que permite que las instancias de su clase sean invocables como funciones.
Nota: La secuencia regular de Fibonacci comienza con 0 y 1. En su secuencia similar a Fibonacci, el segundo número puede ser cualquier cosa, pero se mantiene la regla de que un número es la suma de los dos números anteriores en la secuencia. secuencia.
En este método, usted determina si el valor de Fibonacci para el índice objetivo ya está calculado y almacenado en la memoria caché. Luego, agrega una llamada a print()
que lo ayudará a depurar su código usando id()
para garantizar que se utilicen los valores almacenados en caché.
Así es como funciona esta clase en la práctica:
>>> from fibonacci import Fibonaccish
>>> fibonacci_333 = Fibonacci(333)
>>> fibonacci_333(2)
0 0 id = 94800819952840
1 333 id = 140276932935312
333
>>> fibonacci_333(4)
2 333 id = 140276932934960
1 333 id = 140276932935312
2 333 id = 140276932934960
999
En este ejemplo de código, crea una instancia de Fibonaccish
con un valor inicial de 333. Los primeros valores de esta secuencia serán 0, 333, 333, 666, 999 y 1665.
La instancia que crea es invocable, por lo que puede usarla como una función normal. Luego, llamas a la instancia con 2
como argumento. La llamada imprime la identidad de los valores 0
y 333
en el índice 0
y 1
, respectivamente. A continuación, llamas a fibonacci_333()
con 4
como argumento. En este caso, obtienes la identidad de 333
tres veces, tanto en el índice 1 como en el 2.
Cuando observas las identidades, te das cuenta de que tu función usa el mismo objeto para los mismos índices, mientras que es diferente para las dos instancias diferentes de 333
. De esta manera, puede confirmar que la función utiliza el caché como se esperaba.
Si repites el ejemplo con la secuencia habitual de Fibonacci, Fibonacci(1)
, verás resultados ligeramente diferentes. En este caso, Python internará 1
bajo el capó, de modo que el mismo objeto se use tanto en el índice 1 como en el 2 de su caché.
Comprobando nombres y atributos: dir()
y vars()
A veces, es necesario conocer los atributos o métodos definidos en un objeto o ámbito determinado. Para este tipo de requisitos, Python tiene dos funciones integradas diferentes, dir()
y vars()
.
La función dir()
sin argumentos devuelve la lista de nombres en el ámbito actual. Entonces, el resultado dependerá del lugar en el que llames a la función. Con cualquier objeto Python como argumento, dir()
intenta devolver la lista de atributos de ese objeto.
Por ejemplo, si llamas a dir()
sin argumentos en una nueva sesión REPL, obtendrás un resultado como el siguiente:
>>> dir()
[
'__annotations__',
'__builtins__',
'__doc__',
'__loader__',
'__name__',
'__package__',
'__spec__'
]
Como puede ver, dir()
devuelve la lista de nombres definidos en su alcance actual, que es el alcance global en este ejemplo.
Si llamas a dir()
con un objeto Python como argumento, obtendrás una lista de los atributos y métodos del objeto. Si el objeto de entrada es una clase, obtendrá una lista de métodos y atributos de clase. Si el objeto es una instancia de una clase existente, obtendrá una lista de métodos, atributos de clase y atributos de instancia.
Considere el siguiente ejemplo que reutiliza su clase Rectangle
de la sección sobre la función super()
:
>>> class Rectangle:
... def __init__(self, length, width):
... self.length = length
... self.width = width
... def area(self):
... return self.length * self.width
... def perimeter(self):
... return 2 * (self.length + self.width)
...
>>> dir(Rectangle)
[
'__class__',
'__delattr__',
'__dict__',
...
'area',
'perimeter'
]
>>> rectangle = Rectangle(2, 4)
>>> dir(rectangle)
[
'__class__',
'__delattr__',
'__dict__',
...
'area',
'length',
'perimeter',
'width'
]
En la primera llamada a dir()
, obtienes los atributos y métodos de la clase Rectangle
. En este caso, utiliza el objeto de clase como argumento. En la segunda llamada a dir()
, utiliza una instancia de Rectangle
como argumento y obtiene todos los métodos, atributos de clase y atributos de instancia.
El comportamiento predeterminado de dir()
es diferente para diferentes tipos de objetos. Aquí hay un resumen de estas diferencias:
- A module object
Devuelve la lista de nombres definidos en el módulo.
- A type or class object
Devuelve la lista de nombres de atributos y métodos de clase y de las clases base.
- Other objects
Devuelve la lista de atributos y métodos, incluidos los atributos de clase y los atributos de las clases base.
También puede personalizar el comportamiento predeterminado de dir()
proporcionando el método especial .__dir__()
en sus clases personalizadas. Sin embargo, este tema está más allá del alcance de este tutorial.
La función vars()
devuelve el atributo .__dict__
para un módulo, clase, instancia o cualquier otro objeto con un atributo .__dict__
:
>>> vars(Rectangle)
mappingproxy(
{
'__module__': '__main__',
'__init__': <function Rectangle.__init__ at 0x10352d080>,
'area': <function Rectangle.area at 0x10352d120>,
'perimeter': <function Rectangle.perimeter at 0x10352d1c0>,
'__dict__': <attribute '__dict__' of 'Rectangle' objects>,
'__weakref__': <attribute '__weakref__' of 'Rectangle' objects>,
'__doc__': None
})
>>> vars(rectangle)
{'length': 2, 'width': 4}
En este ejemplo, llamas a vars()
con la clase Rectangle
como argumento. Obtienes el atributo .__dict__
de la clase, que contiene métodos y atributos de clase. Tenga en cuenta que también contiene un atributo .__dict__
que contiene los atributos de las instancias de la clase. Ese .__dict__
es lo que obtienes cuando llamas a vars()
con una instancia de la clase.
El atributo .__dict__
es un diccionario que funciona como un espacio de nombres que asigna nombres a objetos. Por ejemplo, puede asignar un nombre de método a un objeto de método o un nombre de atributo a un valor u objeto específico.
Ejecutar código Python desde cadenas
En situaciones excepcionales, puede resultar útil evaluar expresiones o ejecutar código que viene como un objeto de cadena. Esta práctica no es común en el código del mundo real porque puede no ser seguro, especialmente cuando el código de destino proviene de una fuente que no es confiable, como la entrada del usuario.
Independientemente de los problemas de seguridad involucrados, Python tiene tres funciones integradas que le permiten evaluar expresiones o ejecutar código que viene como una cadena. Aquí hay un resumen de estas funciones:
eval()
Evalúa expresiones arbitrarias de Python a partir de una cadena o entrada de código compilado.
exec()
Ejecuta código Python arbitrario a partir de una cadena o entrada de código compilado.
compile()
Genera un objeto de código compilado a partir de una cadena.
En las siguientes secciones, aprenderá los conceptos básicos de estas funciones. Para comenzar, comenzará usando la función eval()
para evaluar expresiones de Python.
Ejecutando expresiones a partir de cadenas: eval()
En Python, una expresión es una combinación de objetos y operadores que devuelve un valor. Encontrará varios tipos de expresiones, incluidas expresiones matemáticas, booleanas, de comparación, expresiones bit a bit y más. Cuando trabaje con expresiones, puede ejecutarlas como código Python normal. Sin embargo, ¿qué sucede si necesita evaluar expresiones definidas como cadenas?
Por ejemplo, piense en cómo evaluaría lo siguiente:
"sum([2, 3, 4, 5]) / 4 + 100"
Si desea evaluar esta cadena como una expresión, tendrá que analizar la cadena y descubrir cómo extraer los operandos y operadores. Luego, puedes reconstruir la expresión y ejecutarla en el intérprete de Python. Este proceso puede parecer algo rápido. Sin embargo, puede resultar abrumador en la práctica, especialmente si se considera el número infinito de expresiones diferentes que es posible que deba evaluar en código real.
Afortunadamente, Python tiene una función eval()
incorporada que te ayuda a evaluar expresiones que vienen como cadenas.
Nota: Para obtener más información sobre eval()
, consulte el tutorial Python eval()
: Evaluar expresiones dinámicamente.
Si tiene una cadena que contiene una expresión Python válida, puede llamar a eval()
con esa cadena como argumento. La función analizará la cadena, la compilará en código de bytes y finalmente la evaluará como una expresión normal:
>>> eval("sum([2, 3, 4, 5]) / 4 + 100")
103.5
¡Guau! ¡Eso fue rápido y sencillo! Simplemente pasó su cadena a eval()
, ejecutó el código y obtuvo el resultado de la expresión.
La firma de eval()
se parece a la siguiente:
eval(expression[, globals[, locals]])
El primer argumento,
expression
Una cadena que contiene una expresión de Python válida
globals
Un diccionario que contiene un espacio de nombres global para usar en la llamada a
eval()
locals
Un diccionario que contiene un espacio de nombres local para usar en la llamada a
eval()
Ya has visto un ejemplo del uso del argumento expresión
, por lo que ahora puedes centrarte en los otros dos argumentos. En cada ejemplo, deberá proporcionar una expresión.
A continuación se muestra un ejemplo del uso del argumento globals
:
>>> numbers = [2, 3, 4, 5]
>>> n = len(numbers)
>>> eval("sum(numbers) / n + 100")
103.5
>>> eval("sum(numbers) / n + 100", {})
Traceback (most recent call last):
...
NameError: name 'numbers' is not defined
>>> eval("sum(numbers) / n + 100", {"numbers": numbers, "n": n})
103.5
De forma predeterminada, eval()
tiene acceso al alcance global, por lo que puede usar todos los nombres definidos en este alcance en la expresión que pasa a la función. Si configura globals
en un diccionario vacío, restringe el acceso al alcance global y la función falla.
Finalmente, puede usar un diccionario explícito, como lo hizo en el ejemplo final, para proporcionar las variables globales que desea usar al evaluar la expresión de destino.
El argumento locals
funciona de manera similar. Se necesita un diccionario de nombres locales:
>>> def evaluator(expression):
... numbers = [2, 3, 4, 5]
... n = len(numbers)
... return eval(expression, {}, {"numbers": numbers, "n": n})
...
>>> evaluator("sum(numbers) / n + 100")
103.5
Dentro de la función evaluator()
, define numbers
y n
como variables locales. En la llamada a eval()
, utiliza un diccionario vacío para globals
y un diccionario que contiene las variables locales para locals
.
Aunque la función eval()
puede parecer una herramienta increíble, debes tener cuidado al usarla en tu código. En la práctica, estará más seguro si no utiliza esta herramienta en código del mundo real. ¿Por qué?
La función eval()
tiene implicaciones de seguridad que pueden ser difíciles de eludir. Por ejemplo, si utiliza la función para evaluar expresiones proporcionadas por usuarios externos, expone su sistema a la ejecución de código Python arbitrario.
Para obtener más información sobre cómo reducir los riesgos de seguridad asociados con eval()
, consulte Minimización de los problemas de seguridad de eval()
en Python . eval()
: tutorial sobre evaluación dinámica de expresiones.
Ejecutar código desde cadenas: exec()
y compile()
La función eval()
es una poderosa herramienta en Python. Sin embargo, está diseñado para evaluar expresiones. A veces, es posible que desees ejecutar fragmentos de código más complejos que vienen como cadenas. Por ejemplo, es posible que desee ejecutar bucles, declaraciones condicionales, declaraciones compuestas e incluso scripts completos. En este escenario, puede utilizar las funciones integradas exec()
y compile()
.
Nota: Para obtener más información sobre exec()
, consulta el tutorial exec()
de Python: Ejecutar código generado dinámicamente.
Aquí está la firma de la función exec()
:
exec(code [, globals [, locals]])
El argumento code
puede ser una cadena que contenga código Python válido. También puede ser un objeto de código compilado, que puede crear con la función compile()
. Aprenderá sobre compile()
en un momento. Por ahora, utilizará una cadena para proporcionar el argumento code
.
Si code
viene como una cadena, entonces exec()
lo analiza como una secuencia de declaraciones de Python. Luego, compila el código en código de bytes y, finalmente, ejecuta el código a menos que ocurra un error de sintaxis durante el paso de análisis o compilación.
Considere el siguiente ejemplo:
>>> functions = [
... "def add(a, b): return a + b",
... "def subtract(a, b): return a - b",
... "def multiply(a, b): return a * b",
... "def divide(a, b): return a / b",
... ]
>>> for function in functions:
... exec(function)
...
En este ejemplo, define una lista de cadenas. Cada cadena contiene funciones de Python para una operación aritmética básica. Luego, inicia un bucle sobre la lista. Con exec()
, ejecutas las cadenas que definen las funciones. Este paso lleva todas las funciones a su alcance global actual. Ahora puedes usarlos como lo harías con una función normal:
>>> add(1, 2)
3
>>> subtract(3, 2)
1
>>> multiply(2, 3)
6
>>> divide(6, 3)
2.0
Las funciones aritméticas ahora están disponibles en su alcance global, por lo que puede usarlas para ejecutar sus cálculos.
Al igual que eval()
, exec()
toma los argumentos globals
y locals
, que nuevamente son opcionales. Estos argumentos tienen significados similares en ambas funciones, por lo que puedes probarlos como ejercicio.
Nota: La función exec()
también tiene implicaciones de seguridad. Para obtener más información sobre ellos, consulte la sección Descubriendo y minimizando los riesgos de seguridad detrás de exec()
en exec()
de Python: ejecutar código generado dinámicamentetutorial.
Cuando tenga una cadena que contenga código que reutilizará varias veces, puede usar la función compile()
para compilar el código una vez y usarlo en todas partes. Esta práctica hará que su código sea más eficiente y rápido porque el paso de compilación se ejecuta solo una vez.
La firma de compile()
se parece a la siguiente:
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
Esta firma es un poco complicada porque tiene varios argumentos que debes comprender. Aquí hay un resumen de los argumentos y su significado:
source
Contiene el código que necesita compilar en código de bytes.
filename
Mantenga el archivo desde el cual se leyó el código.
mode
Especifica qué tipo de código debe compilarse.
flags
anddont_inherit
Controla qué opciones del compilador deben activarse y qué funciones futuras deben permitirse.
optimize
Especifica el nivel de optimización de la compilación.
Para leer desde un objeto de cadena, deberá establecer filename
en el valor "<string>"
. El argumento mode
puede tomar uno de los siguientes valores:
"eval"
cuandosource
consta de una sola expresión"exec"
cuandosource
es una secuencia de declaraciones"single"
cuandosource
es una declaración interactiva única
Dependiendo del código fuente y la función que planeas usar para ejecutarlo, seleccionarás el primer o el segundo valor. El argumento single
resulta útil cuando desea ejecutar una declaración como print("Hello, World!")
que normalmente ejecutaría en una sesión interactiva.
Para ilustrar cómo utilizar compile()
, considere el siguiente ejemplo de juguete:
>>> code = """
... result = sum(number for number in iterable if not number % 2)
... """
>>> compiled_code = compile(code, "<string>", "exec")
>>> context = {"iterable": [1, 2, 3, 4]}
>>> exec(compiled_code, context)
>>> context["result"]
6
>>> context = {"iterable": [10, 40, 50, 20]}
>>> exec(compiled_code, context)
>>> context["result"]
120
En este ejemplo, tiene un fragmento de código en una cadena. El código consiste en una llamada a sum()
que envuelve una expresión generadora que toma un iterable de números y devuelve los números pares. A continuación, utiliza la función compile()
para compilar la cadena en un objeto de código listo para su ejecución. El diccionario context
contiene un iterable de números.
Llamas a exec()
con el código compilado y el diccionario de contexto como argumentos. Tenga en cuenta que utiliza context
para proporcionar el argumento globals
. La llamada a exec()
actualizará este diccionario con cualquier nombre que defina en el código compilado. En este ejemplo específico, context
termina manteniendo la variable result
con la suma de los números pares en el iterable.
Para acceder al valor calculado, utilice el diccionario context
con la clave "result"
. En el ejemplo final, reutiliza el código compilado para realizar un cálculo similar con una lista de valores diferente.
Uso de funciones diversas
Python tiene algunas otras funciones integradas que cubren diversos temas. Aquí hay un resumen de estas funciones:
help()
Invoca el sistema de ayuda integrado.
hash()
Calcula el valor hash de un objeto.
__import__()
Invocado por la declaración
import
memoryview()
Devuelve un objeto de vista de memoria
En las siguientes secciones, aprenderá los conceptos básicos de estas funciones y cómo usarlas en su código Python o en una sesión interactiva del lenguaje. Para comenzar, comenzará con la función incorporada help()
.
Accediendo al sistema de ayuda integrado: help()
La función incorporada help()
resulta útil cuando trabajas en una sesión REPL de Python. Esta función le brinda acceso al sistema de ayuda interactivo integrado. Continúe y abra una sesión interactiva de Python en su terminal. Luego, llame a help()
sin argumentos. Se le presentará el sistema de ayuda:
>>> help()
Welcome to Python 3.x's help utility!
If this is your first time using Python, you should definitely check out
the tutorial on the internet at https://docs.python.org/3.x/tutorial/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
return to the interpreter, just type "quit".
To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics". Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".
help>
El resultado le da una cálida bienvenida a la utilidad de ayuda de Python. Luego, le sugiere que siga el tutorial oficial de Python si es nuevo en el idioma. En los párrafos tercero y cuarto, se le brindan instrucciones para utilizar el sistema de ayuda.
Al final de la página, tiene el mensaje help>
esperando su entrada. Continúe y escriba el nombre str
y luego presione Enter. Verás algo como lo siguiente:
Help on class str in module builtins:
class str(object)
| str(object='') -> str
| str(bytes_or_buffer[, encoding[, errors]]) -> str
|
| Create a new string object from the given object. If encoding or
| errors is specified, then the object must expose a data buffer
| that will be decoded using the given encoding and error handler.
| Otherwise, returns the result of object.__str__() (if defined)
| or repr(object).
| encoding defaults to sys.getdefaultencoding().
| errors defaults to 'strict'.
|
| Methods defined here:
|
| __add__(self, value, /)
| Return self+value.
|
| __contains__(self, key, /)
| Return key in self.
...
Esta es la página de ayuda para la clase str
. En esta página, encontrará información detallada sobre la clase y sus objetivos. Para salir de la página y volver al sistema de ayuda, continúe y presione Q.
Mientras esté en el sistema de ayuda, puede consultar la ayuda de muchos objetos de Python, incluidos módulos integrados, funciones, palabras clave y mucho más. Adelante, pruébalo. ¡Quizás encuentres información útil!
Hay una segunda forma de utilizar la función help()
. Primero, escriba Q en el indicador help>
y luego presione Enter para regresar. a su sesión interactiva. Una vez allí, puedes llamar a help()
con cualquier objeto Python como argumento. Por ejemplo, si llamas a la función con la clase str
como argumento, te llevará a la misma página que viste antes:
>>> help(str)
Esta forma de llamar a help()
le brinda acceso rápido a la página de ayuda de un objeto determinado. Es importante tener en cuenta que puede utilizar el objeto directamente como argumento para help()
o el nombre del objeto como una cadena como en help("str")
. Sin embargo, en la mayoría de los casos, es más seguro utilizar el nombre del objeto como una cadena:
>>> help(sys)
Traceback (most recent call last):
...
NameError: name 'sys' is not defined
En este ejemplo, intenta acceder a la página de ayuda del módulo sys
. Utiliza el nombre del módulo como argumento y obtiene una excepción NameError
porque el módulo no está presente en su alcance actual. La llamada a help()
funcionará de forma segura si usa el nombre del módulo como una cadena, como en "sys"
. ¡Anímate y pruébalo!
Creando códigos hash: hash()
Si trabaja en campos como la integridad de los datos, la seguridad o la criptografía, es posible que esté familiarizado con los códigos hash. Un código hash es un número que puede actuar como una huella digital para un dato determinado. Suele ser mucho más pequeño que los datos originales y permite verificar su integridad.
Para crear un código hash para un objeto determinado, necesita una función hash. Python tiene su propia función incorporada para crear códigos hash. La función se llama convenientemente hash()
.
Nota: Para obtener más información sobre las tablas hash, consulte el tutorial Crear una tabla hash en Python con TDD.
La firma de hash()
es como la siguiente:
hash(object)
Toma un objeto como argumento y devuelve el valor hash del objeto de entrada. El valor hash debe ser un número entero.
A continuación se muestran algunos ejemplos del uso de la función hash()
:
>>> hash(42)
42
>>> hash(2.7)
1614090106449586178
>>> hash("Hello")
-6239611042439236057
>>> hash(int)
270201092
>>> class DemoClass: pass
...
>>> hash(DemoClass)
346520709
>>> demo_instance = DemoClass()
>>> hash(demo_instance)
271491289
En estos ejemplos, ha utilizado la función hash()
con diferentes objetos, incluidos valores numéricos, cadenas, objetos de función y clases personalizadas. En todos los casos, obtienes un código hash único.
En la práctica, hay objetos que no tienen valor hash:
>>> hash([1, 2, 3])
Traceback (most recent call last):
...
TypeError: unhashable type: 'list'
>>> hash({"one": 1, "two": 2})
Traceback (most recent call last):
...
TypeError: unhashable type: 'dict'
>>> hash({"red", "green", "bleu"})
Traceback (most recent call last):
...
TypeError: unhashable type: 'set'
Notarás que los objetos mutables no se pueden usar mediante hash en Python porque puedes cambiar el valor de un objeto mutable durante su vida útil.
Importación de objetos desde nombres de cadenas: __import__()
La función __import__()
incorporada de Python es una herramienta avanzada que no es común en la programación diaria. La función se llama internamente mediante la instrucción import
. Se desaconseja el uso directo de __import__()
en favor de importlib.import_module()
. Sin embargo, es una función incorporada, por lo que aprenderá un poco sobre ella en esta sección.
Nota: Para profundizar en el sistema de importación, consulte el tutorial Python import
: técnicas avanzadas y consejos.
La firma de __import__()
se parece a la siguiente:
__import__(name, globals=None, locals=None, fromlist=(), level=0)
Con esta función, puede importar un módulo por su
name
El nombre de un módulo como una cadena
globals
Un diccionario que representa el espacio de nombres global.
locals
Un diccionario que representa el espacio de nombres local.
fromlist
Una lista de objetos o submódulos que deben importarse desde el módulo.
level
Un valor positivo que indica el número de directorios principales para buscar en relación con el directorio del módulo que llama a
__import__()
Para hacer algo equivalente a import sys
con la función __import__()
, puedes hacer algo como lo siguiente:
>>> sys = __import__("sys")
>>> sys
<module 'sys' (built-in)>
En este ejemplo, crea una variable sys
y le asigna el resultado de llamar a __import__()
con la cadena "sys"
como argumento. Esta llamada a __import__()
importa el módulo sys
a su alcance global actual.
Manipular datos binarios de manera eficiente: memoryview()
La función incorporada memoryview()
le permite acceder a los datos internos de un objeto que admite el protocolo de búfer, como array.array
, bytes
objetos y bytearray
. Puede utilizar esta función para manipular grandes conjuntos de datos o interactuar con datos binarios.
Por ejemplo, si tiene un conjunto de datos grande y desea utilizar una parte del mismo, crear una copia sería ineficiente. En su lugar, puede crear un objeto memoryview
para acceder a los datos sin copiarlos. Esto le permite utilizar menos memoria y aumenta la velocidad de ejecución.
Por ejemplo, supongamos que tiene los datos de píxeles de una imagen representados como bytearray
y desea invertir los valores de píxeles. Para realizar esta operación de manera eficiente, puede utilizar la función memoryview()
:
>>> image = bytearray([0, 127, 255, 64, 128, 192, 32, 96, 160])
>>> mv = memoryview(image)
>>> for i in range(len(mv)):
... mv[i] = 255 - mv[i]
...
>>> list(mv)
[255, 128, 0, 191, 127, 63, 223, 159, 95]
>>> list(image)
[255, 128, 0, 191, 127, 63, 223, 159, 95]
En este ejemplo, crea un objeto memoryview
para acceder a los datos que representan su imagen. En el bucle for
, iteras sobre los datos e inviertes los valores de los píxeles. La transformación se refleja en los datos originales.
En resumen, la función memoryview()
es una poderosa herramienta para trabajar con objetos que admiten el protocolo de búfer sin copiar los datos, lo que hace que su código sea más eficiente en memoria y más rápido.
Conclusión
Ha aprendido los conceptos básicos de las funciones integradas de Python. Estas son funciones que puedes usar directamente sin importar nada porque están disponibles en el ámbito o espacio de nombres integrado.
Las funciones integradas resuelven una amplia gama de problemas de programación comunes, como realizar operaciones matemáticas, trabajar con tipos de datos comunes, procesar iterables de datos, manejar entradas y salidas, trabajar con ámbitos y más.
En este tutorial, has aprendido:
- Los conceptos básicos de las funciones integradas de Python
- Acerca de los casos de uso comunes de las funciones integradas de Python
- Cómo utilizar estas funciones para resolver problemas prácticos en Python
Con este conocimiento, tienes habilidades básicas de Python que te ayudarán a escribir código Pythonic sólido. Más importante aún, ahora conoce todas estas increíbles funciones y puede usarlas en su código para abordar tareas comunes de manera eficiente sin tener que reinventar la rueda.