Apéndice E — Cadenas.

Objetivo. Explicar el tipo de dato básico cadena (str) y como se usa en diferentes contextos.

E.1 Definición de cadenas.

En Python, una cadena (string) es una secuencia de caracteres utilizada para representar textos.

Las cadenas se pueden crear utilizando:

  • comillas simples: ',
  • comillas dobles: ",
  • comillas triples: """ o '''.

Son inmutables, lo que significa que no se pueden cambiar una vez que se han creado. Sin embargo, se pueden crear nuevas cadenas basadas en operaciones realizadas en las cadenas originales.

Veamos algunos ejemplos.

  • Definición de una cadena usando comillas simples ':
simples = 'Hay pocas cosas tan ensordecedoras como el silencio'
print(simples)
Hay pocas cosas tan ensordecedoras como el silencio
  • Definición de una cadena usando comillas dobles ":
dobles = "Hay pocas cosas tan ensordecedoras como el silencio"
print(dobles)
Hay pocas cosas tan ensordecedoras como el silencio
  • Definición de una cadena usando comillas triples """ y ''':
triples1 = '''Hay pocas cosas tan ensordecedoras como el silencio'''
print(triples1)

triples2 = """Hay pocas cosas tan ensordecedoras como el silencio"""
print(triples2)
Hay pocas cosas tan ensordecedoras como el silencio
Hay pocas cosas tan ensordecedoras como el silencio
print(type(simples), type(dobles), type(triples1), type(triples2), sep="\n")
<class 'str'>
<class 'str'>
<class 'str'>
<class 'str'>

Observa que el tipo de dato es str.

E.2 Caracteres especiales.

  • Las cadenas pueden contener caracteres especiales como cambio de línea, tabulador, entre otros.

  • Para que estos caracteres se puedan representar se requiere del caracter de escape \.

  • Algunos de estos caracteres se muestran en la siguiente tabla:

Secuencia de escape Caracter espacial
\ Diagonal invertida para ignorar el cambio de línea
\\ Diagonal invertida (\)
\' Comilla simple (')
\" Comilla doble (")
\n Cambio de línea (ASCII Linefeed LF)
\t Tabulador (ASCII Sangría horizontal TAB)

La documentación completa se puede encontrar en el siguiente enlace: Escape sequences.

Ejemplo E.1: Definición de cadenas.
  1. Definir e imprimir las siguientes cadenas:
    1. Enjoy the moments now, because they don't last forever
    2. Python "pythonico"
# 1.A. Forma 1. Usamos el caracter de escape
poema = 'Enjoy the moments now, because they don\'t last forever'
print(poema)
Enjoy the moments now, because they don't last forever
# 1.A. Forma 2. Definimos la cadena con " "
poema = "Enjoy the moments now, because they don't last forever"
print(poema)
Enjoy the moments now, because they don't last forever

Observa que es posible imprimir ' sin usar el caracter \ si la cadena se define con " y viceversa, como se muestra a continuación:

# 1.B. La cadena puede tener " dentro de ' ... '
titulo = 'Python "pythonico"'
print(titulo)
Python "pythonico"
#1.B. Usando dobles comillas y el caracter de escape
titulo = "Python \"pythonico\""
print(titulo)
Python "pythonico"

.

Ejemplo E.2: Textos largos.

Definir e imprimir el siguiente texto:

Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
# Forma 1. 
queja = "Desde muy niño \ntuve que \"interrumpir\" 'mi' educación \npara ir a la escuela"
print(queja)
Desde muy niño 
tuve que "interrumpir" 'mi' educación 
para ir a la escuela

En esta primera forma definimos la cadena usando comillas dobles. Para imprimir las dobles comillas usamos el caracter de escape \". De igual manera, para indicar el cambio de línea usamos \n. Para imprimir las comillas simples (') no es necesario realizar nada especial dado que la cadena se define usando dobles comillas ".

#  Forma 2. Una cadena larga la definimos con triples comillas simples.
queja = '''
Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
'''
print(queja)

Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela

Observa que en el ejemplo anterior la cadena contiene comillas dobles y simples (" y '), pero no hay necesidad de usar el caracter de escape para imprimirlas; de igual manera no fue necesario indicar los cambios de línea, estos se toman de manera implícita. Lo anterior fue posible por el uso de las triples comillas para definir la cadena.

#  Forma 3. Una cadena larga la definimos con triples comillas dobles.
queja = """
Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
"""
print(queja)

Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela

.

Ejemplo E.3: Más textos.

Definir e imprimir el siguiente texto:


El siguiente es un ejemplo de función:
--------------------------------------
def funcion(N):
        suma = 0
        for i in range(N):
                 suma += 1
        return suma

Una manera directa es mediante el uso de triples comillas dobles y el caracterm de escape \t:

codigo = """
El siguiente es un ejemplo de función:
--------------------------------------
def funcion(N):
\tsuma = 0
\tfor i in range(N):
\t\tsuma += 1 
\treturn suma
"""
print(codigo)

El siguiente es un ejemplo de función:
--------------------------------------
def funcion(N):
    suma = 0
    for i in range(N):
        suma += 1 
    return suma

Observa que cuando el texto es largo y de varias líneas, conviene usar triples comillas. Para agregar la sangría al principio de algunas líneas usamos el tabulador \t.

E.3 Indexación de las cadenas.

La indexación permite acceder a diferentes elementos o rangos de elementos de una cadena.

  • Los elementos de una cadena de N elementos, se numeran empezando en 0 y terminando en N-1, el cual representa el último elemento de la cadena.
  • También se pueden usar índices negativos donde -1 representa el último elemento y -N el primer elemento.

Veamos el siguiente ejemplo:

ejemplo = M u r c i é l a g o
índice positivo \(\rightarrow\) 0 1 2 3 4 5 6 7 8 9
índice negativo \(\rightarrow\) -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
  • La cadena tiene N = 10 elementos.
  • Sus índices positivos van de 0 a 9.
  • Sus índices negativos van de -1 a -10.

Ahora veamos algunos ejemplos de acceso a ciertos elementos de la cadena.

# Definimos la cadena
ejemplo = 'Murciélago'
print(ejemplo)
print(type(ejemplo))
Murciélago
<class 'str'>
# Primer elemento de la cadena
print(ejemplo[0]) 
M
# Elemento en la posición 5
print(ejemplo[5]) 
é
# Elemento en la posición 9 (en este caso es el último)
print(ejemplo[9]) 
o
# Último elemento de la cadena
print(ejemplo[-1]) 
o
# Elemento en la posición -6 o equivalentemente en la posición 4
print(ejemplo[-6]) 
print(ejemplo[4])
i
i
# Elemento en la posición -10, el primero en este caso
print(ejemplo[-10]) 
M

E.3.1 Acceso a porciones de las cadenas (slicing).

Se puede obtener una subcadena a partir de la cadena original, para ello usamos el siguiente formato: str[Start:End:Stride]

Start :Índice del primer caracter para formar la subcadena. Se incluye el elemento con este índice.

End : Índice que indica el caracter final de la subcadena. No se incluye el elemento con este índice.

Stride: Salto entre elementos.

Si queremos obtener la subcadena urcié de la cadena original Murciélago podemos hacerlo como sigue:

  • con índices positivos:
ejemplo = M u r c i é l a g o
índice positivo \(\rightarrow\) 0 1 2 3 4 5 6 7 8 9
ejemplo[1:6] = u r c i é
  • con índices negativos:
ejemplo = M u r c i é l a g o
índice negativo \(\rightarrow\) -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
ejemplo[-9:-4] = u r c i é

Veamos los siguientes ejemplos

print(ejemplo[1:6])
urcié
print(ejemplo[-9:-4])
urcié
print(ejemplo[:]) # Cadena completa
Murciélago
print(ejemplo[0:5]) # Elementos del 0 al 4 
Murci
print(ejemplo[::2]) # Todos los elementos, con saltos de 2
Mrilg
print(ejemplo[1:8:2]) # Los elementos de 1 a 7, con saltos de 2
ucéa
print(ejemplo[::-1]) # La cadena en reversa
ogaléicruM

E.4 Métodos aplicables sobre las cadenas.

Las cadenas son objetos de la clase <class 'str'> y tienen definidos atributos y métodos. Véase Common string operations para más información.

Recuerda que la lista de métodos de un objeto se puede obtener si ponemos el nombre del objeto más un punto (.) y luego tecleamos tabulador (↹), obtendremos algo similar a la imagen mostrada en la Figura E.1.

Métodos y atributos de las cadenas
Figura E.1: Métodos y atributos de un objeto de tipo str.

Veamos algunos ejemplos de los métodos de las cadenas.

# Imprimimos la cadena original
print(ejemplo)
Murciélago
# Centramos la cadena en 20 espacios
print(ejemplo.center(20))
     Murciélago     
# Centramos la cadena en 20 espacios y usamos '-' en los espacios restantes
print(ejemplo.center(20,'-')) 
-----Murciélago-----
# Convertimos todos los caracteres a mayúsculas
print(ejemplo.upper())
MURCIÉLAGO
# Encontrar un caracter dentro de la cadena, 
# nos proporciona el índice solo de la primera aparición:
print(ejemplo.find('é'))
5
# Cuando el caracter no está en la cadena, regresa un -1
print(ejemplo.find('e'))
-1
# Cuenta el número de aparciones de un caracter dentro de la cadena
print(ejemplo.count('g'))
1
# Pregunta si la cadena se puede imprimir
print(ejemplo.isprintable())
True
# Reemplazamos un caracter o conjunto de caracteres por otro.
print(ejemplo.replace('é', 'e'))
Murcielago

E.5 Funciones y operadores sobre cadenas.

Veamos algunas funciones incorporadas y operadores que se pueden aplicar sobre las cadenas.

# Definimos una cadena
cadena = 'anita lava la tina'
print(cadena)
anita lava la tina
  • Función len() para obtener la longitud de la cadena.
print(len(cadena))
18
  • Funciones max() y min() para obtener el máximo y mínimo de acuerdo con su código unicode.
print(min(cadena)) # El mínimo es el espacio en blanco
print(max(cadena))
 
v
  • Función sorted() regresa una lista de elementos de la cadena ordenados, de acuerdo con su código unicode.
print(sorted(cadena))
[' ', ' ', ' ', 'a', 'a', 'a', 'a', 'a', 'a', 'i', 'i', 'l', 'l', 'n', 'n', 't', 't', 'v']
  • Operador == para comparar cadenas
cadena_reversa = cadena[::-1] # construimos la cadena en reversa
print('original  : ', cadena)
print('invertida : ', cadena_reversa)
print('¿Las cadenas son iguales? ', cadena == cadena_reversa)
original  :  anita lava la tina
invertida :  anit al aval atina
¿Las cadenas son iguales?  False

Para checar que el contenido de cadena es un palíndromo tendríamos que eliminar los espacios cuando hacemos la comparación de la cadena original con la cadena en reversa:

# Eliminamos los espacios
cadena_original_sin_esp = cadena.replace(' ','')
cadena_reversa_sin_esp = cadena_reversa.replace(' ','')

# Imprimimos las cadenas
print('original sin espacios: "', cadena_original_sin_esp, '"', sep='')
print('en reversa sin espacios: "', cadena_reversa_sin_esp, '"', sep='')

# Verificamos si es palíndromo o no
print('¿Es palíndromo? :', cadena_original_sin_esp == cadena_reversa_sin_esp)
original sin espacios: "anitalavalatina"
en reversa sin espacios: "anitalavalatina"
¿Es palíndromo? : True

El siguiente es el mismo algoritmo, pero con un código más reducido (pythonico):

print('¿"', cadena, '" es palíndromo? ', cadena.replace(' ','') == cadena[::-1].replace(' ',''), sep='')
¿"anita lava la tina" es palíndromo? True
# Usamos el caracter \ para escribir una 
# sola instrucción en varias líneas
print('¿"', cadena, '" es palíndromo? ', \
      cadena.replace(' ','') == cadena[::-1].replace(' ',''), \
      sep='')
¿"anita lava la tina" es palíndromo? True
  • Operador in para saber si un elemento está en la cadena.
print('v' in cadena)
True
  • Operador + para concatenar cadenas.
palabra = 'Palíndromo : '
print(palabra + cadena)
Palíndromo : anita lava la tina
  • Operador * para repetir la cadena.
# Repetimos la cadena 'oh yeah ' 5 veces
expresion = 'oh yeah ' * 5
print(expresion)
oh yeah oh yeah oh yeah oh yeah oh yeah 

E.6 Construcción de cadenas

Existen varias maneras de construir cadenas, a continuación se revisan algunos ejemplos.

E.6.1 Usando operaciones básicas.

Los operadores: + y * están definidos para las cadenas.

Veamos el siguiente ejemplo:

frase1 = "Somos aquello en lo que creemos"
frase2 = "aún sin darnos cuenta"

# Concatenación de cadenas
frase_total = frase1 + ', ' + frase2 + '.'

print(frase_total)
Somos aquello en lo que creemos, aún sin darnos cuenta.

En el siguiente ejemplo creamos una cadena de 60 guiones - usando el operador *:

print('-' * 60)
------------------------------------------------------------

Escribimos la frase_total centrada en 60 espacios y entre dos líneas:

print('-' * 60)
print(frase_total.center(60))
print('-' * 60)
------------------------------------------------------------
  Somos aquello en lo que creemos, aún sin darnos cuenta.   
------------------------------------------------------------

Podemos agregar al autor de la frase:

print('-' * 60)
print(frase_total.center(60))
print("Carlos Monsivais".rjust(60))
print('-' * 60)
------------------------------------------------------------
  Somos aquello en lo que creemos, aún sin darnos cuenta.   
                                            Carlos Monsivais
------------------------------------------------------------

Observa que aplicamos el método rjust() para justificar a la derecha, y lo hicimos directamente en el momento de la creación de la cadena "Carlos Monsivais" (al vuelo).

E.6.2 Concatenación y casting

Vamos a crear la siguiente cadena: Pedro Páramo tiene 15 años y pesa 70.5 kg.

Usaremos el operador + y construiremos la cadena usando algunas variables; también convertiremos algunas variables a tipo str:

# Definimos las siguientes variables
edad = 15
nombre = 'Pedro'
apellido = 'Páramo'
peso = 70.5

# Construimos la cadena usando el operador '+' y la función 'str()' 
datos = nombre + apellido + 'tiene' + str(15) + 'años y pesa' + str(70.5) + 'kg'

print(datos)
PedroPáramotiene15años y pesa70.5kg

Para agregar espacios es necesario hacerlo de manera explícita como sigue:

datos = nombre + ' ' + apellido + ' tiene ' + str(15) + ' años y pesa ' + str(70.5) + ' kg'
print(datos)
Pedro Páramo tiene 15 años y pesa 70.5 kg

E.6.3 Método str.format()

Este método permite sustituir variables en los lugares indicados por {}:

datos = '{} {} tiene {} años y pesa {} kg'.format(nombre, apellido, edad, peso)
print(datos)
Pedro Páramo tiene 15 años y pesa 70.5 kg

Observa que aplicamos el método format() a la cadena en construcción.

E.6.4 Cadenas formateadas (f-string, formatted string literals)

Este tipo de cadenas permite sustituir variables en los lugares indicados:

datos = f'{nombre} {apellido} tiene {edad} años y pesa {peso} kg'
print(datos)
Pedro Páramo tiene 15 años y pesa 70.5 kg

Observa que agregamos una f al principio de la definición de la cadena para indicar que se trata de una cadena formateada.

E.6.5 Cadenas usando el método str.join()

Dada una cadena que funciona como separador, este método recibe una estructura de datos que contiene las cadenas que se van a unir y que estarán separados por la cadena inicial:

datos = " ".join([nombre, apellido, 'tiene', str(15), 'años y pesa', str(70.5), 'kg'])
print(datos)
Pedro Páramo tiene 15 años y pesa 70.5 kg

En el ejemplo anterior la cadena inicial es un espacio " " y junta todos los elementos que se dan entre corchetes []. El uso de corchetes construye una lista, que es un tipo de dato que se describe en el Apéndice I.

E.7 Formato de la salida.

Es posible utilizar algunos modificadores en la definición de una cadena para que se imprima con un cierto formato. Esto aplica para cadenas formateadas y para el método format. Veamos algunos ejemplos.

E.7.1 Texto.

# Impresión del nombre en 30 espacios de texto
sdef = f'{nombre:30s}'  # Alineación a la izq. por omisión
sder = f'{nombre:>30s}' # Alineación a la der.
sizq = f'{nombre:<30s}' # Alineación a la izq.
scen = f'{nombre:^30s}' # Centrada
print(sdef)
print(sder)
print(sizq)
print(scen)
Pedro                         
                         Pedro
Pedro                         
            Pedro             

Ahora agregamos las cadenas ---| y |--- para delimitar los 30 espacios.

# Impresión del nombre en 30 espacios de texto
sdef = f'---|{nombre:30s}|---'  # Alineación a la izq. por omisión
sder = f'---|{nombre:>30s}|---' # Alineación a la der.
sizq = f'---|{nombre:<30s}|---' # Alineación a la izq.
scen = f'---|{nombre:^30s}|---' # Centrada

print(sdef)
print(sder)
print(sizq)
print(scen)
---|Pedro                         |---
---|                         Pedro|---
---|Pedro                         |---
---|            Pedro             |---
NotaNota.

Observa que en el ejemplo anterior se usó una s al final del número 30, esto es para indicar que la variable nombre es de tipo cadena. Para enteros en base diez se usa una d y para flotantes una f. Estas terminaciones no son necesarias aunque es conveniente agregarlas para hacer el código más claro y que no haya errores de formato.

Más información la puedes consultar en: Format Specification Mini-Language

E.7.2 Enteros

Para números enteros podemos definir el número de espacios y alinear la salida:

# Este es un formato de número entero que usa _ para separar los miles
n1 = 5_521_345_678
n2 = 7_712_932_143
n3 = 8_123_535_098

idef = f'---|{n1:15d}|---'  # alineación a la der. por omisión
icen = f'---|{n1:^15d}|---' # centrado
iizq = f'---|{n2:<15d}|---' # alineación a la izq.
ider = f'---|{n3:>15d}|---' # alineación a la der.

print(idef, icen, iizq, ider, sep='\n')
---|     5521345678|---
---|  5521345678   |---
---|7712932143     |---
---|     8123535098|---

También es posible usar , como separador de los miles en la salida, veamos:

idef = f'---|{n1:15,d}|---'  # alineación a la der. por omisión
icen = f'---|{n1:^15,d}|---' # centrado
iizq = f'---|{n2:<15,d}|---' # alineación a la izq.
ider = f'---|{n3:>15,d}|---' # alineación a la der.

print(idef, icen, iizq, ider, sep='\n')
---|  5,521,345,678|---
---| 5,521,345,678 |---
---|7,712,932,143  |---
---|  8,123,535,098|---

Y se puede completar con 0’s los espacios en blanco:

idef = f'---|{n1:015,d}|---'  # alineación a la der. por omisión
icen = f'---|{n1:^015,d}|---' # centrado
iizq = f'---|{n2:<015,d}|---' # alineación a la izq.
ider = f'---|{n3:>015,d}|---' # alineación a la der.

print(idef, icen, iizq, ider, sep='\n')
---|005,521,345,678|---
---|05,521,345,6780|---
---|7,712,932,14300|---
---|008,123,535,098|---

Se puede generar la salida de un entero en las bases decimal, hexadecimal, octal o binaria usando d, x, o y b respectivamente.

ejemplo = 16
print(f'int: {ejemplo:d}')
print(f'hex: {ejemplo:x}')
print(f'oct: {ejemplo:o}')
print(f'bin: {ejemplo:b}')
int: 16
hex: 10
oct: 20
bin: 10000

E.7.3 Flotantes

En el caso de números flotantes se puede definir el número de decimales en la salida:

# Valor aproximado de pi
pi = 3 + 1/7

# Cadena con 5 decimales de pi:
spi = f'{pi:.5f}'

print('El valor de PI es aproximadamente', spi) 
El valor de PI es aproximadamente 3.14286

Y también es posible definir el número total de espacios que incluyen la parte entera, el punto decimal y el número de decimales:

numero_flotante_grande = 213.2131255345435643

# Cadena con 15 espacios totales y 3 decimales
snumero = f'{numero_flotante_grande:15.3f}'

print(f'---|{snumero}|---')
---|        213.213|---

Al igual que las cadenas y los enteros, también se puede usar una alineación en la salida y rellenar con ceros los espacios en blanco:

snum_cen = f'{numero_flotante_grande:^015.3f}'
snum_izq = f'{numero_flotante_grande:<015.3f}'
snum_der = f'{numero_flotante_grande:>015.3f}'

print(snum_cen)
print(snum_izq)
print(snum_der)
0000213.2130000
213.21300000000
00000000213.213

E.7.4 Usando el método format()

Usando el método str.format(), también podemos formatear la salida. Aplica exactamente lo mismo que con las f-string. Por ejemplo:

# Definimos dos números enteros
votos_a_favor = 42_572_654   
votos_en_contra = 43_132_495 

# Realizamos algunas operaciones
total_de_votos = votos_a_favor + votos_en_contra
porcentaje = votos_a_favor / total_de_votos

# Revisamos el contenido y tipo de los números
print(votos_a_favor, type(votos_a_favor))
print(votos_en_contra, type(votos_en_contra))
print(total_de_votos, type(total_de_votos))
print(porcentaje, type(porcentaje))

# Realizamos la impresión usando un formato
print('{:^20d} votos a favor ({:^10.2%})'.format(votos_a_favor, porcentaje))
42572654 <class 'int'>
43132495 <class 'int'>
85705149 <class 'int'>
0.496733912684756 <class 'float'>
      42572654       votos a favor (  49.67%  )

Observa que se imprime votos_a_favor en 20 espacios y alineado al centro. También se imprime porcentaje, que es un número flotante, usando 10 espacios que incluyen el punto, dos decimales y el símbolo %. El uso de % convierte el número flotante en un porcentaje (multiplica por 100) automáticamente e imprime el símbolo.

Se pueden usar números para identificar los argumentos de str.format():

ej1 = '{0} y {1}'.format('el huevo', 'la gallina')
ej2 = '{1} y {0:^20s}'.format('el huevo', 'la gallina')

print(ej1)
print(ej2)
el huevo y la gallina
la gallina y       el huevo      

Se le puede dar nombre a los argumentos para que sea más fácil entender la salida

ej3 = "Look {sujeto}, there's an {objeto} up in the sky".format(sujeto='mummy', objeto='aeroplane')

print(ej3)
Look mummy, there's an aeroplane up in the sky

Usar un nombre en los argumentos de str.format() permite ponerlos en cualquier orden en la lista de argumentos:

ej4 = "Look {sujeto}, there's an {objeto} up in the sky".format(objeto='aeroplane', sujeto='mummy')

print(ej4)
Look mummy, there's an aeroplane up in the sky

Se pueden combinar números con nombres de argumento:

ej5 = 'El {0}, el {1}, y el {otro}.'.format('Bueno', 'Malo', otro='Feo')

print(ej5)
El Bueno, el Malo, y el Feo.

Otro ejemplo de alineación (la declaración for la revisaremos en el Apéndice H):

for x in range(1, 11):
    print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

Para más información véase Format String Syntax

E.7.5 Método antiguo para formateo de la salida.

Se puede seguir usando la forma antigua para formatear la salida, la cual es heredada del lengueaje C.

viejo = 'El valor aproximado de pi es %10.6f.' % pi

print(viejo)
El valor aproximado de pi es   3.142857.

E.8 Inmutabilidad de las cadenas

Los elementos de las cadenas no se pueden modificar:

# Intentamos modificar el elemento 5 de la cadena
ejemplo[5] = "e"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[112], line 2
      1 # Intentamos modificar el elemento 5 de la cadena
----> 2 ejemplo[5] = "e"

TypeError: 'int' object does not support item assignment
cadena='''
este es un 
texto muy
largo
'''
print(cadena)

este es un 
texto muy
largo
print(type(cadena))
<class 'str'>
len(cadena)
29
cadena[0] # El primer elemento es un cambio de línea
'\n'
cadena[-1] # El último elemento es un cambio de línea
'\n'
print(cadena[6])
e
cadena[6] = 'h'
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[89], line 1
----> 1 cadena[6] = 'h'

TypeError: 'str' object does not support item assignment