Python: Conoce tu IDLE

Objetivo: invitación a aprovechar al máximo las características de un IDE y presentar un truco sencillo en IDLE.

Aunque para muchos les es suficiente tener abiertos un simple editor de texto y un terminal, lo cierto es que los IDEs surgen con la idea de hacernos la vida más fácil.

Tienes un amplio abanico de IDEs a tu disposición para programar en Python. Echa un vistazo a esta wiki para hacerte una idea.

Uno de mis favoritos es, sin lugar a dudas, IDLE, incluido directamente en las distribuciones Python sobre Windows y a un solo comando de instalación en cualquier Linux. Es relativamente simple, pero aún así ofrece las características mínimas que debe cumplir cualquier IDE que se precie.

Pero, la cuestión, independientemente del IDE de que se trate, ¿conoces y utilizas todo lo que te ofrece?

Muchas veces es como tener un coche de gama alta, repleto de posibilidades, pero conformarnos con que sea capaz de conducirnos de un lado a otro y no beneficiarnos de sus comodidades.

Merece la pena invertir un día o dos descubriendo las maravillas de nuestros IDEs, créeme. Todo el tiempo que emplees te será devuelto con creces; además, queda muy profesional ver manejar un IDE con soltura.

Voy a aprovechar la coyuntura para contarte un truco sencillo para IDLE pero que resulta muy práctico…

Para ilustrar en qué consiste, vamos a escribir un programa muy básico. Lo he dividido en dos módulos para que haya varios ficheros implicados.

# principal.py
# Cálculo del importe por comensal

import auxiliar

total_factura = input('¿A cuánto asciende la broma? ')
asistentes = input('¿Entre cuántas personas hay que repartir? ')
print('Tocamos a', auxiliar.importe(float(total_factura), float(asistentes)))

# auxiliar.py

def importe(cuenta, comensales):
    return cuenta/comensales

El programa simplemente calcula cuánto tiene que pagar cada comensal en una comida en grupo en un restaurante. En el fichero auxiliar.py está definida la función que calculará la división. Obviamente, no es necesario escribir una función para eso, pero lo he hecho para poder justificar un segundo fichero en el proyecto.

>>> 
¿A cuánto asciende la broma? 200
¿Entre cuántas personas hay que repartir? 10
Tocamos a 20.0

Vamos a provocar, deliberadamente un error en tiempo de ejecución. Tal como está escrito, el programa se halla indefenso ante un intento de división por cero:

>>> 
¿A cuánto asciende la broma? 200
¿Entre cuántas personas hay que repartir? 0
Traceback (most recent call last):
  File "C:\Users\javier\My Dropbox\pythonprad\pruebas\principal.py", line 8, in <module>
    print('Tocamos a', auxiliar.importe(total_factura, asistentes))
  File "C:\Users\javier\My Dropbox\pythonprad\pruebas\auxiliar.py", line 4, in importe
    return cuenta/comensales
ZeroDivisionError: division by zero

Como puedes comprobar, Python es muy generoso a la hora de proporcionar información sobre lo sucedido. Se ha provocado un ZeroDivisionError que ha hecho abortar el programa. Te indica además qué lineas de código provocaron el error y dónde están ubicadas. En el módulo principal, en el momento de la invocación y, en última instancia, en el auxiliar al realizar una operación no permitida.

Con esos datos, sólo te resta dirigirte al lugar donde se localiza el error y subsanarlo.

IDLE dispone de un modo muy rápido de hacerlo. Haz clic con el botón derecho sobre cualquier lugar de la línea que contiene la localización del error. Se te abrirá un pequeño menú contextual con la única opción:

Go to file/line

Haz clic y te aparecerá inmediatamente el módulo que contiene el error, posicionado en la línea crítica que lo provocó. Como aparecieron dos errores, uno en cada módulo, en función del lugar donde hagas clic con el botón derecho te llevará a uno u otro.

Ahora sólo falta subsanarlo:

# principal.py
# Cálculo del importe por comensal

import auxiliar

total_factura = input('¿A cuánto asciende la broma? ')
asistentes = input('¿Entre cuántas personas hay que repartir? ')
if asistentes == '0':
    print('¿Me estás vacilando o qué?')
else:
    print('Tocamos a', auxiliar.importe(float(total_factura), float(asistentes)))

O, mucho mejor aún:

# principal.py
# Cálculo del importe por comensal

import auxiliar

total_factura = input('¿A cuánto asciende la broma? ')
asistentes = input('¿Entre cuántas personas hay que repartir? ')
try:
    print('Tocamos a', auxiliar.importe(float(total_factura), float(asistentes)))
except:
    print('¿Me estás vacilando o qué?')

De este modo estaremos protegiendo nuestro código no sólo ante una eventual división entre cero, sino también ante la introducción por parte del usuario de un valor que no pudiera ser convertido a número:

>>> 
¿A cuánto asciende la broma? 200
¿Entre cuántas personas hay que repartir? pimiento
¿Me estás vacilando o qué?

Hablaremos del bloque try y la captura de excepciones en un artículo posterior.

En este caso el ejemplo era sumamente simple, pero tu proyecto podría estar compuesto de centenares de líneas dispuestas en varios ficheros. Desplazarse al punto en el que se ha producido un error puede ser una tarea incómoda. IDLE lo logra instantáneamente, pero tienes que conocerte el truco. Por lo general, dominar un IDE supone aprender un buen puñado de trucos así, pero es un esfuerzo que te ahorrará mucho tiempo, especialmente si pasas muchas horas programando.

Javier Montero Gabarró


Python: Conoce tu IDLE


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python – Detectando la plataforma

Objetivo: detectar en Python la plataforma sobre la que se está ejecutando un programa.

Aprender a programar no es una tarea que termina cuando uno conoce ya los rudimentos del lenguaje (estructuras de datos, control del flujo, funciones, etc.). En cierto modo se podría decir que es a partir de ese punto donde empieza la verdadera labor del programador, momento en el cual se sumerge a investigar en la periferia de librerías que orbitan alrededor del lenguaje en sí.

Uso indistintamente los términos biblioteca y librería. Aunque la primera es, estrictamente, la traducción correcta de library, librería es un término ampliamente aceptado por la comunidad de programadores.

Las librerías extienden la funcionalidad del lenguaje y nos acercan al mundo real, a los problemas cotidianos que todo programador debe afrontar. Nos ayudan a no tener que reinventar la rueda. Ponen a nuestro alcance herramientas con código ampliamente demostrado que resuelven problemas concretos. Además, pueden abstraer una determinada realidad ahorrándonos tener que aprender su funcionamiento interno. Por ejemplo, mi propio cliente de Twitter, desarrollado en Python, hace un uso intensivo de la librería de terceros Tweepy, que encapsula el API de Twitter y me evita tener que invertir tiempo aprendiendo sus pormenores.

Su importancia es tal, que muchas veces la decisión de aprender o no un determinado lenguaje viene marcada por la capacidad de poder utilizar las librerías asociadas.

Ese es uno de los motivos por los que recomiendo no casarse con ningún lenguaje y aprender cuantos más mejor: para poder tener acceso a un vasto universo de colecciones de clases, módulos y funciones que de ese modo tendremos a nuestra disposición.

Python, además de contar con un fabuloso conjunto de librerías de terceros, es famoso especialmente por suministrarse pilas incluidas, haciendo mención a la inmensa biblioteca estándar a la que se tiene acceso desde el mismo momento en que se instala Python.

El programa que realizaremos hoy tiene una misión muy simple: reflejar mi opinión sobre qué plataforma es mejor, Linux, Mac o Windows.

Aunque quien ejecute el programa no lo sepa, lo cierto es que esa discusión me trae sin cuidado y las tres me parecen sobresalientes. El programa será diplomático y responderá lo que el usuario quiere oir, que probablemente coincidirá con el sistema operativo desde el cual está trabajando en ese momento.

El módulo sys, disponible en la librería estándar de Python, abstrae muchos de los detalles de la arquitectura subyacente. Entre ellos se encuentra el que buscamos:

sys.platform

Contiene una cadena de caracteres con la plataforma en la que se está ejecutando el programa.

Obsérvalo en acción:

# ¿Qué plataforma es mejor, Linux, Mac o Windows?

import sys

plataforma = sys.platform

if plataforma == 'linux':
    print('Sin lugar a dudas, donde esté el pingüino que se quite todo lo demás')
elif plataforma == 'darwin':   # La firma del Mac
    print('Siempre he sentido simpatía por la manzana, se nota dónde hay calidad')
elif plataforma == 'win32':
    print('Abrid las ventanas, que entre la luz...')
else:    # Para otros sistemas y variantes de Unix
    print('No me gusta ninguno de los tres; ¿coincides conmigo?')

Si lo ejecuto desde el PC desde el que escribo estas líneas, me devuelve:

>>> 
Abrid las ventanas, que entre la luz...

Este código puede presentar problemas si utilizas versiones de Python anteriores a 3.3. En estas, a la respuesta ‘linux‘ se le agregaba un sufijo numérico indicando la versión mayor de kernel, de modo que la comprobación, tal como aparece en el programa, no detectaría la plataforma. En ese caso es mejor que se realice comprobando si comienza por ‘linux‘ en vez de si se produce una coincidencia exacta.

El método startswith, aplicable a una cadena de caracteres, devuelve True si la cadena comienza por los caracteres facilitados como parámetro.

>>> s = 'pradera'
>>> s.startswith('prad')
True

Sustituye, entonces la expresión

plataforma == 'linux'

por

plataforma.startswith('linux')

y la detección se realizará correctamente.

Consulta la documentación de Python y tómate la molestia de revisar lo que el módulo system puede ofrecerte, como saber la versión de Python que se está ejecutando, o el path de búsqueda de módulos.

Y, por lo general, esfuérzate en conocer la biblioteca estándar de Python. Cada módulo que incorpores a tu kit de herramientas te hará subir de nivel como programador.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2013/02/python-detectando-la-plataforma/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Una función para iterar sobre listas anidadas

Objetivo: crear una función que ilustre cómo iterar sobre listas anidadas de cualquier profundidad.

Un lector del blog me planteaba ayer una interesante cuestión al hilo del artículo dedicado a la iteración sobre una lista con la sentencia for. Se preguntaba cómo proceder en el supuesto de que se tratara de listas anidadas en las que no conocemos a priori su profundidad de anidación.

Por ejemplo, supongamos que deseamos imprimir todos los enteros existentes en la siguiente lista:

lista_anidada = [1, [2, [3, 4, [5, 6], 7]], 8, [9, 10]]

Observa que el segundo elemento, que es el que presenta mayor nivel de anidación, es en realidad otra lista, cuyo segundo elemento es a su vez otra lista de la cual el tercer elemento es otra lista también. En este ejemplo en particular nos encontramos hasta cuatro niveles de profundidad. Nuestra función deberá ser genérica, en el sentido de que no conocerá de antemano la complejidad de la lista.

Una iteración ordinaria nos devolvería el siguiente resultado:

for elemento in lista_anidada:
    print(elemento)

1
[2, [3, 4, [5, 6], 7]]
8
[9, 10]

No nos sirve, pues pretendemos recuperar todos los elementos simples.

Procederemos de la siguiente forma:

Vamos a recorrer la lista de principio a fin. Si el elemento a tratar es una lista habrá que imprimir sus elementos individuales; si no lo es, imprimimos directamente su valor.

Observa con cuidado la frase «si el elemento a tratar es una lista habrá que imprimir sus elementos individuales». Es exactamente el mismo problema que al inicio, salvo que está reducido a un subconjunto más reducido: la lista anidada dentro de la lista.

Al resolver esta segunda cuestión nos aparecería nuevamente una lista anidada, esta vez del tercer nivel; el problema seguiría siendo exactamente el mismo, pero cada vez más reducido.

Escenario perfecto para una función recursiva

Para resolver la parte que dice «si el elemento a tratar es una lista», recurriremos a una función de Python que nos permite saber si un objeto es o no de un tipo determinado: isinstance().

Obsérvala en acción:

>>> a = 5
>>> b = 'casa'
>>> c = [1, 2]
>>> isinstance(a, list)
False
>>> isinstance(b, list)
False
>>> isinstance(c, list)
True

Implementar nuestra función resulta ya una tarea casi obvia:

def imprimir(lista):
    for elemento in lista:
        if isinstance(elemento, list):
            imprimir(elemento)
        else:
            print(elemento)

Fíjate en la técnica recursiva: si elemento es una lista, la función vuelve a llamarse a sí misma, pero esta vez sobre una lista anidada en el siguiente nivel de profundidad. Y así sucesivamente, ahondando todo lo necesario hasta que no quede un entero sin imprimir.

def imprimir(lista):
    for elemento in lista:
        if isinstance(elemento, list):
            imprimir(elemento)
        else:
            print(elemento)

lista_anidada = [1, [2, [3, 4, [5, 6], 7]], 8, [9, 10]]

imprimir(lista_anidada)

>>> 
1
2
3
4
5
6
7
8
9
10

No se salva ni el apuntador.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2013/02/python-una-funcion-para-iterar-sobre-listas-anidadas/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Un programa para la conversión de decimal a binario

Objetivo: crear una función en Python para la conversión de decimal a binario y, por extensión, a cualquier otra base.

Convertir a binario un número decimal es algo que no supone ningún misterio en Python:

>>> bin(81)
'0b1010001'

Incluso el proceso inverso, de binario a decimal, es simple:

>>> int('1010001', 2)
81

Pero la gracia, cuando uno aprende a programar, está en tratar de desarrollar el sexto sentido algorítmico, una faceta a menudo descuidada.

De modo que en el artículo de hoy diseñaremos nuestra propia función encargada de convertir un número decimal a binario, que después extenderemos para expresarlo en cualquier otra base.

Con frecuencia, descubrir el algoritmo subyacente implica realizar la tarea a mano prestando mucha atención a nuestros procesos mentales, convertirlos en palabras y transformarlos después en instrucciones propias del lenguaje de programación.

El ejemplo que nos atañe es sencillo, pues existe una correspondencia prácticamente directa entre nuestro proceso mental y el desarrollo formal, pero no siempre la hay y, en esos casos, es preciso atomizar lo que está pasando por nuestra cabeza.

En la escuela nos enseñan (o, al menos, enseñaban) el procedimiento para convertir a binario un número entero positivo en base decimal:

Dividimos el número entre dos y anotamos el resto de la división. Tomamos el cociente y lo dividimos entre dos, anotando el nuevo resto. Cogemos el nuevo cociente y continuamos la misma operación hasta que no podemos seguir adelante, pues el cociente ya es inferior a dos (uno, en las conversiones a binario). Tomamos entonces ese cociente (uno) y le agregamos, en orden inverso de aparición, todos los restos que hemos ido anotando en el camino.

Vamos a convertir, por ejemplo, 81 a binario:

81 : 2 = 40; Resto: 1
40 : 2 = 20; Resto: 0 
20 : 2 = 10; Resto: 0
10 : 2 = 5; Resto: 0
5 : 2 = 2; Resto: 1
2 : 2 = 1; Resto: 0

Ya no podemos seguir dividiendo entre dos, pues el cociente es uno. Tomamos este cociente, junto a todos los restos en orden inverso y encontramos 81 expresado en binario:

1010001

Nuestro algoritmo va a hacer exactamente lo mismo.

def binarizar(decimal):
    binario = ''
    while decimal // 2 != 0:
        binario = str(decimal % 2) + binario
        decimal = decimal // 2
    return str(decimal) + binario

La variable binario es un string que va acumulando cada resto. Observa su construcción, agregando a la izquierda cada nuevo resto.

La variable decimal parte con el número original, pero en cada iteración toma el valor del nuevo cociente resultado de la división entera. El bucle se repetirá continuamente mientras ese cociente sea distinto de cero. En ese momento, el anterior cociente (un uno), será el dígito más significativo del resultado, devuelto con la sentencia return.

Veamos en acción esta función:

def binarizar(decimal):
    binario = ''
    while decimal // 2 != 0:
        binario = str(decimal % 2) + binario
        decimal = decimal // 2
    return str(decimal) + binario

numero = int(input('Introduce el número a convertir a binario: '))
print(binarizar(numero))

>>> 
Introduce el número a convertir a binario: 81
1010001

Para convertir a cualquier otra base el procedimiento es exactamente el mismo, salvo que en lugar de realizar la división entera entre dos la hacemos en la nueva base.

def cambio_base(decimal, base):
    conversion = ''
    while decimal // base != 0:
        conversion = str(decimal % base) + conversion
        decimal = decimal // base
    return str(decimal) + conversion

numero = int(input('Introduce el número a cambiar de base: '))
base = int(input('Introduce la base: '))
print(cambio_base(numero, base))

>>> 
Introduce el número a cambiar de base: 81
Introduce la base: 5
311

Y ahora una conversión a octal:

>>> 
Introduce el número a cambiar de base: 81
Introduce la base: 8
121

Para hacer pruebas, evita utilizar bases superiores a 10, pues no disponemos de dígitos suficientes para mostrar el resultado. O bien puedes modificar el programa y crearte tus propios dígitos empleando letras del abecedario, como en el sistema hexadecimal.

Ejercicio propuesto 1: crea una función que convierta un número decimal a base 16 (hexadecimal). Necesitarás una especie de tabla que transforme los resultados del resto 10, 11, 12,…, 15 en A, B, C, …, F, respectivamente.

Ejercicio propuesto 2: crea una función que transforme de binario a decimal.

Ejercicio propuesto 3: crea una función que convierta a decimal un número expresado en cualquier otra base.

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2013/01/python-un-programa-para-la-conversion-de-decimal-a-binario/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: El calificador de ámbito nonlocal

Objetivo: presentar el calificador de ámbito de variable nonlocal.

En la anterior entrega presentamos el concepto de ámbito de una variable y llegamos a una serie de conclusiones:

– Una variable creada en el interior de una función es local y solo existe dentro de ella.

– Las variables creadas a nivel de módulo son globales en el sentido de que son accesibles, además de por el propio módulo, por todas las funciones definidas dentro de él. No obstante, solo son modificables por el propio módulo; las funciones sólo pueden consultar su valor.

– Para modificar una variable global desde dentro de una función es necesario que aparezca declarada como global en el cuerpo de la función.

Vamos a introducir un nuevo nivel de complejidad atendiendo a una característica muy interesante de Python: una función puede incluir definiciones de otras funciones; es decir, la definición de función es anidable.

El Ejemplo 1 ilustra esto de un modo sencillo:

# Ejemplo 1

def f1():
    
    def f2():
        nivel2 = 2
        print(nivel0, nivel1, nivel2)
        
    nivel1 = 1
    f2()
    print(nivel0, nivel1)

nivel0 = 0
f1()
print(nivel0)

Observa que la definición de la función f1() incluye la definición de la función f2().

He definido tres variables en ámbitos distintos: nivel0 a nivel de módulo, nivel1 dentro de la función f1() y nivel2 dentro de f2(), que a su vez está anidada dentro de f1().

Comencemos analizando la función más interior, f2(). En ella se crea la variable local nivel2 y se imprime su valor, junto al de las variables nivel0 y nivel1, que pertenecen, respectivamente, al módulo y al ámbito de f1().

Esto ilustra un concepto importante: una función puede acceder como consulta a todas las variables de los ámbitos en los que está contenida su definición. f2() está contenida en f1(), que a su vez lo está en el módulo principal.

La función f1(), además de definir f2(), crea la variable local nivel1, invoca a f2() e imprime las variables nivel0 y nivel1.

Finalmente, el módulo principal define f1(), crea nivel0, invoca f1() e imprime a continuación el valor de nivel0.

Este es el resultado de la ejecución. Es recomendable que sigas paso a paso su ejecución para asegurarte de que entiendes esta salida.

>>> 
0 1 2
0 1
0

Hay que tener muy claro el sentido de la visibilidad. Desde el módulo principal, cualquier intento de acceder a nivel1 o a nivel2 resultaría en error, del mismo modo que desde f1() tampoco podríamos acceder a nivel2. Por el contrario, en sentido contrario, yendo de menos a más si podemos acceder a las variables, pero solo en modo consulta.

Si desde f1() quisiéramos no solo consultar, sino además modificar el valor de la variable a nivel de módulo, nivel0, ya hemos visto que debemos utilizar el calificativo global, como ilustra el Ejemplo 2:

# Ejemplo 2

def f1():
    
    def f2():
        nivel2 = 2
        print(nivel0, nivel1, nivel2)
        
    nivel1 = 1
    global nivel0
    nivel0 = 5
    f2()
    print(nivel0, nivel1)

nivel0 = 0
f1()
print(nivel0)

>>> 
5 1 2
5 1
5

De igual modo, desde la función más interna, f2(), también podríamos modificar la variable de módulo nivel0 usando el calicativo global:

# Ejemplo 3

def f1():
    
    def f2():
        nivel2 = 2
        global nivel0
        nivel0 = 6
        print(nivel0, nivel1, nivel2)
        
    nivel1 = 1
    f2()
    print(nivel0, nivel1)

nivel0 = 0
f1()
print(nivel0)

>>> 
6 1 2
6 1
6

Y ahora la pregunta del millón… ¿Y si quisiéramos modificar la variable nivel1 desde dentro de f2()?

La respueta NO es global, como se ve en el Ejemplo 4:

# Ejemplo 4

def f1():
    
    def f2():
        global nivel1
        nivel1 = 7
        nivel2 = 2
        print(nivel0, nivel1, nivel2)
        
    nivel1 = 1
    f2()
    print(nivel0, nivel1)

nivel0 = 0
f1()
print(nivel0)

>>> 
0 7 2
0 1
0

Observa con cuidado este resultado: la primera línea corresponde a la impresión de f2(). Como vemos, ha impreso el valor 7, correspondiente a nivel1. Sin embargo, la siguiente línea, que corresponde a la impresión propia de f1(), un instante después, nos demuestra que el valor de nivel1 no ha sido cambiado, manteniendo su valor 1 dentro de f1.

La cuestión es que el calificativo global solo puede usarse para variables globales a nivel de módulo. Para poder modificar la variable a nivel de función nivel1, necesitamos un nuevo calificador: nonlocal.

El código siguiente es exacto al anterior, pero cambiando la palabra global por nonlocal.

# Ejemplo 5

def f1():
    
    def f2():
        nonlocal nivel1
        nivel1 = 7
        nivel2 = 2
        print(nivel0, nivel1, nivel2)
        
    nivel1 = 1
    f2()
    print(nivel0, nivel1)

nivel0 = 0
f1()
print(nivel0)

Esta vez sí: hemos logrado modificar nivel1 desde dentro de f2():

>>> 
0 7 2
0 7
0

En el Ejemplo 6 modificamos, desde dentro de f2() tanto nivel0 como nivel1. Observa el uso combinado de global y nonlocal:

# Ejemplo 6

def f1():
    
    def f2():
        global nivel0
        nonlocal nivel1
        nivel0 = 8
        nivel1 = 9
        nivel2 = 2
        print(nivel0, nivel1, nivel2)
        
    nivel1 = 1
    f2()
    print(nivel0, nivel1)

nivel0 = 0
f1()
print(nivel0)

>>> 
8 9 2
8 9
8

Moraleja: utiliza global para poder modificar una variable creada a nivel de módulo desde dentro de una función definida en ese módulo, aunque esté anidada dentro de otra función; utiliza nonlocal para modificar una variable creada a nivel de función desde otra función definida dentro de aquella.

Javier Montero Gabarró


Python: El calificador de ámbito nonlocal


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Funciones para ricos y funciones para pobres

Objetivo: mostrar que las funciones son objetos e ilustrar su uso como argumentos de otras funciones.

Lo hemos dicho ya en alguna que otra ocasión: en Python todo son objetos. Incluso una función es un objeto.

Obsérvalo:

>>> def saluda(nombre):
  print('Hola', nombre)

>>> saluda('Javier')
Hola Javier

>>> type(saluda)
<class 'function'>
>>> print(saluda)
<function saluda at 0x02500078>

Esta circunstancia nos permite ciertos usos que pueden parecer estrambóticos a simple vista. Si una función es un objeto, tiene derecho a que se le trate como tal, bajo riesgo de protestar por agravio comparativo.

Entre otras cosas, tiene derecho a que se use su nombre en asignaciones:

>>> bienvenida = saluda

De modo que ya podemos realizar invocaciones como:

>>> bienvenida('Pedro')
Hola Pedro

Ambos nombres, saluda y bienvenida, referencian al mismo objeto función:

>>> id(bienvenida)
38797432
>>> id(saluda)
38797432

El nombre de una función también puede ser pasado como argumento de otra función.

Vamos a ilustrarlo con un ejemplo muy sencillo. Imagínate que tenemos dos funciones de tarificación diferentes por un mismo servicio. A los clientes normales les aplicaremos un rasero, pero a los más pudientes les daremos una pequeña clavada y su factura será mayor.

def tarifar(horas):
    importe = horas * 20 # Cobramos 20 euros la hora
    return importe

def tarifarplus(horas):
    importe = horas * 60 # Cobramos 60 euros la hora
    return importe

La función tarifar() toma como argumento el número de horas trabajadas y devuelve el importe correspondiente a una tasa de 20 euros la hora. La función tarifarplus() tiene como diferencia el pequeño detalle de que el precio por hora es mayor.

Observa ahora la definición de esta otra función:

def facturar(funcion_tarificacion, horas):
    return funcion_tarificacion(horas)

Como argumentos le pasaremos, además de las horas empleadas, el nombre de la función con la que realizaremos la facturación, función que será empleada para devolver el importe final.

Veamos un ejemplo de invocación de la función facturar() en un intérprete interactivo:

Si tienes poco dinero:

>>> facturar(tarifar, 5)
100

Pero, si te sobra la pasta, te mereces pagar más:

>>> facturar(tarifarplus, 5)
300

Justicia social.

Javier Montero Gabarró


Python: Funciones para ricos y funciones para pobres


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: Iterando y modificando una lista

Objetivo: presentar técnicas de iteración sobre listas que permitan su modificación in-situ.

Comencemos planteando el siguiente problema: tenemos una lista de números y queremos modificarla de modo que almacene, en lugar del número en sí, su cuadrado.

No parece un problema complejo que no sepamos resolver con lo que ya conocemos:

lista = [1, 2, 3, 4, 5]

for elemento in lista:
    elemento = elemento * elemento
    print(elemento) # Una simple verificación

Si ahora observamos la salida:

>>> 
1
4
9
16
25

Aparenta todo haber ido de maravilla; sin embargo, nos encontramos con un pequeño detalle importante:

>>> lista
[1, 2, 3, 4, 5]

¡La lista no ha cambiado!

¿Cómo es posible? ¿Acaso no hemos comprobado como elemento, que ha pasado sucesivamente por todos y cada uno de los elementos de la lista, ha actualizado su valor a elemento * elemento?

Así es. Pero, lo que sucede, es que elemento no es más que una copia del valor original. Por muchos cambios que efectuemos sobre él no afectaran a la lista.

Necesitamos cambiar de estrategia.

Una forma de salvar el escollo sería reconstruir una lista temporal con los nuevos valores al cuadrado.

lista = [1, 2, 3, 4, 5]

lista_temp = []

for elemento in lista:
    elemento = elemento * elemento
    print(elemento)
    lista_temp.append(elemento)

La lista temporal, lista_temp es, en principio, una lista en blanco. Con cada iteración le agregamos el nuevo valor de elemento mediante el método append().

lista_temp ya tiene la solución buscada:

>>> lista
[1, 2, 3, 4, 5]
>>> lista_temp
[1, 4, 9, 16, 25]

Si lo necesitamos, podemos reasignar hacia dónde apunta lista:

>>> lista = lista_temp
>>> lista
[1, 4, 9, 16, 25]

En un nivel mayor de elegancia (en Python, la elegancia suele coincidir con el menor número de líneas de código), está la siguiente técnica: recorriendo el bucle for a través de el índice de la lista en vez de sus elementos. Es decir, como si fuera un bucle for típico de cualquier otro lenguaje de programación:

lista = [1, 2, 3, 4, 5]

for indice in range(len(lista)):
    lista[indice] = lista[indice] * lista[indice]
    print(lista[indice])

El resultado es el que esperamos:

>>> 
1
4
9
16
25
>>> lista
[1, 4, 9, 16, 25]

No solo la impresión es correcta, sino que la lista ha sido actualizada in-situ. Desde el bucle for, a través del índice, hemos podido acceder directamente a la lista, no a una copia de ella.

Apréndete bien esta técnica, pues es muy común. Itera sobre los elementos o los índices según tu necesidad concreta.

Date cuenta de que, para poder iterar a través de los índices, necesitamos conocer el número de elementos totales de la lista. Esto lo obtenemos con la expresión len(lista). Recuerda que la función len() nos devuelve el total de elementos de una secuencia. A continuación la función range() nos construye un iterable: range(len(lista)) facilitará al bucle for, sucesivamente, todos los valores enteros desde cero hasta uno menos que la longitud de la lista, precisamente el mismo rango que tienen sus índices.

Existe un nivel mayor de elegancia aún, las listas por comprensión, una de las construcciones más fascinantes y poderosas de Python. Son merecedoras de uno o varios artículos por separado, pero no me gustaría despedirme hoy sin que, al menos, y a modo de aperitivo, compruebes su potencia:

lista = [1, 2, 3, 4, 5]
lista = [elemento * elemento for elemento in lista]

Así de elegante:

>>> lista
[1, 4, 9, 16, 25]

Bienvenido a Python.

Javier Montero Gabarró


Python: Iterando y modificando una lista


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Productividad aleatoria ponderada en Python

Este artículo, que he clasificado en las categorías «Productividad» y «Python» es peculiar porque mata dos pájaros de un tiro: puede resultar útil tanto al lector interesado en lograr un mayor rendimiento como al estudiante de Python. Se explica una técnica de productividad y a continuación se muestra cómo automatizarla utilizando el lenguaje de programación Python.

En Productividad aleatoria describí un método al que recurro con frecuencia para estimular mi rendimiento al enfrentarme a un conjunto de tareas pendientes de índole diversa.

La esencia del método consiste en dejar que sea el azar el que decida cuál será la siguiente tarea a ejecutar. Esto supone los siguientes beneficios:

Evita perder tiempo decidiendo nuestra siguiente ocupación. ¿Eres capaz de evaluar cuánto tiempo malgastas mareando la perdiz a lo largo del día, decidiendo qué hacer? Calcúlalo y quizás te lleves una sorpresa.

– Dota de un componente lúdico a nuestro sistema de productividad, haciéndolo más divertido y motivante. Es un juego que se rige con reglas sencillas: la suerte está echada y nuestra misión consiste en ejecutar la tarea con eficacia y eficiencia, sin rechistar ni cuestionar si otra labor nos resulta más apetecible.

– Todas las tareas, las que nos gustan más y las que no tanto, están incluidas en el bombo de la fortuna. A menudo solemos postergar las menos atractivas, que probablemente son las más importantes, de modo que no encontramos nunca tiempo para hacerlas. El azar no entiende de preferencias personales y poco a poco irás liquidando todas esas tareas ingratas pero necesarias.

En el artículo sugerí un método sencillo para la gestión aleatoria de tareas que sólo precisaba de dos herramientas: un editor de texto plano y un generador de números aleatorios. Recordémoslo con algo más de detalle.

Como editor de texto sirve cualquiera que incluya numeración de líneas, como Notepad++ o gedit, entre muchísimos otros. Para la elección de un número al azar puedes utilizar el widget de random.org que figura en la esquina inferior izquierda de esta página.

La forma de operar es sencilla: una tarea en cada línea del fichero y que el generador de números aleatorios decida cúal elegimos entre el total de líneas existentes.

Por eso me he referido a un editor de texto plano en lugar de un procesador de textos. En un editor de texto plano no hay cambio de línea lógica hasta que no se pulsa ENTER. Aunque el programa divida la línea lógica en más líneas físicas, en el caso de que no quepa entera en el ancho de la ventana, el número de línea sigue siendo el mismo.

Obsérvalo en el siguiente ejemplo:

Las líneas 3 y 6 no caben enteras en el ancho de la ventana establecido, pero el número de línea se mantiene el mismo.

Una vez tenemos el listado de tareas candidatas sólo resta elegir una al azar. En nuestro ejemplo, habría que elegir un número entre 1 y 9:

Localizamos la línea 8 en el fichero y esa será nuestra próxima tarea a realizar: «Revisión y actualización de un artículo del blog con más de un año de antigüedad».

Podemos refinar el método introduciendo la gestión de prioridades. Sería deseable que las tareas más importantes, aquellas que nos hacen avanzar hacia nuestros principales objetivos, tuviesen más «papeletas» en el sorteo que las que menos contribuyen. Para lograr esto basta con repetir la tarea en la lista las veces que consideremos necesarias, aumentando así su peso específico y la probabilidad de que resulten elegidas.

Para ahorrar tiempo, en vez de repetir la tarea, agregaremos líneas en blanco debajo de ella (como cuando usamos pares de comillas bajo de un texto para indicar que es una repetición exacta de él). Basta con tener presente que una línea en blanco hace mención a la tarea encima de ella.

Obsérvalo en el ejemplo:

Hemos dejado un espacio en blanco después de la tarea 3 y dos después de la 8. Esto es lo mismo que si hubiéramos repetido la tarea en esos huecos, pero se tarda menos con una simple pulsación de ENTER. De este modo, estamos indicando que las tareas 3 y 8 tienen un peso específico de 2 y 3, respectivamente; es decir, la tarea 3 tiene dos veces más probabilidades de salir elegida que cualquier otra ordinaria, y la 8 tres veces más.

Si ahora la elección de la linea al azar recayera en una línea en blanco, como la 4, la tarea elegida sería la inmediatamente superior que estuviera ocupada, es decir, la 3: «Preparar un solo para Joe Ibuprofeno y transcribirlo en solfeo y tablatura con Guitar Pro».

Si no estás interesado en la programación en Python, puedes abandonar ya la lectura del artículo, pues lo que resta de él está dedicado a la creación de un pequeño programa que seleccione, entre todas las tareas definidas y ponderadas en el fichero tareas.txt, una al azar.

Nuestra labor será dotar de contenido al fichero, que el programa se ocupará de la elección automáticamente.

Mostraremos algunas técnicas nuevas no presentadas aún en el blog, como:

– Apertura un fichero de texto que emplea una codificación diferente a la del nativa del sistema operativo sobre el que corre el intérprete Python.

– Recuperación de una línea concreta de un fichero de texto.

– Comprobación de si una línea está en blanco o no.

Para la función aleatoria, necesitaremos importar el módulo random, en el que está definida la función randint(), que emplearemos para la elección de un número entero al azar.

import random

Lo primero que realiza el programa es recuperar todas las líneas del fichero de tareas y almacenarlas en una lista:

fichero = open('tareas.txt', encoding = 'utf-8')
tareas = fichero.readlines()
fichero.close()

La primera línea abre el fichero tareas.txt en modo texto y lectura, opciones por omisión cuando no se especifica nada más. Pero fíjate en la novedad, el parámetro encoding = 'utf-8'.

Python, cuando abre un fichero de texto, necesita saber cómo está codificado para poder interpretarlo correctamente. Si no decimos nada en la función open(), Python, por defecto, asume que está codificado en el modo nativo propio del sistema operativo en el que está corriendo el intérprete. Yo suelo emplear utf-8, una de las maneras de codificar caracteres Unicode, pero Python no tiene forma de saber que mi fichero está empleando ese formato salvo que se lo diga expresamente. El parámetro extra que hemos empleado en open() se ocupa de notificárselo.

Vemos en acción, a continuación, el método readlines() que, como sabemos, rellena una lista en la que cada elemento es una línea del fichero.

Esta es una técnica sencilla que debe figurar en tu repertorio para procesar ficheros de texto:

1) Abre el fichero en modo lectura.
2) Carga su contenido en una lista.
3) Cierra el fichero.
4) Procesa la lista con el contenido del fichero.
5) Abre el fichero en modo escritura (destruyendo el anterior).
6) Vuelca la lista procesada al fichero con el método writelines().
7) Cierra el fichero.

En este ejemplo no serán necesarios los tres pasos últimos, pues no vamos a modificar el fichero. Más adelante contruiremos otros programas sencillos que requerirán las siete etapas.

Una advertencia importante: esta técnica no es más que eso, una técnica. Existen otras formas de trabajar con ficheros de texto, como veremos, que serán más adecuadas que esta en determinadas ocasiones. La presentada aquí tiene una limitación: todo el contenido del fichero se vuelca en memoria. Si la memoria de la que dispone Python es inferior al tamaño del fichero el programa no funcionará.

No uses este método para ficheros muy grandes. En estos casos es preferible que la recuperación del archivo se realice en bloques controlados, liberando la memoria cada vez que se cargue un nuevo bloque tras su proceso.

Cerramos el fichero tan pronto hemos terminado con él. No necesitaremos acceder nuevamente a él.

Para elegir un número de línea al azar, primero debemos saber cuántas líneas hay. Como cada elemento de la lista contiene una única línea, el total de elementos será el total de líneas:

len(tareas)

Hay que elegir una de ellas: la primera en la lista tiene por índice cero, por lo que la última tendrá por índice el total de elementos de la lista menos 1:

len(tareas) - 1

Para elegir un entero al azar entre cero y len(tareas) – 1, usamos la función randint() indicando esos extremos como parámetros:

random.randint(0, len(tareas) - 1)

Recuperamos, entonces, el elemento de la lista que tiene ese índice elegido al azar:

tarea_aleatoria = tareas[random.randint(0, len(tareas) - 1)]

Esa sería la línea buscada, si no fuera porque podría suceder que se tratara de una línea en blanco. En ese caso, habría que buscar la inmediatamente superior que no lo esté.

Pero, ¿qué caracteriza una línea en blanco?

El único contenido que tiene una línea en blanco es el cambio de línea \n. Con esto, el siguiente bucle while comprueba que la línea no esté en blanco y, si lo está, trata de recuperar el elemento anterior hasta que encuentre una línea que no lo esté:

while tarea_aleatoria == '\n':
    tarea_aleatoria = tareas[random.randint(0, len(tareas) - 1) - 1]

Una vez localizada, la imprimimos y misión cumplida:

print(tarea_aleatoria)

Te dejo el código completo del programa:

# Productividad aleatoria ponderada

import random

fichero = open('tareas.txt', encoding = 'utf-8')
tareas = fichero.readlines()
fichero.close()

tarea_aleatoria = tareas[random.randint(0, len(tareas) - 1)]

while tarea_aleatoria == '\n':
    tarea_aleatoria = tareas[random.randint(0, len(tareas) - 1) - 1]

print(tarea_aleatoria)

Javier Montero Gabarró


http://elclubdelautodidacta.es/wp/2012/11/productividad-aleatoria-ponderada-en-python/


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Índice completo de los artículos de la categoría Productividad.


Consulta el índice completo de artículos relacionados con Python.

Python: Los operadores lógicos y sus tablas de verdad

Objetivo: presentar los operadores lógicos de Python e ilustrar el uso de bucles for anidados para mostrar sus tablas de verdad.

Aunque ya hay una amplia colección de artículos dedicados a Python, debemos admitir que hay bastantes elementos del lenguaje que aún no han sido presentados en familia. Es el caso, por ejemplo, de los operadores lógicos, de los que nos ocuparemos hoy. Mostraremos los distintos tipos y dejaremos que Python construya las respectivas tablas de verdad, ejemplo que nos servirá, a su vez, para ilustrar la anidación de un bucle for dentro de otro.

Con toda certeza que te has cruzado alguna vez en tu vida con los operadores lógicos o, como también se los conoce, booleanos. No tengo intención de darte una clase de álgebra booleana, de modo que nos centraremos directamente en su representación en Python.

Los tres operadores lógicos básicos son O, Y y NO, representados en Python por or, and y not, respectivamente.

Podemos incluir también el O EXCLUSIVO, que es verdadero cuando uno y solo uno de los operandos lo es, pero estrictamente debes saber que se deriva a partir de los tres básicos. Su representación es ^, el sombrero o caret.

Como ejercicio práctico, vamos a realizar un programa que construya las tablas de verdad correspondientes.

booleanos = [False, True]

# Tabla de verdad de or

print('x\ty\tx or y')
print('-'*22)
for x in booleanos:
    for y in booleanos:
        print(x, y, x or y, sep = '\t')

print()

# Tabla de verdad de and

print('x\ty\tx and y')
print('-'*22)
for x in booleanos:
    for y in booleanos:
        print(x, y, x and y, sep = '\t')
        
print()

# Tabla de verdad de not

print('x\tnot x')
print('-'*13)
for x in booleanos:
    print(x, not x, sep = '\t')

print()

# Tabla de verdad de ^

print('x\ty\tx ^ y')
print('-'*21)
for x in booleanos:
    for y in booleanos:
        print(x, y, x ^ y, sep = '\t') 

No te preocupes si algo no te queda claro en el código, en breve lo explicaremos. Antes quiero que observes el resultado final:

Las tablas de verdad hablan por sí solas:

– El resultado de or es verdadero cuando cualquiera de los operandos lo es.
– El resultado de and es verdadero solo cuando ambos operandos lo es.
– El operador not invierte el valor del operando.
– La o exclusiva, ^, es cierta cuando uno y solo uno de los operandos lo es.

El programa no debe de suponerte ningún misterio:

Comenzamos creando una lista con los dos posibles valores booleanos, False y True, que utilizaremos para iterar sobre ellos:

booleanos = [False, True]

Observa que no hemos rodeado los elementos entre comillas, pues no son strings.

A continuación imprimimos los títulos para la operación or:

print('x\ty\tx or y')
print('-'*22)

Los \t en la primera línea no son más que tabuladores. La extraña operación de la segunda, multiplicando un string por un número, no hace más que repetir 22 veces el carácter ‘-‘.

El quid de la cuestión recae en la doble iteración usando el bucle for:

for x in booleanos:
    for y in booleanos:
        print(x, y, x or y, sep = '\t')

La variable x recorrerá la lista booleanos, tomando en la primera iteración el valor False y en la siguiente True. Pero, por cada iteración, aparece una nueva variable y que también recorrerá booleanos de izquierda a derecha. Así garantizamos que se alcanzan las cuatro combinaciones posibles de x e y.

En la impresión con print, hemos empleado el argumento sep = ‘t’ para que separe cada elemento mediante un tabulador, en lugar de usar un espacio en blanco, valor por omisión. Aprecia el uso de la expresión x or y para que muestre el resultado del or.

El resto de las tablas se calcula del mismo modo, simplemente teniendo en cuenta que hay que emplear, naturalmente, la expresión lógica adecuada.

Debes saber que los operadores lógicos de Python son del tipo cortocircuitados, término que quizás te resulte familiar si conoces otros lenguajes de programación. Esto significa que, si a partir del primer operando ya se puede deducir el resultado final, Python ni se molestará en evaluar el segundo, con el consiguiente ahorro de tiempo.

En un or, si el primer operando es verdadero, sabemos que el resultado lo será ya, por lo que no es necesario que Python se moleste en comprobar la veracidad del segundo.

Del mismo modo, en un and, si el primer operando es falso, el resultado inmediatamente lo será y tampoco será necesario saber lo que ocurre con el segundo.

Para finalizar, una pequeña advertencia: es un error común confundir los operadores lógicos (or y and) con los operadores de unión e intersección de conjuntos (| y &). No te equivoques.

Javier Montero Gabarró


Python: Los operadores lógicos y sus tablas de verdad


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Python: MAYÚSCULAS, minúsculas y ViCeVeRsA

Objetivo: presentar los métodos que ofrece Python para la gestión de mayúsculas y minúsculas en strings.

Entre nuestro repertorio de técnicas pythonistas no pueden faltar las dedicadas al tratamiento de cadenas de caracteres. Es raro el programa que no las utiliza, de modo que cuanto antes las conozcas mejor será para ti. Hoy hablaremos de un subconjunto de ellas especializadas en el trasiego de letras mayúsculas y minúsculas.

Un problema común cuando un programa recibe texto es su normalización para poder realizar después un tratamiento correcto. Por ejemplo, imagínate que estás requiriendo el DNI del usuario. Tu programa debe ser capaz de reconocer que dos DNI con los mismos números y la misma letra final son realmente el mismo, se escriba la letra en mayúsculas o minúsculas.

Juguemos un rato con el intérprete interactivo. Consideremos, por ejemplo, la siguiente cadena de texto:

>>> a = 'La casa de la Pradera'

Para hacer que un string contenga sólo letras minúsculas disponemos del método lower():

>>> a.lower()
'la casa de la pradera'

Esto crea una copia del objeto con minúsculas. Recuerda que los strings son inmutables y los métodos que se apliquen sobre ellos nunca modificarán el objeto original. Si no tienes muy claro el misterio de la inmutabilidad en Python, te recomiendo que leas el artículo al que apunta el enlace.

La operación contraria, la conversión a mayúsculas, se obtiene mediante el método upper():

>>> a.upper()
'LA CASA DE LA PRADERA'

El método capitalize() devuelve un string en el que solo la primera letra estará escrita en mayúsculas:

>>> a.capitalize()
'La casa de la pradera'

Aunque pueda resultar extravagante, a veces es necesaria la inversión de tipos: lo que está en mayúsculas pasarlo a minúsculas, y viceversa. El método swapcase() resuelve el problema:

>>> a.swapcase()
'lA CASA DE LA pRADERA'

El método title() escribe en mayúsculas solo la primera letra de cada palabra, como en los títulos:

<code>>>> a.title()
'La Casa De La Pradera'

Para otro tipo de conversiones será necesario recurrir a algo más de código. Considera el siguiente problema: dada una palabra cualquiera, transformarla para que el tercer carácter esté escrito en letras mayúsculas.

Supongamos, por ejemplo, la siguiente cadena de caracteres:

>>> a = 'pradera'

Pretendemos que el tercer carácter esté en mayúsculas.

Este intento de conversión fallará debido a la inmutabilidad de los strings, que no permiten la modificación in-situ:

>>> a[2] = a[2].upper()   # El tercer carácter tiene por índice 2
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    a[2] = a[2].upper()   # El tercer carácter tiene por índice 2
TypeError: 'str' object does not support item assignment

Para resolver el problema podemos recurrir a la creación de substrings mediante la técnica de slicing, que hemos utilizado ya en diversas ocasiones:

>>> a = a[:2] + a[2].upper() + a[3:]
>>> a
'prAdera'

El primer término de la concatenación contiene una copia de a desde el primer elemento (índice cero) hasta el tercero (índice 2) sin incluir. El segundo es una copia del tercer carácter de a. Finalmente, el último contiene lo restante de la cadena, es decir, desde el cuarto elemento (índice 3) hasta el final.

Actividad propuesta: construye una función que acepte como parámetros un string y un número y devuelva un string, con el carácter correspondiente al índice, facilitado por el número, en mayúsculas.

Para finalizar, es útil saber si un string está escrito completamente en letras minúsculas o en mayúsculas. Para ello disponemos de los métodos islower() e isupper(), respectivamente.

>>> a = 'pradera'
>>> a.islower()
True
>>> b = 'PIMiENTO'
>>> b.isupper()
False

El método islower() devuelve True cuando todas las letras están en minúsculas y al menos hay un carácter alfabético. Esto otro, por ejemplo, resultaría False, al no existir ninguna letra en el string:

>>> c = ':;..'
>>> c.islower()
False

En cambio, esto sería True:

>>> d = ':;.a'
>>> d.islower()
True

Lo mismo es aplicable a isupper(): devuelve True cuando todas las letras están en mayúsculas y al menos hay una letra en la cadena.

Son muchos los métodos de los que dipone el objeto string y es tu deber conocerlos. Agruparlos en pequeños bloques, como hemos hoy, facilita su aprendizaje.

Javier Montero Gabarró


Python: MAYÚSCULAS, minúsculas y ViCeVeRsA


El texto de este artículo se encuentra sometido a una licencia Creative Commons del tipo CC-BY-NC-ND (reconocimiento, no comercial, sin obra derivada, 3.0 unported)


El Club del Autodidacta


Consulta el índice completo de artículos relacionados con Python.

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

ACEPTAR
Aviso de cookies