Clase 2: Modularización y tipos compuestos
Nota
Escenas del capítulo anterior:
En la clase anterior preparamos la infraestructura:
Instalamos los programas y paquetes necesarios.
Aprendimos como ejecutar: una consola usual, de ipython, o iniciar un jupyter notebook
Aprendimos a utilizar la consola como una calculadora
Vimos algunos comandos mágicos y como enviar comandos al sistema operativo
Aprendimos como obtener ayuda
Iniciamos los primeros pasos del lenguaje
Veamos un ejemplo completo de un programa (semi-trivial):
# Definición de los datos
r = 9.
pi = 3.14159
#
# Cálculos
A = pi*r**2
As = 4 * A
V = 4*A*r/3
#
# Salida de los resultados
print("Para un círculo de radio",r,"cm, el área es",A,"cm²")
print("Para una esfera de radio",r,"cm, el área es",As,"cm²")
print("Para una esfera de radio",r,"cm, el volumen es",V,"cm³")
En este ejemplo simple, definimos algunas variables con los datos del
problema (r
y pi
), realizamos cálculos y sacamos por pantalla
los resultados. A diferencia de otros lenguajes, python no necesita una
estructura rígida, con definición de un programa principal.
Otro punto importante de este ejemplo es el uso de comentarios. El caracter “#” inicia un comentario de línea, y el intérprete de python ignora todos lo que viene a continuación hasta que encuentra una nueva línea.
Modularización y encapsulado
Una característica importante de la programación es la posibilidad de
definir partes del código para realizar alguna tarea específica y poder
reutilizarla. En Python, una de las maneras más efectivas de hacer esto
es mediante la definición de funciones. Ya vimos un ejemplo, con la
función print()
, que se usa para imprimir valores a pantalla (por
defecto) o un archivo. Existen otras funciones ya definidas en Python
(len()
, max()
, min()
, abs()
, etc). Puede ver la lista
completa en la
documentación.
Definición básica de funciones
Tomemos el ejemplo del programa anterior para definir una función que calcule el área de un disco
def area_disco(r):
"""Cálculo del área de un círculo de radio `r`"""
# Definición de constantes
pi = 3.141593
# Cálculo
A = pi * r**2
return A
Puntos a notar:
Las funciones se definen utilizando la palabra
def
seguida por el nombre.A continuación, entre paréntesis se escriben los argumentos, en este caso el radio
r
,La función devuelve algo; puede ser uno o más valores.
Lo que devuelve la función se especifica mediante la palabra reservada
return
(en este casoA
que es un valor real). Si es más de un valor, se separan con comas. Si una función no devuelve algo explícitamente, entonces devuelveNone
.Al principio de la definición de la función se escribe el string de documentación.
help(area_disco)
Help on function area_disco in module __main__: area_disco(r) Cálculo del área de un círculo de radio r
R = 2
Area = area_disco(R)
print("Para un círculo de radio", R, "cm, el área es",Area,"cm²")
Para un círculo de radio 2 cm, el área es 12.566372 cm²
print("Para un círculo de radio", 3, "cm, el área es",area_disco(3),"cm²")
Para un círculo de radio 3 cm, el área es 28.274337 cm²
Módulos
Los módulos son el mecanismo de Python para reusar código. Existen varios módulos que son parte de la biblioteca standard para distintos tipos de aplicaciones. Además existe un repositorio en la que contribuye la comunidad, con bibliotecas para muchos usos diversos.
El uso de módulos es muy simple, para poder aprovecharlo necesitaremos saber dos cosas:
Qué funciones están ya definidas y listas para usar
Cómo acceder a ellas
Empecemos con la segunda cuestión. Para utilizar las funciones debemos
importarlas en la forma import modulo
, donde modulo es el nombre
que queremos importar.
Esto nos lleva a la primera cuestión: cómo saber ese nombre, y que funciones están disponibles. La respuesta es: la documentación.
Una vez importado, podemos utilizar constantes y funciones definidas en
el módulo con la notación “de punto”: modulo.funcion()
.
Módulo math
El módulo math contiene las funciones más comunes (trigonométricas, exponenciales, logaritmos, etc) para operar sobre números de punto flotante, y algunas constantes importantes (pi, e, etc). En realidad es una interface a la biblioteca math en C.
import math
# algunas constantes y funciones elementales
raiz5pi= math.sqrt(5*math.pi)
print (raiz5pi, math.floor(raiz5pi), math.ceil(raiz5pi))
print (math.e, math.floor(math.e), math.ceil(math.e))
# otras funciones elementales
print (math.log(1024,2), math.log(27,3))
print (math.factorial(7), math.factorial(9), math.factorial(10))
print ('Combinatorio: C(6,2):',math.factorial(6)/(math.factorial(4)*math.factorial(2)))
3.963327297606011 3 4
2.718281828459045 2 3
10.0 3.0
5040 362880 3628800
Combinatorio: C(6,2): 15.0
A veces, sólo necesitamos unas pocas funciones de un módulo. Entonces para abreviar la notación combiene importar sólo lo que vamos a usar, usando la notación:
from xxx import yyy
from math import sqrt, pi, log
import math
raiz5pi = sqrt(5*pi)
print (log(1024, 2))
print (raiz5pi, math.floor(raiz5pi))
10.0
3.963327297606011 3
import math as m
m.sqrt(3.2)
1.7888543819998317
import math
print(math.sqrt(-1))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[9], line 2
1 import math
----> 2 print(math.sqrt(-1))
ValueError: math domain error
Módulo cmath
El módulo math
no está diseñado para trabajar con números complejos,
para ello existe el módulo cmath
import cmath
print('Usando cmath (-1)^0.5=', cmath.sqrt(-1))
print(cmath.cos(cmath.pi/3 + 2j))
Usando cmath (-1)^0.5= 1j
(1.8810978455418161-3.1409532491755083j)
Si queremos calcular la fase (el ángulo que forma con el eje x) podemos usar la función phase
z = 1 + 0.5j
cmath.phase(z) # Resultado en radianes
0.4636476090008061
math.degrees(cmath.phase(z)) # Resultado en grados
26.56505117707799
Ejercicios 02 (a)
Escriba funciones que calculen:
El volumen de una esfera
El volumen de una caja de lados
L1
,L2
,L3
Escriba una función que tome como argumentos tres valores:
a
,b
,c
y calcule los ceros (raíces) del polinomio \(a x^{2} + b x + c\).Considere un polígono regular de \(N\) lados inscripto en un círculo de radio unidad:
Escriba una función que tome como argumento el número de lados \(N\) y calcule el ángulo interior del polígono regular correspondiente (por ejemplo el de un triángulo es 60 grados, de un cuadrado es 90 grados, y de un pentágono es 108 grados). Pruebe su función para valores de \(N= 3, 5, 6, 8, 9, 10, 12\).
¿Puede calcular la longitud del lado de los polígonos regulares si se encuentran inscriptos en un círculo de radio unidad?
En todos los casos, pruebe las funciones escritas
Tipos simples: Números
Números Enteros
Números Reales o de punto flotante
Números Complejos
Mencionamos anteriormente que todos las entidades en Python son objetos, que tienen al menos tres atributos: tipo, valor e identidad. Pero además, puede tener otros atributos como datos o métodos. Por ejemplo los números enteros, unos de los tipos más simples que usaremos, tienen métodos que pueden resultar útiles en algunos contextos.
a = 3 # Números enteros
print(type(a), a.bit_length(), sep="\n")
<class 'int'>
2
b = 127
print(type(b))
print(b.bit_length())
<class 'int'>
7
En estos casos, usamos el método bit_length
de los enteros, que nos
dice cuántos bits son necesarios para representar un número. Para verlo
utilicemos la función bin()
que nos da la representación en binario
de un número entero
# bin nos da la representación en binarios
print(a, "=", bin(a), "->", a.bit_length(),"bits")
print(b, "=", bin(b), "->", b.bit_length(),"bits")
3 = 0b11 -> 2 bits
127 = 0b1111111 -> 7 bits
Esto nos dice que el número 3
se puede representar con dos bits, y
que para representar el número 127
se necesitan 7 bits.
Los números de punto flotante también tienen algunos métodos definidos. Por ejemplo podemos saber si un número flotante corresponde a un entero:
b = -3.0
b.is_integer()
True
c = 142.25
c.is_integer()
False
o podemos expresarlo como el cociente de dos enteros, o en forma hexadecimal
c.as_integer_ratio()
(569, 4)
s = c.hex()
print(s)
0x1.1c80000000000p+7
Acá la notación, compartida con otros lenguajes (C, Java), significa:
[sign] ['0x'] integer ['.' fraction] ['p' exponent]
Entonces ‘0x1.1c8p+7’ corresponde a:
(1 + 1./16 + 12./16**2 + 8./16**3)*2.0**7
142.25
Recordemos, como último ejemplo, los números complejos:
z = 1 + 2j
zc = z.conjugate() # Método que devuelve el conjugado
zr = z.real # Componente, parte real
zi = z.imag # Componente, parte imaginaria
print(z, zc, zr, zi, zc.imag)
(1+2j) (1-2j) 1.0 2.0 -2.0
Tipos compuestos
En Python, además de los tipos simples (números y booleanos, entre ellos) existen tipos compuestos, que pueden contener más de un valor de algún tipo. Entre los tipos compuestos más importantes vamos a referirnos a:
- Se pueden definir con comillas dobles ( ” ), comillas simples ( ’ ), o tres comillas (simples o dobles). Comillas (dobles) y comillas simples producen el mismo resultado. Sólo debe asegurarse que se utiliza el mismo tipo para abrir y para cerrar el stringEjemplo:
s = "abc"
(el elementos[0]
tiene el valor"a"
). - Las listas son tipos que pueden contener más de un elemento de cualquier tipo. Los tipos de los elementos pueden ser diferentes. Las listas se definen separando los diferentes valores con comas, encerrados entre corchetes. Se puede referir a un elemento por su índice.Ejemplo:
L = ["a",1, 0.5 + 1j]
(el elementoL[0]
es igual al string"a"
). - Las tuplas se definen de la misma manera que las listas pero con paréntesis en lugar de corchetes. Ejemplo:
T = ("a",1, 0.5 + 1j).
- Los diccionarios son contenedores a cuyos elementos se los identifica con un nombre (key) en lugar de un índice. Se los puede definir dando los pares
key:value
entre llavesEjemplo:D = {'a': 1, 'b': 2, 1: 'hola', 2: 3.14}
(el elementoD['a']
es igual al número 1).
Strings: Secuencias de caracteres
Una cadena o string es una secuencia de caracteres (letras, “números”, símbolos).
Se pueden definir con comillas, comillas simples, o tres comillas (simples o dobles). Comillas simples o dobles producen el mismo resultado. Sólo debe asegurarse que se utilizan el mismo tipo para abrir y para cerrar el string
Triple comillas (simples o dobles) sirven para incluir una cadena de caracteres en forma textual, incluyendo saltos de líneas.
saludo = 'Hola Mundo' # Definición usando comillas simples
saludo2 = "Hola Mundo" # Definición usando comillas dobles
saludo, saludo2
('Hola Mundo', 'Hola Mundo')
saludo == saludo2
True
Los strings se pueden definir equivalentemente usando comillas simples o dobles. De esta manera es fácil incluir comillas dentro de los strings
otro= "that's all"
dijo = '"Cómo te va" dijo el murguista a la muchacha'
print(otro)
that's all
print(dijo)
"Cómo te va" dijo el murguista a la muchacha
respondio = "Le dijo \"Bien\" y lo dejó como si nada"
print(respondio)
Le dijo "Bien" y lo dejó como si nada
Para definir strings que contengan más de una línea, manteniendo el formato, se pueden utilizar tres comillas (dobles o simples):
Texto_largo = '''Aquí me pongo a cantar
Al compás de la vigüela,
Que el hombre que lo desvela
Una pena estraordinaria
Como la ave solitaria
Con el cantar se consuela.'''
print (Texto_largo,'\n')
Aquí me pongo a cantar
Al compás de la vigüela,
Que el hombre que lo desvela
Una pena estraordinaria
Como la ave solitaria
Con el cantar se consuela.
Texto_largo
'Aquí me pongo a cantarn Al compás de la vigüela,nQue el hombre que lo desvelan Una pena estraordinarianComo la ave solitarian Con el cantar se consuela.'
En Python
se puede utilizar cualquier caracter que pueda ingresarse
por teclado, ya que por default Python-3 trabaja usando la codificación
UTF-8, que incluye todos los símbolos que se nos ocurran. Por ejemplo:
# Un ejemplo que puede interesarnos un poco más:
label = "σ = λ T/ µ + π · δξ"
print('tipo de label: ', type(label))
print ('Resultados corresponden a:', label, ' (en m/s²)')
tipo de label: <class 'str'>
Resultados corresponden a: σ = λ T/ µ + π · δξ (en m/s²)
Operaciones
En Python ya hay definidas algunas operaciones que involucran strings como la suma (composición o concatenación) y el producto por enteros (repetición).
s = saludo + ' -> ' + otro + '\t'
s = s + "chau"
print (s) # Suma de strings
Hola Mundo -> that's all chau
Como vemos la suma de strings es simplemente la concatenación de los
argumentos. La multiplicación de un entero n
por un string es
simplemente la suma del string n
veces:
a = '1'
b = 1
print(a, type(a))
print(b, type(b))
1 <class 'str'>
1 <class 'int'>
print ("Multiplicación por enteros de strings:", 7*a)
print ("Multiplicación por enteros de enteros:", 7*b)
Multiplicación por enteros de strings: 1111111
Multiplicación por enteros de enteros: 7
La longitud de una cadena de caracteres (como de otros objetos) se puede
calcular con la función len()
print ('longitud del saludo =', len(saludo), 'caracteres')
longitud del saludo = 10 caracteres
Por ejemplo, podemos usar estas operaciones para realizar el centrado manual de una frase:
titulo = "Centrado manual simple"
n = int((60-len(titulo))//2) # Para un ancho de 60 caracteres
print ((n)*'<', titulo ,(n)*'>')
#
saludo = 'Hola Mundo'
n = int((60-len(saludo))//2) # Para un ancho de 60 caracteres
print (n*'*', saludo, n*'*')
<<<<<<<<<<<<<<<<<<< Centrado manual simple >>>>>>>>>>>>>>>>>>> ********************* Hola Mundo *********************
Iteración y Métodos de Strings
Los strings poseen varias cualidades y funcionalidades. Por ejemplo:
Se puede iterar sobre ellos, y también quedarse con sólo una parte (slicing)
Tienen métodos (funciones que se aplican a su dueño)
Veamos en primer lugar cómo se hace para seleccionar parte de un string
Indexado de strings
Podemos referirnos a un caracter o una parte de una cadena de caracteres mediante su índice. Los índices en Python empiezan en 0.
s = "0123456789"
print ('Primer caracter :', s[0])
print ("Segundo caracter :", s[1])
Primer caracter : 0
Segundo caracter : 1
Si queremos empezar desde el final utilizamos índices negativos. El índice “-1” corresponde al último caracter.n
print ("El último caracter :", s[-1])
print ("El anteúltimo caracter :", s[-2])
El último caracter : 9
El anteúltimo caracter : 8
También podemos elegir un subconjunto de caracteres:
print ('Los tres primeros: ', s[0:3])
print ('Todos a partir del tercero: ', s[3:])
print ('Los últimos dos: ', s[-2:])
print ('Todos menos los últimos dos:', s[:-2])
Los tres primeros: 012
Todos a partir del tercero: 3456789
Los últimos dos: 89
Todos menos los últimos dos: 01234567
Estas “subcadenas” son cadenas de caracteres, y por lo tanto pueden utilizarse de la misma manera que cualquier otra cadena:
print (s[:3] + s[-2:])
01289
La selección de elementos y subcadenas de una cadena s
tiene la
forma general
s[i: f: p]
donde i, f, p
son enteros. La notación se refiere a la subcadena
empezando en el índice i
, hasta el índice f
recorriendo con paso
p
. Casos particulares de esta notación son:
Un índice simple. Por ejemplo
s[3]
se refiere al tercer elemento.Un índice negativo se cuenta desde el final, empezando desde
-1
.Si el paso
p
no está presente el valor por defecto es 1. Ejemplo:s[2:4] = s[2:4:1]
.Si se omite el primer índice, el valor asumido es 0. Ejemplo:
s[:2:1] = s[0:2:1]
.Si se omite el segundo índice, el valor asumido es -1. Ejemplo:
s[1::1] = s[1:-1:1]
.Notar que puede omitirse más de un índice. Ejemplo:
s[::2] = s[0:-1:2]
.
print(s)
print(s[0:5:2])
print (s[::2])
print (s[::-1])
print (s[::-3])
0123456789
024
02468
9876543210
9630
Veamos algunas utilidades que se pueden aplicar sobre un string:
a = "La mar estaba serena!"
print(a)
La mar estaba serena!
Por ejemplo, en python es muy fácil reemplazar una cadena por otra
usando el método de strings replace()
b = a.replace('e','a')
print(b)
La mar astaba sarana!
o separar las palabras:
print(a.split())
['La', 'mar', 'estaba', 'serena!']
print(a.split('s'))
['La mar e', 'taba ', 'erena!']
En este caso, tanto replace()
como split()
son métodos que ya
están definidos para los strings.
Recordemos que un método es una función que está definida junto con el tipo de objeto. En este caso el string. Hay más información sobre todos los métodos de las cadenas de caracteres en: String Methods
Veamos algunos ejemplos más:
Buscar y reemplazar cosas en un string:
a.find('e')
7
a.find('x')
-1
a.find('e',8)
15
a.find('re')
16
El método find(sub[, start[, end]]) -> int
busca el substring
sub
empezando con el índice start
(argumento opcional) y
finalizando en el índice end
(argumento opcional, que sólo puede
aparecer si también aparece start
). Devuelve el índice donde inicial
es substring.
Formato de strings
En python se le puede dar formato a los strings de distintas maneras.
Vamos a ver dos opciones: - Uso del método format
- Uso de
“f-strings”
El método format()
es una función que busca en el strings las llaves
y las reemplaza por los argumentos. Veamos esto con algunos ejemplos:
a = 2024
m = 'Feb'
d = 6
s = "Hoy es el día {} de {} de {}".format(d, m, a)
print(s)
print("Hoy es el día {}/{}/{}".format(d,m,a))
print("Hoy es el día {0}/{1}/{2}".format(d,m,a))
print("Hoy es el día {2}/{1}/{0}".format(d,m,a))
Hoy es el día 6 de Feb de 2024
Hoy es el día 6/Feb/2024
Hoy es el día 6/Feb/2024
Hoy es el día 2024/Feb/6
raiz = "datos-{}-{}-{}.dat"
fname = raiz.format(a,m,d)
print(fname)
datos-2024-Feb-6.dat
Más recientemente se ha implementado en Python una forma más directa de intercalar datos con caracteres literales, mediante f-strings, que permite una sintaxis más compacta. Comparemos las dos maneras:
pi = 3.141592653589793
s1 = "El valor de π es {}".format(pi)
s2 = "El valor de π con cuatro decimales es {0:.4f}".format(pi)
print(s1)
print(s2)
El valor de π es 3.141592653589793
El valor de π con cuatro decimales es 3.1416
print("El valor de 2π con seis decimales es {:012.6f}".format(2*pi))
El valor de 2π con seis decimales es 00006.283185
Para darle formato a números enteros usamos el caracter ‘d’ (decimal)
print("{:03d}".format(5))
print("{:3d}".format(5))
005
5
t = f"el valor de π es {pi}"
print(t)
el valor de π es 3.141592653589793
Podemos obtener estos mismos resultados usando “f-strings”
print(f"el valor de π es {pi}")
print(f"El valor de π con seis decimales es {pi:.4f}")
print(f"El valor de 2π con seis decimales es {2*pi:012.6f}")
print(f"{5:03d}")
print(f"{5:3d}")
el valor de π es 3.141592653589793
El valor de π con seis decimales es 3.1416
El valor de 2π con seis decimales es 00006.283185
005
5
fname = f"datos-{a}-{m}-{d}.dat"
print(fname)
datos-2024-Feb-6.dat
Conversión de tipos
Como comentamos anteriormente, y se ve en los ejemplos anteriores, uno no define el tipo de variable a-priori sino que queda definido al asignársele un valor (por ejemplo a=3 define a como una variable del tipo entero).
a = 3 # a es entero
b = 3.1 # b es real
c = 3 + 0j # c es complejo
print ("a es de tipo {0}\nb es de tipo {1}\nc es de tipo {2}".format(type(a), type(b), type(c)))
print ("'a + b' es de tipo {0} y 'a + c' es de tipo {1}".format(type(a+b), type(a+c)))
a es de tipo <class 'int'>
b es de tipo <class 'float'>
c es de tipo <class 'complex'>
'a + b' es de tipo <class 'float'> y 'a + c' es de tipo <class 'complex'>
Si bien Python hace la conversión de tipos de variables en algunos casos, no hace magia, no puede adivinar nuestra intención si no la explicitamos.
print (1+'1')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[60], line 1
----> 1 print (1+'1')
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Sin embargo, si le decimos explícitamente qué conversión queremos, todo funciona bien
print (str(1) + '1')
print (1 + int('1'))
print (1 + float('1.e5'))
11
2
100001.0
# a menos que nosotros **nos equivoquemos explícitamente**
print (1 + int('z'))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[62], line 2
1 # a menos que nosotros **nos equivoquemos explícitamente**
----> 2 print (1 + int('z'))
ValueError: invalid literal for int() with base 10: 'z'
Ejercicios 02 (b)
Para la cadena de caracteres:
s = '''Aquí me pongo a cantar
Al compás de la vigüela,
Que el hombre que lo desvela
Una pena estraordinaria
Como la ave solitaria
Con el cantar se consuela.'''
Forme un nuevo string de 10 caracteres que contenga los 5 primeros y los 5 últimos del string anterior
s
. Imprima por pantalla el nuevo string.Forme un nuevo string que contenga los 10 caracteres centrales de
s
(utilizando un método que pueda aplicarse a otros strings también). Imprima por pantalla el nuevo string.Cuente la cantidad de veces que aparecen los substrings
es
,la
,que
,co
, en los siguientes dos casos: distinguiendo entre mayúsculas y minúsculas, y no distinguiendo. Imprima el resultado.Cambie todas las letras “m” por “n” y todas las letras “n” por “m” en
s
. Imprima el resultado por pantalla.
Utilizando funciones y métodos de strings en la cadena de caracteres:
s1='En un lugar de la Mancha de cuyo nombre no quiero acordarme'
Obtenga la cantidad de caracteres.
Imprima la frase anterior pero con cada palabra empezando en mayúsculas.
Cuente cuantas letras ‘a’ tiene la frase, ¿cuántas vocales tiene?
Centrado manual de frases
Utilizando la función
len()
centre una frase corta en una pantalla de 80 caracteres. Utilice la frase: “Un ejercicio con cadena de caracteres”Agregue subrayado a la frase anterior
Escriba una función que centre y subraye una frase dada como argumento. Se espera obtener algo así:
Un ejercicio con cadena de caracteres -------------------------------------
Repita el punto anterior utilizando métodos de strings
Veamos como obtener ayuda sobre un tipo (en este caso strings)
s = ""
help(s) # Equivalentemente, se puede usar: help(str)
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. | | __eq__(self, value, /) | Return self==value. | | __format__(self, format_spec, /) | Return a formatted version of the string as described by format_spec. | | __ge__(self, value, /) | Return self>=value. | | __getattribute__(self, name, /) | Return getattr(self, name). | | __getitem__(self, key, /) | Return self[key]. | | __getnewargs__(...) | | __gt__(self, value, /) | Return self>value. | | __hash__(self, /) | Return hash(self). | | __iter__(self, /) | Implement iter(self). | | __le__(self, value, /) | Return self<=value. | | __len__(self, /) | Return len(self). | | __lt__(self, value, /) | Return self<value. | | __mod__(self, value, /) | Return self%value. | | __mul__(self, value, /) | Return self*value. | | __ne__(self, value, /) | Return self!=value. | | __repr__(self, /) | Return repr(self). | | __rmod__(self, value, /) | Return value%self. | | __rmul__(self, value, /) | Return value*self. | | __sizeof__(self, /) | Return the size of the string in memory, in bytes. | | __str__(self, /) | Return str(self). | | capitalize(self, /) | Return a capitalized version of the string. | | More specifically, make the first character have upper case and the rest lower | case. | | casefold(self, /) | Return a version of the string suitable for caseless comparisons. | | center(self, width, fillchar=' ', /) | Return a centered string of length width. | | Padding is done using the specified fill character (default is a space). | | count(...) | S.count(sub[, start[, end]]) -> int | | Return the number of non-overlapping occurrences of substring sub in | string S[start:end]. Optional arguments start and end are | interpreted as in slice notation. | | encode(self, /, encoding='utf-8', errors='strict') | Encode the string using the codec registered for encoding. | | encoding | The encoding in which to encode the string. | errors | The error handling scheme to use for encoding errors. | The default is 'strict' meaning that encoding errors raise a | UnicodeEncodeError. Other possible values are 'ignore', 'replace' and | 'xmlcharrefreplace' as well as any other name registered with | codecs.register_error that can handle UnicodeEncodeErrors. | | endswith(...) | S.endswith(suffix[, start[, end]]) -> bool | | Return True if S ends with the specified suffix, False otherwise. | With optional start, test S beginning at that position. | With optional end, stop comparing S at that position. | suffix can also be a tuple of strings to try. | | expandtabs(self, /, tabsize=8) | Return a copy where all tab characters are expanded using spaces. | | If tabsize is not given, a tab size of 8 characters is assumed. | | find(...) | S.find(sub[, start[, end]]) -> int | | Return the lowest index in S where substring sub is found, | such that sub is contained within S[start:end]. Optional | arguments start and end are interpreted as in slice notation. | | Return -1 on failure. | | format(...) | S.format(*args, **kwargs) -> str | | Return a formatted version of S, using substitutions from args and kwargs. | The substitutions are identified by braces ('{' and '}'). | | format_map(...) | S.format_map(mapping) -> str | | Return a formatted version of S, using substitutions from mapping. | The substitutions are identified by braces ('{' and '}'). | | index(...) | S.index(sub[, start[, end]]) -> int | | Return the lowest index in S where substring sub is found, | such that sub is contained within S[start:end]. Optional | arguments start and end are interpreted as in slice notation. | | Raises ValueError when the substring is not found. | | isalnum(self, /) | Return True if the string is an alpha-numeric string, False otherwise. | | A string is alpha-numeric if all characters in the string are alpha-numeric and | there is at least one character in the string. | | isalpha(self, /) | Return True if the string is an alphabetic string, False otherwise. | | A string is alphabetic if all characters in the string are alphabetic and there | is at least one character in the string. | | isascii(self, /) | Return True if all characters in the string are ASCII, False otherwise. | | ASCII characters have code points in the range U+0000-U+007F. | Empty string is ASCII too. | | isdecimal(self, /) | Return True if the string is a decimal string, False otherwise. | | A string is a decimal string if all characters in the string are decimal and | there is at least one character in the string. | | isdigit(self, /) | Return True if the string is a digit string, False otherwise. | | A string is a digit string if all characters in the string are digits and there | is at least one character in the string. | | isidentifier(self, /) | Return True if the string is a valid Python identifier, False otherwise. | | Call keyword.iskeyword(s) to test whether string s is a reserved identifier, | such as "def" or "class". | | islower(self, /) | Return True if the string is a lowercase string, False otherwise. | | A string is lowercase if all cased characters in the string are lowercase and | there is at least one cased character in the string. | | isnumeric(self, /) | Return True if the string is a numeric string, False otherwise. | | A string is numeric if all characters in the string are numeric and there is at | least one character in the string. | | isprintable(self, /) | Return True if the string is printable, False otherwise. | | A string is printable if all of its characters are considered printable in | repr() or if it is empty. | | isspace(self, /) | Return True if the string is a whitespace string, False otherwise. | | A string is whitespace if all characters in the string are whitespace and there | is at least one character in the string. | | istitle(self, /) | Return True if the string is a title-cased string, False otherwise. | | In a title-cased string, upper- and title-case characters may only | follow uncased characters and lowercase characters only cased ones. | | isupper(self, /) | Return True if the string is an uppercase string, False otherwise. | | A string is uppercase if all cased characters in the string are uppercase and | there is at least one cased character in the string. | | join(self, iterable, /) | Concatenate any number of strings. | | The string whose method is called is inserted in between each given string. | The result is returned as a new string. | | Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs' | | ljust(self, width, fillchar=' ', /) | Return a left-justified string of length width. | | Padding is done using the specified fill character (default is a space). | | lower(self, /) | Return a copy of the string converted to lowercase. | | lstrip(self, chars=None, /) | Return a copy of the string with leading whitespace removed. | | If chars is given and not None, remove characters in chars instead. | | partition(self, sep, /) | Partition the string into three parts using the given separator. | | This will search for the separator in the string. If the separator is found, | returns a 3-tuple containing the part before the separator, the separator | itself, and the part after it. | | If the separator is not found, returns a 3-tuple containing the original string | and two empty strings. | | removeprefix(self, prefix, /) | Return a str with the given prefix string removed if present. | | If the string starts with the prefix string, return string[len(prefix):]. | Otherwise, return a copy of the original string. | | removesuffix(self, suffix, /) | Return a str with the given suffix string removed if present. | | If the string ends with the suffix string and that suffix is not empty, | return string[:-len(suffix)]. Otherwise, return a copy of the original | string. | | replace(self, old, new, count=-1, /) | Return a copy with all occurrences of substring old replaced by new. | | count | Maximum number of occurrences to replace. | -1 (the default value) means replace all occurrences. | | If the optional argument count is given, only the first count occurrences are | replaced. | | rfind(...) | S.rfind(sub[, start[, end]]) -> int | | Return the highest index in S where substring sub is found, | such that sub is contained within S[start:end]. Optional | arguments start and end are interpreted as in slice notation. | | Return -1 on failure. | | rindex(...) | S.rindex(sub[, start[, end]]) -> int | | Return the highest index in S where substring sub is found, | such that sub is contained within S[start:end]. Optional | arguments start and end are interpreted as in slice notation. | | Raises ValueError when the substring is not found. | | rjust(self, width, fillchar=' ', /) | Return a right-justified string of length width. | | Padding is done using the specified fill character (default is a space). | | rpartition(self, sep, /) | Partition the string into three parts using the given separator. | | This will search for the separator in the string, starting at the end. If | the separator is found, returns a 3-tuple containing the part before the | separator, the separator itself, and the part after it. | | If the separator is not found, returns a 3-tuple containing two empty strings | and the original string. | | rsplit(self, /, sep=None, maxsplit=-1) | Return a list of the substrings in the string, using sep as the separator string. | | sep | The separator used to split the string. | | When set to None (the default value), will split on any whitespace | character (including n r t f and spaces) and will discard | empty strings from the result. | maxsplit | Maximum number of splits (starting from the left). | -1 (the default value) means no limit. | | Splitting starts at the end of the string and works to the front. | | rstrip(self, chars=None, /) | Return a copy of the string with trailing whitespace removed. | | If chars is given and not None, remove characters in chars instead. | | split(self, /, sep=None, maxsplit=-1) | Return a list of the substrings in the string, using sep as the separator string. | | sep | The separator used to split the string. | | When set to None (the default value), will split on any whitespace | character (including n r t f and spaces) and will discard | empty strings from the result. | maxsplit | Maximum number of splits (starting from the left). | -1 (the default value) means no limit. | | Note, str.split() is mainly useful for data that has been intentionally | delimited. With natural text that includes punctuation, consider using | the regular expression module. | | splitlines(self, /, keepends=False) | Return a list of the lines in the string, breaking at line boundaries. | | Line breaks are not included in the resulting list unless keepends is given and | true. | | startswith(...) | S.startswith(prefix[, start[, end]]) -> bool | | Return True if S starts with the specified prefix, False otherwise. | With optional start, test S beginning at that position. | With optional end, stop comparing S at that position. | prefix can also be a tuple of strings to try. | | strip(self, chars=None, /) | Return a copy of the string with leading and trailing whitespace removed. | | If chars is given and not None, remove characters in chars instead. | | swapcase(self, /) | Convert uppercase characters to lowercase and lowercase characters to uppercase. | | title(self, /) | Return a version of the string where each word is titlecased. | | More specifically, words start with uppercased characters and all remaining | cased characters have lower case. | | translate(self, table, /) | Replace each character in the string using the given translation table. | | table | Translation table, which must be a mapping of Unicode ordinals to | Unicode ordinals, strings, or None. | | The table must implement lookup/indexing via __getitem__, for instance a | dictionary or list. If this operation raises LookupError, the character is | left untouched. Characters mapped to None are deleted. | | upper(self, /) | Return a copy of the string converted to uppercase. | | zfill(self, width, /) | Pad a numeric string with zeros on the left, to fill a field of the given width. | | The string is never truncated. | | ---------------------------------------------------------------------- | Static methods defined here: | | __new__(*args, **kwargs) from builtins.type | Create and return a new object. See help(type) for accurate signature. | | maketrans(...) | Return a translation table usable for str.translate(). | | If there is only one argument, it must be a dictionary mapping Unicode | ordinals (integers) or characters to Unicode ordinals, strings or None. | Character keys will be then converted to ordinals. | If there are two arguments, they must be strings of equal length, and | in the resulting dictionary, each character in x will be mapped to the | character at the same position in y. If there is a third argument, it | must be a string, whose characters will be mapped to None in the result.
Tipos contenedores
En Python existen tipos compuestos (que pueden contener más de un valor). Uno de ellos que ya vimos es el tipo string que es una cadena de caracteres. Veamos otros:
Listas
Las listas son tipos compuestos. Se definen separando los elementos con comas, todos encerrados entre corchetes. En general las listas pueden contener diferentes tipos, y pueden no ser todos iguales, pero suelen utilizarse con ítems del mismo tipo. Algunas características:
Los elementos no son necesariamente homogéneos en tipo.
Los elementos están ordenados.
Se accede mediante un índice.
Están definidas operaciones entre Listas, así como algunos métodos
x in L
(¿x es un elemento de L?)x not in L
(¿x no es un elemento de L?)L1 + L2
(concatenar L1 y L2)n*L1
(n veces L1)L1*n
(n veces L1)L[i]
(Elemento i-ésimo)L[i:j]
(Elementos i a j)L[i:j:k]
(Elementos i a j, elegidos uno de cada k)len(L)
(longitud de L)min(L)
(Mínimo de L)max(L)
(Máximo de L)L.index(x, [i])
(Índice de x, iniciando en i)L.count(x)
(Número de veces que aparece x en L)L.append(x)
(Agrega el elemento x al final)
Veamos algunos ejemplos:
cuadrados = [1, 9, 16, 25]
En esta línea hemos declarado una variable llamada cuadrados
, y le
hemos asignado una lista de cuatro elementos. En algunos aspectos las
listas son muy similares a los strings. Se pueden realizar muchas de
las mismas operaciones en strings, listas y otros objetos sobre los que
se pueden iterar (iterables).
Las listas pueden accederse por posición y también pueden rebanarse (slicing)
Nota
La indexación de iteradores empieza desde cero (como en C)
cuadrados[0]
1
cuadrados[3]
25
cuadrados[-1]
25
cuadrados[:3:2]
[1, 16]
cuadrados[-2:]
[16, 25]
Los índices pueden ser positivos (empezando desde cero) o negativos empezando desde -1.
cuadrados: |
1 |
9 |
16 |
25 |
---|---|---|---|---|
índices: |
0 |
1 |
2 |
3 |
índices negativos: |
-4 |
-3 |
-2 |
-1 |
Nota
La asignación entre listas no copia todos los datos
a = cuadrados
a is cuadrados
True
print("Valores originales")
print(a)
cuadrados[0]= -1
print("Valores modificados")
print(a)
print(cuadrados)
Valores originales
[1, 9, 16, 25]
Valores modificados
[-1, 9, 16, 25]
[-1, 9, 16, 25]
a is cuadrados
True
cuadrados[0] = 1
b = cuadrados.copy()
print("Valores originales")
print(b)
print(cuadrados)
print("Valores modificados")
cuadrados[0]=-2
print(b)
print(cuadrados)
Valores originales
[1, 9, 16, 25]
[1, 9, 16, 25]
Valores modificados
[1, 9, 16, 25]
[-2, 9, 16, 25]
Comprensión de Listas
Una manera sencilla de definir una lista es utilizando algo que se llama Comprensión de listas. Como primer ejemplo veamos una lista de números cuadrados como la que escribimos anteriormente. En lenguaje matemático la defiríamos como \(S = \{x^{2} : x \in \{0 \dots 9\}\}\). En python es muy parecido.
Podemos crear la lista cuadrados
utilizando compresiones de listas
L1 = [1,3,5]
L2= [i**2 for i in L1]
print(L2)
[1, 9, 25]
cuadrados = [i**2 for i in range(10)]
cuadrados
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Una lista con los cuadrados sólo de los números pares también puede crearse de esta manera, ya que puede incorporarse una condición:
L = [a**2 for a in range(2,21) if a % 2 == 0]
L
[4, 16, 36, 64, 100, 144, 196, 256, 324, 400]
Tuplas
Las tuplas son objetos similares a las listas, sobre las que se puede iterar y seleccionar partes según su índice. La principal diferencia es que son inmutables mientras que las listas pueden modificarse.
L1 = [0,1,2,3,4,5] # Las listas se definen con corchetes
T1 = (0,1,2,3,4,5) # Las tuplas se definen con paréntesis
L1[0] = -1
print(f"L1[0] = {L1[0]}")
L1[0] = -1
try:
T1[0] = -1
print(f"{T1[0] = }")
except:
print('Tuples son inmutables')
Tuples son inmutables
Las tuplas se usan cuando uno quiere crear una “variable” que no va a ser modificada. Además códigos similares con tuplas pueden ser un poco más rápidos que si usan listas.
Un uso común de las tuplas es el de asignación simultánea a múltiples variables:
a, b, c = (1, 3, 5)
print(b)
print(a, b, c)
3
1 3 5
# Los paréntesis son opcionales en este caso
a, b, c = 4, 5, 6
print(b)
print(a,b,c)
5
4 5 6
Un uso muy común es el de intercambiar el valor de dos variables
print(a,b)
a, b = b, a # swap
print(a,b)
4 5
5 4
Rangos
Los objetos de tipo range representan una secuencia inmutable de números y se usan habitualmente para ejecutar un bucle for un número determinado de veces. El formato es uno de:
range(stop)
range(start, stop)
range(start, stop, step)
range(2)
range(0, 2)
type(range(2))
range
range(2,9)
range(2, 9)
list(range(2,9))
[2, 3, 4, 5, 6, 7, 8]
list(range(2,9,2))
[2, 4, 6, 8]
Operaciones sobre listas
Veamos algunas operaciones que se pueden realizar sobre listas. Por ejemplo, se puede fácilmente:
concatenar dos listas,
buscar un valor dado,
agregar elementos,
borrar elementos,
calcular su longitud,
invertirla
Empecemos concatenando dos listas, usando el operador “suma”
L1 = [0,1,2,3,4,5]
L1 + L1
[0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
2*L1 == L1 + L1
True
L = 3*L1
Las listas tienen definidos métodos, que podemos ver con la ayuda
incluida, por ejemplo haciendo help(list)
print(L)
[0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5]
L.index(3) # Índice del elemento de valor 3
3
L.index(3,4) # Índice del valor 3, empezando del cuarto
9
L.count(3) # Cuenta las veces que aparece el valor "3"
3
Si queremos agregar un elemento al final utilizamos el método
append
:
L.append(8)
print(L)
[0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 8]
L.append([9, 8, 7])
print(L)
[0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 8, [9, 8, 7]]
Si queremos insertar un elemento en una posición que no es el final de
la lista, usamos el método insert()
. Por ejemplo para insertar el
valor 6 en la primera posición:
L.insert(0,6)
print(L)
[6, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 8, [9, 8, 7]]
L.insert(-2,6)
print(L)
[6, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 8, [9, 8, 7]]
En las listas podemos sobreescribir uno o más elementos
L[0:3] = [2,3,4]
L[4]=-4
print(L)
[2, 3, 4, 2, -4, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 8, [9, 8, 7]]
L[-2:]=[0,1]
print(L)
[2, 3, 4, 2, -4, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 0, 1]
L[-2:] = [7,"fin2"]
print(L)
[2, 3, 4, 2, -4, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 'fin2']
L.extend([0,1]) # Extendemos con varios elementos
print(L)
[2, 3, 4, 2, -4, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 'fin2', 0, 1]
print(L)
L.remove('fin2') # Remueve la primera aparición del valor 3
print(L)
[2, 3, 4, 2, -4, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 'fin2', 0, 1]
[2, 3, 4, 2, -4, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1]
print(L1)
L1.reverse()
print(L1)
[0, 1, 2, 3, 4, 5]
[5, 4, 3, 2, 1, 0]
Función de Python que invierte una lista
print(list(reversed(L1)))
[0, 1, 2, 3, 4, 5]
L.sort() # Ordena la lista (si los elementos son comparables)
print(L)
[-4, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 7]
El método sort()
de las listas acepta dos argumentos opcionales:
key
y reverse
L.sort(True)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[50], line 1
----> 1 L.sort(True)
TypeError: sort() takes no positional arguments
L.sort(reverse=True)
print(L)
[7, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, -4]
Funciones que aplican sobre listas
Hay algunas funciones de Python que se aplican sobre listas (o sobre
iterables en general). Algunas de ellas son la suma sum()
e
inversión reversed()
L
[7, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 0, 0, 0, -4]
sum(L)
60
reversed(L)
<list_reverseiterator at 0x7fed3814ceb0>
L1 = list(reversed(L))
print(L1)
[-4, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 7]
Las funciones mínimo min()
, máximo max()
y ordenar sorted()
toman como argumento una lista (u otro iterable) de elementos que pueden
compararse entre sí
print(min(L), max(L))
-4 7
print(sorted(L))
[-4, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 7]
help(sorted)
Help on built-in function sorted in module builtins:
sorted(iterable, /, *, key=None, reverse=False)
Return a new list containing all items from the iterable in ascending order.
A custom key function can be supplied to customize the sort order, and the
reverse flag can be set to request the result in descending order.
Estas funciones toman además un argumento opcional key
, que es una
función que se aplica a cada elemento antes de compararlos
Puede encontrarse más información en la Biblioteca de Python.
s = "abcde"
L3 = ['hola','que','tal']
s.join(L3)
'holaabcdequeabcdetal'
" ".join(L3)
'hola que tal'
print("\n".join(L3))
hola
que
tal
Ejercicios 02 (c)
Para Entregar: Manejos de listas:
Cree la lista N de longitud 50, donde cada elemento es un número entero de 1 a 50 inclusive (Ayuda: vea la expresión
range
).Invierta la lista.
Extraiga de N una lista N1 que contenga sólo aquellos elementos que sean el cuadrado de algún número entero.
Extraiga de N una lista N2 que contenga sólo aquellos elementos que sean iguales al \(n^2-n\) para algún número entero \(n\).
Ayuda: Puede resultar útil recordar el uso de comprensión de listas.
Debe enviar por correo electrónico, con asunto “02_Suapellido”, un programa llamado 02_SuApellido.py (en todos los casos utilice su apellido, no la palabra “SuApellido”).
Cree una lista de la forma
L = [1,3,5,...,17,19,19,17,...,3,1]
(Ayuda: vea la expresiónrange
).Escriba una función que tome un número entero de tres cifras, y devuelva el mayor entero que se puede formar con esas cifras (Ayuda: considere convertir el número entero a otros tipos).
Construya una lista
L2
con 2000 elementos, todos iguales a0.0005
. Imprima su suma utilizando la funciónsum
y comparar con el resultado que arroja la función que existe en el módulomath
para realizar suma de números de punto flotante.Operación “rara” sobre una lista:
Defina la lista
L = [0,1]
Realice la operación
L.append(L)
Ahora imprima L, e imprima el último elemento de
L
.Haga que una nueva lista
L1
tenga el valor del último elemento deL
y repita el inciso anterior.
.