Hacer un
programa en
Python que
pida el
precio de 5
productos y
muestre el
total según
la tasa de
IVA vigente.
@author parzibyte
Recomendados:
Definir una constante en Python: https://parzibyte.me/blog/2019/01/16/constantes-
"""
PORCENTAJE_IVA = 16
conteo_productos = 1 # Saber en cuál producto vamos
precio_total = 0 # Acumulador del total de productos
# Mientras que el conteo del productos sea menor o igual a 5
while conteo_productos <= 5:
mensaje = "Ingresa el precio del producto número {}: ".format(
conteo_productos)
precio_como_cadena = input(mensaje)
# Convertir a flotante
precio = float(precio_como_cadena)
# Agregarlo al precio total
precio_total = precio_total + precio
# Ya leímos un producto, le sumamos al conteo
conteo_productos = conteo_productos + 1
# Cuando el ciclo termine calculamos el IVA
aumento = precio_total * (PORCENTAJE_IVA / 100) # Dividir entre 100 porque es un porcentaje
# Sumar el aumento
precio_con_iva = precio_total + aumento
# Imprimir totales
print("Total: ${}".format(precio_total))
print("IVA: ${}".format(aumento))
print("Total con IVA: ${}".format(precio_con_iva))
En Python no es necesario definir las variables antes de usarlas, a diferencia de C y
similares. Basta con que la declares asignándole un valor. Por ejemplo escribe directamente:
>>> base = 86
>>> iva = base * 0.21
>>> total = base + iva
>>> print (total)
104.06
>>>
Para quienes no hayáis programado nunca os puede parecer bastante normal. Parecen las
operaciones que hacemos en una calculadora o en una hoja de cálculo. La diferencia es
que Python ha memorizado las variables. Prueba con:
>>> print(base, iva, total)
86 18.06 104.06
Pero probablemente a los que vengáis de C, os sorprenderá que no hemos definido el tipo de
las variables como int o float, y sin embargo Python ha aceptado graciosamente la entrada
suponiendo nuestras intenciones, y los ha considerado enteros.
Sería más cómodo si pudiéramos pedir a Python que nos solicite un valor y luego
calculásemos el IVA y el total. Disponemos de una instrucción para pedirle información al
usuario:
base = input ("Dame el precio del artículo, por favor : ")
Python sacará el mensaje que le pasamos entre comillas y esperará a que le demos una
respuesta que se la asignara a la variable base. Si ahora escribes
>>> base = input ("Dame el precio del artículo, por favor : ")
Dame el precio del artículo, por favor : 99
>>> print(base)
99
Fíjate que he escrito artículo con acento. Python 3 se queda tan ancho y reproduce
correctamente los símbolos no USA. Esta es una de los motivos de cambio de Python 2 a 3.
Python 2 solo acepta el código ASCII estándar, mientras que Python 3 trabaja desde
el principio con Unicode para permitirnos este tipo de caracteres.
En Python 2 tendrías problemas escribiendo acentos y Ñs..
Pero tienes que tener cuidado con input porque convierte en String lo que recibe, con
resultados un tanto desconcertantes para los novicios. ¿Qué te parece esto?
>>> print (base * 3)
999999
Python considera a base una String y por eso al intentar multiplicar hace algo que para él es
muy normal (Y para mi) entiende que multiplicar una String por 3 es copiarla 3 veces, y el
resultado es ese.
La sobrecarga de operadores que vimos con C++ y Arduino está integrado dese el
principio en Python.
Es bastante razonable, pero tienes que acostumbrarte porque si no, el intérprete te puede
jugar una mala pasada. De hecho intenta esto:
>>>print (base +1)
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
print (base +1)
TypeError: Can't convert 'int' object to str implicitly
Base es una String y no acepta la conversión implícita y rechaza la operación.
El problema es que Python no está seguro de que conversión implícita queremos.
¿Queremos que el resultado sea un int y entonces el valor seria 99+1 = 100, O por el contrario
queremos que sea una String y el resultado es “991”?.
Y ante la duda, rechaza la operación.
Si no me crees prueba esto:
>>> type(base)
<class 'str'>
Ya ves que él insiste en que base es una String y punto. Si quieres convertirlo en un número
necesitas la función int():
>>> print (int(base) * 2)
198
Para calcular el IVA podemos hacer:
iva = base * 1.21
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
iva = base * 1.21
TypeError: can't multiply sequence by non-int of type 'float'
Ya estamos otra vez. 1.21 es un float y no acepta que lo multipliquemos por un int sin más.
Los tipos tiene que ser iguales y para eso necesitamos la función float()
>>> iva = float(base) * 0.21
>>> print(iva)
21.0
Los nuevos no os asustéis. He querido apretar un poco de más hoy, para demostrar que
aunque no necesitemos definir los tipos, Python no va a pasarnos ni una en cuanto tenga
dudas (A diferencia de C++ que haría conversiones implícitas sobre la marcha)
Vale, con todo esto ya estamos listos para escribir un programa en el editor, que nos pida un
precio y después calculamos IVA y total a partir del precio base (Debidamente convertido a
float o int)
Os propongo que lo intentéis sin mirar la solución que viene a continuación. Recuerda que se
aprende pensando, no copiando.
La salida debería ser algo así:
>>> ========== RESTART: C:\Python35-32\dos.py ================
Dame el precio del artículo, por favor : 100
100.0 21.0 121.0
>>>
Aquí os dejo el primer programita:
# programa para calcular el IVA y total
base = input ("Dame el precio del artículo, por favor : ")
base = float( base)
iva = base * 0.21
total = base + iva
print (base, iva, total)
De paso a provecho para deciros que si empiezas una línea por el símbolo #, Python
considerará toda esa línea como un comentario.
1. Inicio:
2. Escribir: programa que calcule el IVA de un producto.
3. Escribir: Insertar el valor del producto.
4. Leer: El valor del producto (x).
5. Examinar; Realizar la operación (x)(.16)= n.
6. Examinar: Realizar (X+n)=g
7. Escribir: Mostrar el resultado de "g".
8. Fin.
Creación de una función con el comando pass.
La manera intencional de declarar una función que no haga nada pues tiene que
darse con un comando que tampoco haga nada. Os presentamos el
comando pass. Y eso es lo que hace, nada de nada. Mirad este código:
>>> def adios():
... pass #Aquí colocaremos código a futuro
...
>>> adios()
>>>
Como veís, al invocar la función no realiza «nada». Aquí vamos a explicar línea por
línea:
Línea 1: definimos la función con la palabra reservada def seguido de un
espacio y el nombre que hayamos escogido para la función. Luego colocamos
par de paréntesis, uno que abre y otro que cierra, allí luego colocaremos los
argumentos o datos que le queremos pasar a la función. Los dos puntos «:»
indican que la línea no acaba allí, que hay más en líneas siguientes y al
presionar intro observaréis que el prompt pasa a ser «…» y nos invita a escribir
la segunda línea.
Línea 2: en la primera parte de este tutorial hablamos de configurar nuestro
editor de textos para que al presionar la tecla TAB nos inserte espacios en vez
del caracter tabulador. Ahora os rogamos, para cumplir con las normas de
Python.org que lo configuréis exactamente a 4 espacios o que pulséis 4
espacios la primera vez y luego vuestro procesador indentará automáticamente
cada vez que presionéis intro. Así que colocamos el comando pass (que no
hace nada sino gastar 4 bytes en nuestro disco duro al estar guardado en un
archivo). Luego colocamos un comentario sobre lo que pensamos hacer a
futuro con dicha función.
Línea 3: una línea en blanco para poder presionar intro y volver al prompt
interactivo. También debemos dejar una línea en blanco si estuvieramos
escribiendo en un archivo, por razones de legibilidad y claridad en nuestro
código.
Creación de una función útil en la vida real.
Muy bonito estudiar la teoría pero debemos de ser pragmáticos y ponerla a trabajar en
nuestras vidas. Para ello vamos a realizar una función que dado un monto nos calcule
el impuesto a las ventas que debemos pagar (Impuesto al Valor Agregado, I.V.A. o
IVA). En nuestro país, Venezuela, todo eso está normado por la ley y si queréis
revisarlo nosotros hemos publicado una entrada al respecto.
El cálculo es el siguiente: al monto (que llamaremos base gravada o base) le
multiplicamos por la tasa de impuesto y la dividimos entre cien. A la fecha la tasa es
de un 12% pero puede aumentar o disminuir con el paso del tiempo, pero en general
dura meses y hasta años en un mismo valor. Asumiremos entonces que es 12% y
pasamos a escribir la función:
>>> def impuesto(base):
... print('Impuesto a pagar:', round(base*12/100,2))
...
>>> impuesto(100)
Impuesto a pagar: 12
>>>
Rápidamente observamos, en la única linea de la función, como hemos utilizado la
función print() , hemos separados con comas los argumentos para nos imprima un
espacio en blanco entre ellos, y uno de los argumentos le hemos pasado una
funcion round() a su vez con dos argumentos: el cálculo del impuesto en sí y el
número 2 para indicarle que redondee el impuesto a dos decimales ya que así lo
exige la ley (hay ciertos casos como el manejo de moneda extranjera o divisa -por ej.:
€- y venta de hidrocarburos que, debidos a los altos montos, al multiplicar con solo 2
decimales trae mucha diferencia: solo en esos casos se exigen 4 decimales ¿por qué
demonios explicamos esto? Más adelante veréis ).
Por supuesto, el comando pass lo eliminamos y el comentario también, pero no
debemos dejarlo así, siempre debemos agregarle un texto explicativo, no solo para
nosotros a futuro, que se nos pueden olvidar las cosas (¡vamos , a menos que seas
Rainman!) sino para enriquecer a la comunidad de software libre, debemos compartir
nuestras creaciones (y cobrar por el servicio, claro está, el que trabaja se gana su pan
diario). Si con esos argumentos no os hemos convencido aquí va un tercero que es
necesario: Python.org tiene algo llamado docustring que fue diseñado para que se
puedan construir manuales a partir de un formato especial que nosotros agreguemos
a nuestras funciones. ¿Cómo funciona esto? Solamente os decimos que debemos
seguir estudiando cómo escribir funciones y en su oportunidad volveremos a tocar el
tema.
Baste entonces con escribir nuestro comentario encerrado en un entrecomillado triple
para cumplir con Python.org y sus normas, veamos
>>> def impuesto(base):
... ''' Cálculo del IVA a un monto dado '''
... print('Impuesto a pagar:',round(base*12/100,2))
...
>>>
¿A que es más lúcida nuestra función? Pero ojo, ahora vamos a llamar la
función impuesto() tal cual, sin ningún monto y veremos un hermoso error, al traste
con nuestra emoción, pero la computadora está en lo correcto, y si nosotros hemos
fallado ¿qué esperamos entonces de nuestros futuros usuarios de nuestros
programas?
Pues he aquí que vamos a mejorar nuestra función, la versión 0.1, de esta manera:
>>> def impuesto(base=0):
... ''' Cálculo del IVA a un monto dado V. 0.1 '''
... if base==0:
... print('Introduzca un monto mayor que cero.')
... else:
... print('Impuesto a pagar:', round(base*12/100,2))
>>>
Agregamos un valor por defecto así que si al llamar a la función no le pasamos
argumento entonces toma un valor de cero y si el valor es cero imprime un mensaje
invitando a hacerlo. Hemos convertido una función con argumento obligatorio en una
que no lo es. Esto tiene ventajas y desventajas: si no le ponemos valor por
defecto nos obligamos nosotros mismos a ser mejores programadores. Pero como le
pusimos valor por defecto es recomendable que el programa avise que se le está
pasando, así sea verdad o no, un valor cero, por lo tanto el impuesto sería cero y la
función no tendría razón de ser. Si nos equivocaramos programando y en algún punto
llamamos a la función sin argumento con el tiempo recibiremos una hermosa llamada
telefónica de nuestros clientes diciendo algo como «metemos el monto de la base y el
programa dice que introduzcamos un valor mayor que cero«.
Así nuestra función sigue evolucionando: volvemos a colocarla para que sea
obligatoria la base como argumento PERO dejamos el mensaje y lo mejoramos para
manejar valores negativos, la versión 0.2 quedaría así:
>>> def impuesto(base):
... ''' Cálculo del IVA a un monto dado Ver. 0.2 '''
... if base<=0:
... print('Introduzca un monto mayor que cero.')
... else:
... print('Impuesto a pagar:', round(base*12/100,2))
>>>
Funciones con argumentos con palabras clave.
Os dijimos que el monto de la tasa de impuesto dura meses y hasta años con el
mismo valor, pero eventualmente cambia. Por ello vamos a pensar en el futuro y
modifiquemos otra vez, sería la versión 0.3:
>>> def impuesto(base, tasa=12):
... ''' Cálculo del IVA a un monto dado Ver. 0.3 '''
... if base<=0:
... print('Introduzca un monto mayor que cero.')
... else:
... n_tasa = input('Introduzca tasa (12%)')
... if len(n_tasa) > 0:
... tasa=float(n_tasa)
... print('Impuesto a pagar: Bs.', round(base*tasa/100,2))
...
>>>
Aquí le damos la oportunidad al usuario de modificar la tasa si ha cambiado, de lo
contrario pulsa intro y la tasa seguirá con su valor por defecto de un 12% que le
colocamos al declarar la función. La función input() devuelve una cadena de texto: si
el usuario escribió algo la longitud de la cadena es mayor a cero y la función len() nos
lo dirá así, por otra parte la función float() convertirá la cadena de texto a un número
de doble precisión, capaz de manejar decimales.
Pasaremos por alto que el usuario introduzca un valor no numérico, ya llegará el
momento de mejorar nuestro código. Por ahora nos interesa seguir aprendiendo. Así
como modificamos nuestra función nos permite para la tasa desde la llamada a la
función, por ello es lo correcto mostrar dicho monto para que la
función input() enseñe la tasa que va a aplicar, podemos modificar la línea de la
siguiente manera:
... n_tasa = input('Introduzca tasa ('+str(tasa)'%)')
Para llamar a la función escribiremos impuesto(100 , 15) para indicarle a la función,
por lógica, que a un monto de Bs. 100 le calcule el 15% de impuesto. Pero con Python
tenemos varias maneras de llamar a la función y todas producirán el mismo resultado:
Bs. 15 -si simplemente presionamos intro cuando verifica la tasa-, probadlo en
vuestras cónsolas por favor:
>>> impuesto(100 , 15 )
Impuesto a pagar: Bs. 15.0
>>> impuesto(base=100 , tasa=15)
Impuesto a pagar: Bs. 15.0
>>> impuesto(tasa=15, base=100)
Impuesto a pagar: Bs. 15.0
>>> impuesto(tasa=15, 100)
impuesto(tasa=15 , 100)
^
SyntaxError: non-keyword arg after keyword arg
En la última entrada nos arroja error porque no estamos pasando el valor con su
palabra clave, Python espera que el primer argumento sea obligatorio y no importa si
solo tiene 2 argumentos (con una palabra clave pues por descarte el otro argumento
es el «restante»), es decir, si vamos a cambiar el orden de los argumentos siempre
debemos pasarle la palabra clave para indicarle a donde va cada valor. De otra
manera, pues nos aprendemos de memoria el orden exacto de los argumentos de
cada función. Si tenemos un editor que nos ayude a escribir las funciones, bien, por
medio de tooltips nos dirán el nombre y tipo de variable que espera cada función
mientras estamos escribiendo un comando al programar. Pero en GNU/Linux se
necesitan programas pequeños que hagan cosas pequeñas y las hagan
bien. Previendo la programación a futuro, rumbo a la inteligencia artificial, Python nos
ofrece algo muy interesante. Empecemos por docustring ¿lo recordáis?
Por favor, lea también Python 3.5.2 tutorial
Powered by Inline Related Posts
Anotaciones en funciones.
Podemos ‘preguntarle’ a la función para qué sirve por medio de
su docustring simplemente ingresando lo siguiente:
>>> print(impuesto.__doc__)
Cálculo del IVA a un monto dado V. 0.3
Ya vamos viendo la utilidad de documentar a medida que programamos; también
tenemos la posibilidad de «saber» cuántos argumentos recibe la función sin haberle
pasado un solo dato, lo que nos prepara para el poder usarla (si es que otra persona
la escribió o es lo que nosotros escribimos para otras personas). Para ello debemos
agregar a nuestra función la siguiente notación « -> float: » ya que así definimos qué
tipo de dato espera entregar y recibir la función (eso disciplina nuestras tácticas de
programación, pasandole a la función el tipo correcto de dato):
>>> def impuesto(base: float, tasa: float =12) -> float:
... ''' Cálculo del IVA a un monto dado Ver. 0.3 '''
... if base<=0:
... print('Introduzca un monto mayor que cero.')
... else:
... n_tasa = input('Introduzca tasa (12%)')
... if len(n_tasa) > 0:
... tasa=float(n_tasa)
... print('Impuesto a pagar: Bs.', round(base*tasa/100,2))
...
>>>print(impuesto.__annotations__)
{'base': <class 'float'>, 'return': <class 'float'>, 'tasa': <class 'float'>}
¿Observáis el formato como devuelve las definiciones de los argumentos? Vamos a
analizarlos y para ello lo colocaremos en varias líneas de manera indentada:
{
'base': <class 'float'>,
'return': <class 'float'>,
'tasa': <class 'float'>
}
La primera y última línea encierra la definición por medio de corchetes de apertura y
cierra. La segunda línea indica que un argumento tiene como nombre clave la palabra
‘base’ y debe ser un número flotante. La tercera línea «return’ indica lo que devuelve
la función, una variable numérica flotante (la cual habremos redondeado a dos
decimales, como explicamos). No especifica nombre pues ya sabemos cómo se llama
la función. La cuarta línea también indica que debe recibir un argumento llamado
‘tasa’ y debe ser númerica de tipo flotante. Notarán que las nombran entre corchetes
angulares como «class» o clase en castellano: si nosotros hiciéramos nuestras
propias clases podremos referirnos a ellas en cualquier momento. Hay clases
definidas de antamano en Python: ‘float’ es una variables numérica que admite hasta
16 decimales (en su momento veremos los tipos de datos disponibles en Python).
Las anotaciones de funciones son totalmente opcionales y están definidas en PEP
484 y son de reciente adaptación, año 2015, aunque tienen su base en otras PEP,
aparte de ser compatibles, en cierta forma.
Palabra clave «return«.
Lo próximo que vamos a realizar es transformar completamente nuestro código a una
verdadera función con el comando return, veamos:
>>> def impuesto(base: float, tasa: float =12, decimales: int =2) -> float:
... ''' Cálculo del IVA a un monto dado Ver. 0.4'''
... monto=round(base*tasa/100, decimales)
... return monto
...
>>> valor_impuesto=impuesto(100)
>>> print(valor_impuesto)
12.0
Lo que hicimos fue agregarle un argumento adicional, opcional, con la palabra clave
«decimales» y que por defecto es 2 (por ley de nuestra República) y la «tasa» de
impuesto que por ahora es 12 pero que le podemos pasar a la función un valor
diferente sea el caso. También utilizamos una variable llamada «valor_impuesto»
donde guardamos el valor devuetlo para la función y a continuación lo imprimimos por
pantalla; pero esta variable la podemos usar donde y como la necesitemos. Así
podemos practicar de varias maneras el por palabras claves, veamos, que la práctica
hace al maestro (recordemos que estamos en modo interactivo y simplemente al
llamar la función se imprime automáticamente por pantalla, pero si la
guardamos en un archivo .py debemos guardar en una variable para luego
imprimirla, tal como codificamos, de lo contrario no tendremos salida por
pantalla):
>>> impuesto(20)
2.4
>>> impuesto(100, tasa=7)
7.0
>>> impuesto(100, tasa=15, decimales=4)
15.0
>>> impuesto(1477, tasa=17, decimales=4)
251.09
>>> impuesto(1970, tasa=17.89, decimales=4)
352.433
>>> impuesto(1341, decimales=4, tasa=17.89)
239.9049
Lo que siempre debemos hacer es «pasarle» la base, y luego por medio de palabras
claves, sin importar el orden, los otros dos argumentos, de lo contrario arroja error (o
excepción que es el nombre correcto). Si queremos pasarle argumentos, sin importar
el orden, debemos colocarle palabras claves a todos los argumentos, de la siguiente
manera:
>>> impuesto(decimales=2, tasa=10, base = 1500)
150.0
>>> impuesto(decimales=2, tasa=10)
Traceback (most recent call last):
File "/usr/lib/x86_64-linux-gnu/gedit/plugins/pythonconsole/console.py", line
378, in __run
r = eval(command, self.namespace, self.namespace)
File "<string>", line 1, in <module>
TypeError: impuesto() missing 1 required positional argument: 'base'
Sin embargo, si le pasamos solamente los decimales y la tasa y no le pasamos la
base, arroja error, porque ese debe ser un argumento obligatorio , ya que tasa y
decimales le colocamos valores por defecto y así los convertimos en argumentos
opcionales.
Uso de variables para pasarlas a las funciones.
Veremos algo que es facilmente deducible, pero lo complicaremos un poco con los
valores por defecto en los argumentos opcionales de una función. Nos explicamos:
podemos guardar en variables los valores y luego pasarlos a la función:
>>> miMonto=450
>>> miTasa=10
>>> misDecimales=3
>>> miImpuesto=impuesto(miMonto, miTasa, misDecimales)
>>> print(miImpuesto)
45.0
>>> miImpuesto=impuesto(tasa=miTasa, base=miMonto, decimales=misDecimales)
>>> print(miImpuesto)
45.0
Esto no necesita mayor explicación: es simplemente pasarle los valores por medio de
variables. Lo que es más avanzado es pasarle los valores por defecto a la función por
medio de variables declaradas antes de definir la función y dichas variables luego
pueden cambiar su valor pero la función quedará definida con los valores dados
exactamente antes de haber definido la función. Podemos así redefenir la función y
luego explicaremos su utilidad:
valor_tasa=15
def impuesto(base: float, tasa: float =valor_tasa, decimales: int =2) -> float:
''' Cálculo del IVA a un monto dado Ver. 0.4'''
monto=round(base*tasa/100,decimales)
return monto
valor_tasa=16
Aunque luego cambiemos la variable valor_tasa a 16, la función impuesto() quedará
en un valor de por defecto de 15 en la tasa a lo largo de todo el programa.
¿Recordáis que os dijimos que la tasa de impuesto puede variar, según las
necesidades fiscales del país? Pues bueno, nuestra función se puede preparar a
futuro (por ejemplo, realizamos una sencilla aplicación de facturación y manejo de
inventario) si escribimos nuestras funciones de esta manera, las podemos a volver a
recompilar rápidamente si al módulo principal le cambiamos el valor.
Funciones con argumentos arbitrarios.
Podemos definir una función que acepte cualquier argumento, habiendo ya estudiado
anteriormente la flexibilidad que denota Python. Son pocos caracteres que la
componen, pero no se dejen engañar: es una función compleja y difícil de asimilar,
muy genérica, y es difícil darle un uso práctico:
>>> def mi_funcion(*argumentos):
... for mi_arg in argumentos:
... print(mi_arg)
...
>>> mi_funcion(20)
20
>>> mi_funcion()
>>> mi_funcion(20,"prueba")
20
prueba
>>> mi_funcion(20, "prueba", 17, 20, "otra prueba")
20
prueba
17
20
otra prueba
>>>
Funciones con argumentos arbitrarios pero con palabras
claves.
Para «declarar» argumentos arbitrarios en una función solamente tenemos que
precederla con un asterisco y así Python «sabrá» agruparlas en un «diccionario» lo
cual nos permite listarlas (y trabajar) dichos argumentos (que serán una simple
variable más dentro de la función). Pero como mejor es explícito que implícito, Python
nos permite pasar argumentos con palabras claves (y todas deben llevar su palabra
clave o producirá una «errror» o excepción). Tomemos de nuevo nuestra función de
cálculo de IVA con una base dada
>>> def impuesto(**argumentos) -> float:
... ''' Funciones con argumentos y palabras claves '''
... monto=0
... base = 0
... tasa = 12
... decimales = 2
... for arg_clav in argumentos.keys():
... if arg_clav=='base':
... base=float(argumentos[arg_clav])
... if arg_clav=='tasa':
... tasa=float(argumentos[arg_clav])
... if arg_clav=='decimales':
... decimales=int(argumentos[arg_clav])
... monto=round(base*tasa/100,decimales)
... return monto
...
>>> monto_iva=impuesto(decimales=2, base=500, tasa=7)
>>> print(monto_iva)
35.0
>>> print(impuesto.__annotations__)
{'return': <class 'float'>}
>>> print(impuesto.__doc__)
Funciones con argumentos y palabras claves
>>>
Ya nuestras funciones van ganando complejidad y cada vez es más difícil escribirlas
en modo interactivo, creemos que ya vale la pena escribirlas en un archivo por medio
de nuestro editor de texto favorito, pronto daremos unas recomendaciones al respecto
y unas normativas de Python. Mientras, veámos que sucede en este último ejemplo:
Línea 1: declaramos la función en sí con metadatos incluídos.
Línea 2: le establecemos su docustring.
Líneas 3 a 6: incializamos las variables con su valor pro defecto, si lo tuviera.
Línea 7: llamamos a un ciclo for para enumerar todos los argumentos con
palabra claves «pasadas» a la función.
Líneas 8 a 13: por medio de sentencias condicionales verificamos si todos los
elementos de la fórmula del cálculo del impuesto están presentes, si faltare
alguno pues tomaría su valor por defecto.
Línea 14: realiza el cálculo en sí.
Línea 15: devuelve el resultado hacia fuera de la función.
Demás líneas: anotaciones de la función y su docustring. Obsérvese que en
las anotaciones solo nos indica que es una función que solo devuelve un valor
numérico flotante, sin ninguna información de los argumentos necesarios para
que «haga su trabajo»
¿Qué utilidad tiene esto, declarar una función tan extraña que acepte cualquier
cantidad de argumentos con palabras clave? Cuando veamos los diccionarios en
mayor detalle se nos ocurrirán unos cuantos usos útiles, en este punto vamos a
probar algo muy sencillo:
>>> diccionario = { "base" : 277.25 , "tasa" : 19 , "decimales": 3 }
>>> impuesto(**diccionario)
52.678
>>>
Fíjense que las palabras claves deben estar encerradas entre comillas, y que
debemos colocarle dos asteriscos al llamar a la función, así estemos declarando la
función con **argumentos, esto es lo más curioso del asunto y nos devuelve al
principio: cualquier función acepta los argumentos con palabras claves si le
colocamos ** al llamar la función con un diccionario ¿complejo, cierto? Y apenas
estamos comenzando .
Funciones «clonadas».
Python nos permite tomar las funciones que importemos y «cambiarles» el nombre.
Así nuestra función impuesto() que escribimos, tal vez sea para nosotros memorizarla
de otra manera, por ejemplo impt(), pues solo debemos escribir impt = impuesto y
pasarle los valores con el diccionario que hicimos anteriormente, he aquí:
>>> diccionario = { "base" : 277.25 , "tasa" : 17 , "decimales": 4 }
>>> impt = impuesto
>>> impt(**diccionario)
47.1325
>>>
Función abreviada lambda.
A veces necesitamos usar una función una sola vez (cosa rara) y codificarlo en 3
líneas como mínimo (aparte de ir en una sección aparte de nuestro proyecto dedicada
a las funciones) pues que nos lleva tiempo y espacio. Para ello echamos mano de la
¿función de funciones? el comando lambda. Este comando nos permite aplicar, por
ejemplo, un cálculo como el nuestro, que es sumamente sencillo, practiquemos:
>>> (lambda base : round(base*12/100,2))(100)
12.0
Como vemos no le colocamos nombre a la función, solo le indicamos que devuelva la
misma base con el cálculo del impuesto (es todo lo que encierra el primer par de
paréntesis de izquierda a derecha) y en el segundo par de paréntesis le pasamos el
argumento con la base a calcular. Tal vez sea complicado de entender así que
pasamos a definir la función y «clonarla» con un nombre:
>>> impuesto=lambda base : round(base*12/100,2)
>>> impuesto(1000)
120.0
>>> impuesto(7)
0.84
>>> impuesto(70)
8.4
>>> impuesto(100)
12.0
>>>
Acá vemos que es una manera de definir rápidamente una función. Si queremos
colocarle los argumentos completos la podemos definir de la siguiente manera:
>>> impuesto=lambda base, tasa, decimales: round(base*tasa/100,decimales)
>>> impuesto(100,12,2)
12.0
>>> impuesto(543,17,4)
92.31
>>>
Evidentemente que los argumentos son posicionales, si queremos agregarles
palabras claves… pues para eso definimos la función completa como ya lo hemos
hecho. Consideramos útil a este comando/función dentro de otra función declarada
para que se circunscriba dentro de esa función solamente, pero vosotros juzgad y
dadle algún otro uso novedoso, ¡a practicar!
Creamos dos funciones, una para el método a y otra para el método b. Pedimos al
usuario que indique qué método desea calcular. Para el método a pedimos el precio
base y el porcentaje de IVA y proporcionamos el precio con IVA incluido. Para el
método b pedimos el PVP (precio de venta al público) o precio con el IVA incluido,
tambien pedimos el porcentaje de IVA y proporcionamos el precio base o precio sin
IVA. Las funciones proporcionan el resultado final imprimiendo por pantalla el valor
resultante redondeado a dos decimales.
def metodoA():
base = float(input('Valor de base? ') or 200)
percent = int(input('Valor de porcentaje? ') or 21)
result = base * (1 + (percent / 100))
print('\nBase=', base, '\nPorcentaje= ' + str(percent) + '%')
print('Precio con IVA=', round(result,2))
def metodoB():
conIVA = float(input('Precio con IVA? ') or 242)
percent = int(input('Porcentaje? ') or 21)
result = conIVA / (1 + (percent / 100))
print('\nPrecio con IVA=',conIVA,'\nPorcentaje= '+str(percent)+'%')
print('Precio base=', round(result,2))
print('\nCálculo del IVA \nDispone de dos métodos:\n')
print('Método a: Si damos el precio sin IVA y el porcentaje de IVA nos
dará el PVP (Precio Venta Público)\n')
print('Método b: Si damos el precio con IVA y el porcentaje de IVA nos
dará el precio base \n')
metodo = input('Que metodo quieres usar? (a/b) ')
metodo = metodo.lower()
while metodo != 'a' and metodo != 'b':
metodo = input('El termino introducido no es valido\nQue metodo quieres
usar? (a/b) ')
metodo = metodo.lower()
if metodo == 'a':
metodoA()
elif metodo == 'b':
metodoB()
1. # Repetición, decisión
2. # Mastermind
3. # El ordenador selecciona un número, y le pide al
usuario que lo adivine.
4. # Cada vez que introduce un valor, el ordenador le
indica la usuario si el
5. # elegido por él es mayor o menor al introducido.
6.
7. import random
8.
9. random.seed()
10. x = random.randint(1, 99)
11.
12. turnos = 1
13. valor = int(input("Mastermind\nDame un valor de 1 a
99: "))
14. while valor != x:
15. if valor > x:
16. print("Es menor.")
17. elif valor < x:
18. print("Es mayor.")
19. else:
20. break
21.
22. turnos += 1
23. valor = int(input("Mastermind\nDame un valor de 1 a
99: "))
24. print("Lo has acertado en", turnos, "turnos.")
1. # Listas, bucles
2. # Fibonacci en una lista
3. # La sucesión de Fibonacci consiste en empezar con los
dos primeros elementos
4. # siendo 0 y 1. Los siguientes elementos se calculan
sumando el valor en la
5. # posición anterior, y el valor en la penúltima
posición.
6.
7. n = int(input("Dame num. posiciones en Fibonacci: "))
8. suc_fibo = [0, 1]
9. n -= 2
10.
11. for _ in range(n):
12. nuevo_elemento = suc_fibo[-1] + suc_fibo[-2]
13. suc_fibo += [nuevo_elemento]
14.
15. print(suc_fibo)
1. # Bucles
2. # Convertir un valor binario (base 2) a base 10.
3.
4. binario = input("Dame el valor binario: ")
5. binario = binario.strip()
6.
7. num_digitos = len(binario)
8. base = num_digitos - 1
9. resultado = 0
10. for i in range(num_digitos):
11. resultado += (2 ** base) * int(binario[i])
12. base -= 1
13.
14. print("Resultado en decimal:", resultado)
15.
1. # Diccionarios, bucles, decisión
2. # Frecuencias
3. # Calcula las frecuencias de cada carácter en un texto
pedido por teclado.
4.
5. # Pedir los datos
6. texto = input("Dame un texto: ")
7. texto = str.lower(str.strip(texto))
8. frecs = {}
9.
10. # Tratar las vocales acentuadas
11. texto = str.replace(texto, 'á', 'a')
12. texto = str.replace(texto, 'é', 'e')
13. texto = str.replace(texto, 'í', 'i')
14. texto = str.replace(texto, 'ó', 'o')
15. texto = str.replace(texto, 'ú', 'u')
16. texto = str.replace(texto, 'ü', 'u')
17.
18. # Inicializar el diccionario de frecuencias
19. for x in "abcdefghijklmnpqrstuvwxyzñ":
20. frecs[x] = 0
21.
22. # Calcular las frecuencias en el texto
23. for x in texto:
24. if x in frecs:
25. frecs[x] += 1
26.
27. # Visualizar los resultados
28. claves_ordenadas = list(dict.keys(frecs))
29. list.sort(claves_ordenadas)
30. for k in claves_ordenadas:
31. frec = frecs[k]
32. if frec > 0:
33. print(str.format("Letra {0} aparece: {1} vece(s).",
k, frec))
1. # Juego de dados
2. # En un juego de dados, todos los participantes tienen
el
3. # mismo número de dados (con 6 caras, de la 1 a la 6).
4. # En cada turno, cada jugador tira todos sus dados,
sumando
5. # cada dado para obtener una puntuación.
6. # Gana el jugador con mejor puntuación tras tres turnos.
7. #
8. # [email protected] - (c) 2017 - Licencia MIT
9.
10.
11. import random
12.
13.
14. class Dado:
15. """Representa un dado de seis caras, de 1 a 6."""
16.
17. def __init__(self):
18. self.ultimo_resultado = 0
19.
20. def tirada(self):
21. self.ultimo_resultado = random.randint(1, 6)
22. return self.ultimo_resultado
23.
24. def __str__(self):
25. return str(self.ultimo_resultado)
26.
27.
28. class Jugador:
29. """Representa a un jugador que tiene x dados."""
30.
31. def __init__(self, nick, num_dados):
32. """Crea un nuevo jugador.
33.
34. :param nick: El nick del jugador.
35. :param num_dados: El num. de dados para la
partida."""
36.
37. self.nick = nick
38. self.num_dados = num_dados
39. self.dados = []
40. self.ultima_tirada = []
41. for i in range(num_dados):
42. self.dados += [Dado()]
43.
44. def tirada(self):
45. """Realiza una tirada con todos los dados."""
46.
47. self.ultima_tirada = []
48.
49. for dado in self.dados:
50. self.ultima_tirada += [dado.tirada()]
51.
52. return self.ultima_tirada
53.
54. def __str__(self):
55. toret = self.nick + ": "
56.
57. for x in self.ultima_tirada:
58. toret += str(x) + ' '
59.
60. return toret.strip()
61.
62.
63. class Juego:
64. """Representa un juego de x jugadores e y turnos.
65. Permitirá incorporar jugadores.
66. El método juega() lanza los y turnos, guardando
67. los resultados parciales y la puntuación total."""
68.
69. def __init__(self, num_turnos, num_dados):
70. """Crea un nuevo juego.
71.
72. :param num_turnos: El num. de turnos a jugar.
73. :param num_dados: El num. de dados para todos.
74. """
75.
76. self.num_turnos = num_turnos
77. self.num_dados = num_dados
78. self.jugadores = []
79. self.puntos_max = []
80. self.puntos_parciales = []
81. self.turnos = []
82.
83. def inserta_jugador(self, nick):
84. self.jugadores += [Jugador(nick, self.num_dados)]
85.
86. def juega(self):
87. self.puntos_max = [0] * len(self.jugadores)
88. self.turnos = []
89.
90. for _ in range(self.num_turnos):
91. self.puntos_parciales = [[]] * len(self.jugadores)
92.
93. for i, jugador in enumerate(self.jugadores):
94. pts = jugador.tirada()
95. self.puntos_max[i] += sum(pts)
96. self.puntos_parciales[i] =
list(jugador.ultima_tirada)
97.
98. self.turnos += [list(self.puntos_parciales)]
99.
100. def __str__(self):
101. toret = str.format("Juego de {0} turnos y {1}
dados.\n\n",
102. self.num_turnos, self.num_dados)
103.
104. for puntos in self.turnos:
105. for i, pts in enumerate(puntos):
106. toret += self.jugadores[i].nick + ": " + str(pts)
107.
108. toret += '\n'
109. toret += '\n'
110.
111. toret += "Puntuaciones finales:\n"
112. for i, pts in enumerate(self.puntos_max):
113. toret += self.jugadores[i].nick + ": " + str(pts) +
'\n'
114.
115. return toret
116.
117. if __name__ == "__main__":
118. random.seed()
119. juego = Juego(random.randint(2, 6),
random.randint(3, 6))
120. juego.inserta_jugador("Baltasar")
121. juego.inserta_jugador("Fulano")
122. juego.inserta_jugador("Mengano")
123. juego.inserta_jugador("Zutano")
124. juego.juega()
125. print(juego)