**Ir a:** [*Repositorio*](https://gitea.kickto.net/devfzn/Apuntes_Python), [*Modulo 1*](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1#modulo-1-python-basico), [*Modulo 3*](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_3#modulo-3-python-basico) ## Modulo 2 - Python basico #### [Indice](#modulo-2-python-basico) - [Strings Format](#strings) - [Decodificadores de strings](#decodificadores-de-strings) - [Función join](#join) - [Metodos de Strings](#metodos-de-strings) - [Constantes de la libreria string](#constantes-que-define-la-libreria-string) - [Formateo de strings](#formateo-de-strings) - [Fecha y Hora](#fechas-date) - [Datetime](#datetime-hora-y-fechas) - [Conversion a string](#tiempo-a-string) - [Excepciones](#excepciones) - [Excepcion personalizada](#excepción-personalizada) - [Context manager](#context-manager) - [Manejo de excepción IndexError](#manejo-de-excepción-indexerror) - [Otro ejm. excepción personalizada](#ejemplo-de-excepción-personalizada) - [Input/Output strings](#input-output-string) - [Leer y escribir archivos](#leer-y-escribir-archivos) - [Leer Archivos](#leer-archivos) - [Escribir en archivos](#escribiendo-en-archivos) - [Leer, Escribir CSV](#leer-y-escribir-csv) - [Datos estructurados JSON](#json) - [Matrices, Conjuntos](#matrices) - [Listas, Pilas, Colas, Stacks](#listas) - [Funciones](#algunas-funciones) - [Listas como Pilas](#listas-como-pilas) - [Listas como Colas](#listas-como-colas) - [Listas por comprensión](#listas-por-comprension) - [Buscar en lista](#buscar-elemento-en-una-lista) - [Listas por comprensión 2](#comprension-de-listas-2) - [Tuplas y secuencias](#tuplas) - [Diccionarios](#diccionarios) - [Operaciones sobre diccionarios](#las-operaciones-principales-son) - [Acceso a elementos](#acceso-a-elementos-por-claves) - [Metodos](#metodos-en-los-diccionarios) - [Iterando diccionarios](#iterando-diccionarios) - [Resumen](#resumen-diccionarios) - [Generadores](#generadores) - [Ejemplos](#uso-de-generadores) - [Decoradores](#decoradores) - [Ejercicios](#ejercicios-modulo-2) - [Verdurería](#verdureria) - [El juego del Gato](#el-gato) ---- ## Strings Cadenas(*secuencia*) de caracteres ```python 'Str' "Str" """ Para multilinea usar 3 pares de cualquier tipo """ a_str = 'Hola Mundo!' # * Acceso a caracter según posición a_str[0] # retorna H a_str[-1] # retorna ! # * Slicinf de un string a_str[:4] # retorna HOLA a_str[5:9] # retorna Mundo # * Longitud String len(a_str) # retorna 11 ``` Caracter de escape **` \ `**, para acceder a las secuencias de escape comunes. Ej.: **` \' `**, **` \" `**, **` \n `**, **` \r `**, **` \t `**. ### Decodificadores de strings ej. codificar (de unicode a un byte array con codif. determinada) decodificar ( de un byte array con una codif. determ. a unicode) ```python a_str = 'Otoño' # utf-8 encode str_codific = a_str.encode('utf-8') # Respuesta: b'Oto\\xc3\\xb1o' # utf-8 decode str_codific.decode('utf-8') # Respuesta: 'Otoño' # Unicode es la ley # ASCCI no tiene estos caracteres.. lo cual da error # str2 = "áéíóú" # str3 = str2.encode('ascii') ``` ### Strings y variables ```python nombre = "Reberte" "Hola %s" % nombre # 'Hola Reberte' "Un nro. %d" % 5 # 'Un nro. 5' "Nr0. de 2 digitos %02d" % 5 # 'Nr0. de 2 digitos 05' "Un float %f" % 6.4 # 'Un float 6.400000' "Float 2 digitos %.2f" % 2.54 # 'Float 2 digitos 2.54' "Hola %(name)s" % {'name': nombre } # 'Hola Reberte' "Hola {}".format(nombre) # 'Hola Reberte' "{0} + {1} es {2}".format(7,2,7+2) # '7 + 2 es 9' ``` ### join Construye strings concatenando lista de valores ```python ' ',join(["Hola", nombre]) ', '.join(['1','2','3','4']) ``` ## Metodos de Strings python -i `>>> help(str)` ``` METODOS DE LOS STRINGs NOMBRE ej. Resultado capitalize 'word'.capitalize() 'Word' center 'word'.center(10,'*') '**word**' count 'word'.countd(d) 1 encode 'word'.encode('utf-8') b'word' endswith 'word'.endswith('d') True find 'wordw'.find('w') 0 rfind 'wordw'.rfind('w') 4 format 'Hola {}'.format('Elmo') 'Hola Elmo' index 'wordw'.index('w') 0 rindex 'wordw'.rindex('w') 4 isalnum 'word'.isalnum() True isalpha 'word'.isalpha() True isdecimal '10'.isdecimal() True isdigit '10'.isdigit() True islower 'woRd'.islower() False isnumeric '23'.isnumeric() True isprintable 'word'.isprintable() True isspace ' '.isspace() True islitle 'Two Words'.islitle() True isupper 'WORD'.isuper() True lower 'woRd'.lower() 'word' replace 'woRd'.replace('R','rl') 'world' split '1-2-3-4'.split('-') ['1', '2', '3', '4'] startwith 'word'.startwith('w') True strip ' word '.strip() 'word' lstrip rstrip ljust 'word'.ljust(8) 'word ' rjust swapcase 'WoRd'.swapcase() 'wOrD' title 'a title'.title() 'A Title' upper 'word'.upper() 'WORD' zfill 'word'.zfill(10) '000000word' rindex 'word'. ``` #### Constantes que define la libreria string - **ascii_letters** : La concatenación de las letras minúsculas y letras mayúsculas. `abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` - **ascii_lowercase** : Las letras minúsculas. `abcdefghijklmnopqrstuvwxyz` - **ascii_uppercase** : Las letras mayúsculas. `ABCDEFGHIJKLMNOPQRSTUVWXYZ` - **digits** : Los dígitos del sistema decimal. `0123456789` - **hexdigits** : Los dígitos del sistema hexadecimal. `0123456789abcdefABCDEF` - **octdigits** : Los dígitos del sistema octal. `01234567` - **punctuation** : Símbolos de puntuación. `!"#$%&\'()*+,-./:;<=>?@[\\]^_\`{|}~` - **printable** : Todos los caracteres considerados imprimibles. ``` 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJK MNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c ``` - **whitespace** : Todos los caracteres considerados espacios en blanco. `\t\n\r\x0b\x0c` ### Formateo de strings ```python name = 'Reberte' print('Hola {}'.format(name)) # 'Hola Reberte' print('{} + {} = {}'.format(2,5,7)) # '2 + 5 = 7' print('{1} + {2} = {0}'.format(7,5,2)) # '5 + 2 = 7' print('Hola {nombre}'.format(nombre = name)) # 'Hola Reberte' tupla = 4, 3 type(tupla) # print('X: {0[0]}; Y: {0[1]}'.format(tupla)) # 'X: 4; Y: 3' print('{0:f} + {1:f} = {result:f}'.format(2, 5, result=7)) '2.000000 + 5.000000 = 7.000000' print('{0:.3f} + {1:.3f} = {result:.3f}'.format(2, 5, result=7)) # '2.000 + 5.000 = 7.000' print('{:d}'.format(25)) # '25' # '{:d}'.format(25.5) # Traceback (most recent call last): # File "", line 1, in # ValueError: Unknown format code 'd' for object of type 'float' print('{:.0f}'.format(25.50)) # '26' print('Hola {nombre:16}'.format(nombre=name)) # 'Hola Reberte ' print('Hola {nombre:<16}'.format(nombre=name)) # 'Hola Reberte ' print('Hola {nombre:>16}'.format(nombre=name)) # 'Hola Reberte' print('Hola {nombre:^16}'.format(nombre=name)) # 'Hola Reberte ' print('Hola {nombre:*^16s}'.format(nombre=name)) # 'Hola ****Reberte*****' ``` ---- ## Fechas (date) ```python import datetime # date object # 18-Jun-20 fecha = datetime.date(2020, 6, 18) fecha.year # 2020 fecha.month # 6 fecha.day # 18 fecha.weekday() # Lunes 0 -> Domingo 6 fecha.isoweekday() # Lunes 1 -> Domingo 7 fecha.isocalendar() # tuple( año, semana, dia semana) fecha.isoformat() # YYY-MM-DD ``` ### timedelta() ```python hoy = datetime.date.today() ayer = hoy - datetime.timedelta(days=1) delta = hoy - ayer # 1 day, 0:00:00 ``` ### Datetime ( hora y fechas ) ```python fecha_hora = datetime.datetime(2020, 12, 2, 9, 15, 30) # (YYYY, MM, D, h, m , s ) print(fecha_hora.date()) # 2020-12-02 # formato local ahora = datetime.datetime.now() # UTC ahora = datetime.datetime.utcnow() ``` ### Tiempo a string ```python hora = datetime.time(10, 40, 35) hora.hour hora.minute hora.second hora.microsecond fecha = datetime.datetime(2020, 4, 30, 11, 25, 30) ``` - Conversion DateTime a String # strftime - `fecha.strftime('%Y-%m-%d')` - `fecha.strftime('%Y-%m-%d' T%H:%M:%S')` - `fecha.strftime('%Y-%m-%d %H:%M:%S')` - Conversion String a DateTime # strptime - `fecha.strptime('2020-01-10', '%Y-%m-%d')` - `fecha.strptime('2020-01-10 T11:30:25', '%Y-%m-%d' T%H:%M:%S')` - `fecha.strptime('2020-01-10 11:30:25','%Y-%m-%d %H:%M:%S')` ---- ## Excepciones Hay principalmente 2 tipos de errores: de sintaxis y excepciones ```python while True : try: x = int(input('Excepcion si no se ingresa un ENTERO ->')) break except ValueError: print('Se puede salir con Ctrl-C') ``` ```python while True : try: x = int(input('Excepcion si no se ingresa un ENTERO ->')) break except (ValueError, KeyboardInterrupt): print('Ya, no se puede salir y con Ctrl-C') ``` ``` ... except (RuntimeError, TypeError, NameError): ... pass ``` ```python class B(Exception): pass class C(B): pass class D(C): pass for cls in [B, C, D]: try: raise cls() except D: print("D", D) except C: print("C", C) except B: print("B", B) print('') ``` ```python for cls in [B, C, D]: try: raise cls() except B: ( print("B") except D: print("D") except C: print("C") print('') ``` ```python import sys try: f = open('mifile.txt') s = f.readline() i = int(s.strip()) except OSError as err: print("Error OS: {0}".format(err)) except ValueError: print("No pude convertir el dato a entero.") except: print("Error inesperador: ", sys.exc_info()[0]) raise #for arg in sys.argv[1:]: # try: # f = open(arg, 'r') # except OSError: # print('no pude abrir', arg) # else: # print(arg, 'tiene', len(f.readlines()), 'lineas') # f.close() ``` *python -i* ```python try: raise Exception('carne', 'huevos') except Exception as inst: print(type(inst)) print(inst.args) print(inst) #x, y = inst #print('x: ',x ,'y: ',y) ``` ```python >>> raise RuntimeError('Error error bip bap bip! no computa! bip bap!') Traceback (most recent call last): File "", line 1, in RuntimeError: Error error bip bap bip! no computa! bip bap! ``` ### Relanzando la excepción para ser manejada en otro contexto. ```python try: raise NameError('y bueno un error común') except NameError: print('ee.. salto un except!') raise ``` ----- ### Excepción Personalizada ```python class Error(Exception): """Clase base para excepciones en el módulo""" pass ``` ### Acciones de limpieza ```python class EntradaError(Error): """Excepción lanzada por error en las entradas. Atributos: expresion -- expresión de entrada en la que ocurre el error mensaje -- explicación del error """ def __init__(self, expresion, mensaje): self.expresion = expresion self.mensaje = mensaje ``` ```python class TransicionError(Error): """Lanzada por operación que intenta transición de estado no permitida. Atributos: previo -- estado al conmenzar la transición siguiente -- nuevo estado intentado mensaje -- explicación de transición no permitida """ def __init__(self, previo, siguiente, mensaje): self.previo = previo self.siguiente = siguiente self.mensaje = mensaje ``` ### finally ```python try: #raise KeyboardInterrupt pass finally: print('hasta pronto!') def dividir(x, y): try: res = x / y except ZeroDivisionError: print("¡división por cero!") else: print("el resultado es: ", res) finally: print('bloque finally') dividir(2, 1) dividir(2, 0) ``` ### Context manager Esta sentencia deja el archivo abierto tras usarlo ```python for linea in open("miarchivo.txt"): print(linea, end="") # with asegura liberar el recurso tras su uso with open("miarchivo.txt") as f: for linea in f: print(linea, end="") ``` ### Manejo de excepción IndexError ```python def find(elemento, lista): """Devuelve el indice del @elemento en @lista. Si no lo encuentra retorna -1 """ index = 0 while True: try: if lista[index] == elemento: return index except IndexError: return -1 index += 1 # ejemplos de find print(find(4,[2,3,4,5])) # 2 print(find(2,[2,3,4,5])) # 0 print(find(9,[2,3,4,5])) # -1 ``` ### Ejemplo de excepción personalizada ```python class MiExcepcion(Exception): "Excepcion personalizada" pass def fun_ejm(numero): if numero <= 0: raise MiExcepcion("nro negativ. o cero") return 1/numero print(fun_ejm(10)) print(fun_ejm(-4)) ``` ---- ## Input Output String - **repr(), rjust()** ```python for x in range(1, 11): print(repr(x).rjust(2), repr(x * x).rjust(3), repr(x * x * x).rjust(4)) # 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 ``` ```python 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 ``` - **zfill()** ```python print('12'.zfill(5), end='\n' * 2) # 00012 ``` - **format()** ```python print('Somos {}, pero otras "{}!"'.format('celestes', 'magenta')) # Somos celestes, pero otras "magenta!" print('Somos {1}, cantamos "{0}"'.format('aves', 'pio-pio')) # Somos pio-pio, cantamos "aves" print('Este {cosa} es {adjetivo}.'.format(cosa='loro', adjetivo='azul')) # Este loro es azul. print('Este {0} es {1}!, le pongo un {nota}'.format('color', 'muy llamativo', nota=7.456)) # Este color es muy llamativo!, le pongo un 7.456 ``` **Convertir valor antes que se formatee** ```python # !a apply() # !s str() # !r repr() var = 'ratas' print('mi yate esta lleno de {!r}.'.format(var)) # mi yate esta lleno de ratas. ``` ```python from math import pi print('El valor de PI es aprox. {0:.3f}.'.format(pi), '\n'*2) # El valor de PI es aprox. 3.142. print('\n El valor de Pi es app. %.2f.' % pi) # El valor de Pi es app. 3.14. tabla = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 76789877} for nombre, telefono in tabla.items(): print('{0:8} ==> {1:8d}'.format(nombre, telefono)) # Sjoerd ==> 4127 # Jack ==> 4098 # Dcab ==> 76789877 print('\n', 'Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; ' 'Dcab: {0[Dcab]:d}'.format(tabla)) # Jack: 4098; Sjoerd: 4127; Dcab: 76789877 print('\nJack: {Jack:d}; Sjoerd: {Sjoerd:d}; ' 'Dcab: {Dcab:d}'.format(**tabla)) # Jack: 4098; Sjoerd: 4127; Dcab: 76789877 ``` ### Leer y escribir archivos ```python mi_file = open('nombre_archivo', 'modo') -r read (default) -r+ read/write -w write -a append -x ? ``` - **read()** ```python # El context manager cierra el archivo despues de usarlo with open('archivo') as f: datos_leidos = f.read() ``` - **readline()** lee linea a linea - **f.close()** cierre de archivo aribitrario. ```python print(f.closed) <-- 'True' si el archivo se cerro. list(f) ó f.readlines() <-- pare lee todas las lineas del archivo. f.write('cadena a escribir\n') 18 s = str(valor) # valor = ('respuesta', 16) f.write(s) 15 ``` - **f.tell()** Devuelve la posición actual en el archivo, representada como número de bytes desde elcomienzo del archivo en modo binario y un número opaco en modo texto. - **f.seek()** *python -i* ```python f.seek(desplazamiento, desde_donde) >>> f =open('archivodetrabajo', 'rb+') >>> f.write(b'0123456789abcdef') >>> f.seek(5) # Va al sexto byte en el archivo 5 >>> f.read(1) b'5' >>> f.seek(-3, 2) # Va al tercer byte antes del final 13 >>> f.read(1) b'd' ``` otros: - isatty() - truncate() ----- ## Leer Archivos ```python # Abrir archivo arch = open('./python_subprocess_bash', 'r') # Leer contenido arch.read() # Cerrar el arrchivo arch.close() ``` > **Context manager:** > en este caso **with** abre y cierra el archivo > **read()** lee todo el contenido del archivo ```python with open('./python_subprocess_bash', 'r') as archivo: print(archivo.read()) ``` ### Lee por linea ```python with open('./python_subprocess_bash', 'r') as archivo: print(archivo.readline()) ``` ### Genera una lista con las lineas del archivo ```python with open('./python_subprocess_bash', 'r') as archivo: print(archivo.readlines()) ``` ### Genera una lista con las lineas del archivo ```python with open('./python_subprocess_bash', 'r') as archivo: print(list(archivo)) ``` ### For recorre linea a linea ```python with open('./python_subprocess_bash', 'r') as archivo: for linea in archivo: print(linea) ``` ---- ## Escribiendo en archivos ```python import subprocess arch = 'python_subprocess_bash' with open(arch, 'w') as archivo: archivo.write('Hola mundo') subprocess.check_call(["cat", arch]) print('') ``` ### Escribir multiples lineas. ```python with open(arch, 'w') as archivo: archivo.writelines(['Linea 1.\n', 'Linea 2.\n', 'Linea 3.\n', 'Linea 4.\n']) subprocess.check_call(["cat", arch]) ``` ### Anexadon al final de archivo. 'a' ```python with open(arch, 'a') as archivo: archivo.write('!odnuM aloH') subprocess.check_call(["cat", arch]) ``` ---- ## Leer y escribir CSV ### Leer CSV `csv.reader(archivo.csv)` ```python import csv with open('ejm.csv', 'r') as csv_arch: reader = csv.reader(csv_arch) for row in reader: #print('\t'.ljust(2).join(row)) print('{0:8}\t{1:8}\t{2:8}\t{3:8}'.format(*row)) #print('{0:8}\t{1:8}\t{2:8}\t{3:8}'.format(row[0], row[1], row[2], row[3] #print('\n', help(row)) # las filas son listas ``` ### Escribir CSV `csv.writer(arch.csv).writerow(['elementos','a','escribir'])` ```python with open('ejm.csv', 'a') as csv_arch: writer = csv.writer(csv_arch) writer.writerow(['Elvira', 'Zápáté', '34467845', 'lervielpare@zumail.zen']) ``` ---- ## JSON **Java Scrit Object Notation** El módulo estandar llamado json puede tomar datos de Python con una jerarquía, y convertirlo a representaciones de cadena de caracteres. Este proceso es llamado **serializing**. Reconstruir los datos desde la representación de cadena de caracteres es llamado **deserializing**. El formato JSON es comunmente usado por aplicaciones modernas para permitir intercambiar datos. ```python import json ``` ### Serializar un objeto ```python # Transforma el mismo a una representacion de caracteres. json.dumps([1, 2, 3]) # '[1, 2, 3]' ``` ### Deserializar una cadena ```python # Transforma la cadena a un objeto json json.loads('[1, 2, 3]') # [1, 2, 3] ``` ### Escribir como json a un archivo ```python with open('archivo.json', 'w') as arch: json.dump([1, 2, 3, 4], arch) ``` ### Leer un json ```python with open('archivo.json', 'r') as arch: print( json.load(arch) ) ``` ### Otro ejemplo ```python x = [1, 'simple', 'lista'] f = open('test_file_json', 'r+') json.dumps([1, 'simple','lista']) # Suponiendo q f es un archivo de texto abierto para escritura: json.dump(x, f) f.close() f = open('test_file_json', 'r') # Suponiendo q f fue abierto para lectura: print(json.load(f)) f.close() ``` ---- ## Matrices Se pueden considerar como listas de listas, lo visto en listas aplica tambien en matrices ### Definción de matriz de 3 filas y 4 columnas. ```python matriz = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] # Acceso a elementos matriz[ fila o lista1 ] [ columna o lista2 ] matriz[0][0] # 1 matriz[1][2] # 7 # Ejm. suma de matrices def suma_matr(A, B): """ Suma 2 matrices. A: len(A) == len(B), integers. B: len(A) == len(B), integers. returns: Matriz con resulta de la suma de los elementos de A y B """ filas, colums, C = len(A), len(A[0]), [] for fila in range(filas): fila_temp = [] for columna in range(colums): fila_temp.append(A[fila][columna] + B[fila][columna]) C.append(fila_temp) return C print(suma_matr(matriz, matriz)) # [[2, 4, 6, 8], [10, 12, 14, 16], [18, 20, 22, 24]] ``` > Libreria **NumPy** para trabajar con matrices ## Conjuntos Un conjunto esta entre llaves no tiene elementos repetidos. ```python frutas = {'manzana', 'naranja', 'manzana', 'pera', 'naranja', 'banana', 'kiwi'} print(frutas) #{'kiwi', 'naranja', 'manzana', 'banana', 'pera'} print('pera' in frutas, 'yerba' in frutas) # True False ``` ### Creacion de conjuntos ```python conj_a = set() type(conj_a) # a = set('abracadabra') #{'r', 'a', 'b', 'd', 'c'} b = set('alacazam') #{'l', 'm', 'a', 'z', 'c'} print('\n a =',a ,' b =',b) ``` ### Operaciones de conjuntos ```python a - b # {'d', 'b', 'r'} elementos de a menos elementos de b a | b # {'l', 'd', 'a', 'z', 'm', 'c', 'b', 'r'} elementos de a y b a & b # {'c', 'a'} elementos en común (INTERSECCION) a ^ b # {'l', 'z', 'b', 'm', 'd', 'r'} elementos únicos de cada set ``` ### Comprensión de conjuntos ```python a = {x for x in 'abracadabra' if x not in 'abc'} a.add('z') a.remove('z') print('\n', a) # {'r', 'd'} ``` ### Ayuda sobre la clase set python -i `>>>help(set)` ``` class set(object) set() -> new empty set object set(iterable) -> new set object Build an unordered collection of unique elements. Methods defined here: add(...) Add an element to a set. This has no effect if the element is already present. clear(...) Remove all elements from this set. copy(...) Return a shallow copy of a set. difference(...) Return the difference of two or more sets as a new set. (i.e. all elements that are in this set but not the others.) difference(...) Return the difference of two or more sets as a new set. (i.e. all elements that are in this set but not the others.) difference_update(...) Remove all elements of another set from this set. discard(...) Remove an element from a set if it is a member. If the element is not a member, do nothing. intersection(...) Return the intersection of two sets as a new set. (i.e. all elements that are in both sets.) intersection_update(...) Update a set with the intersection of itself and another. isdisjoint(...) Return True if two sets have a null intersection. issubset(...) Report whether another set contains this set. issuperset(...) Report whether this set contains another set. pop(...) Remove and return an arbitrary set element. Raises KeyError if the set is empty. remove(...) Remove an element from a set; it must be a member. If the element is not a member, raise a KeyError. symmetric_difference(...) Return the symmetric difference of two sets as a new set. (i.e. all elements that are in exactly one of the sets.) symmetric_difference_update(...) Update a set with the symmetric difference of itself and another. union(...) Return the union of sets as a new set. (i.e. all elements that are in either set.) update(...) Update a set with the union of itself and others. ``` ---- ## Listas Permiten guardar todo tipo de objetos ```python lista = [3, 7.5, 'Hola', 7j + 5, [1, 2]] # Acceso mediante indexacion lista[0] # 3 lista[2] # 'Hola' lista[-1] # [1, 2] # Slicing lista[1:] # [7.5, 'Hola', (5+7j), [1, 2]] lista[1:2] # [7.5] lista[1:3] # [7.5, 'Hola'] lista[:2] # [3, 7.5] lista[:] # [3, 7.5, 'Hola', (5+7j), [1, 2]] ``` ### Algunas funciones ```python # Cantidad de elementos len(lista) # 5 # Agrega al final lista.append(2) # Extiende la lista con elementos de otra lista # "o tupla" lista.extend((1, 2)) lista.extend([3, 4]) # Insertar elemento en posición lista.insert(4, 'Intercalado') lista.insert(12, 'Fuera de Rango') lista.insert(-1, 'Hacia atrás') # Cuenta coincidencias con argumento lista.count(3) # Elimina el 1er elemento encontrado lista.remove(3) # Copia la lista superficialmente (mutable) copia_lista = lista.copy() # Saca ultimo elemento, o el indicado en el indice lista.pop() # Limpiar lista lista.clear() ``` ```python # Lista ls ls = [1, 2, 3, 4] x = 1 ls.append(x) itr = range(10) ls.extend(itr) i = 0 # indice ls.insert(i, -1) # Elimina el primer valor encontrado (error si no ecuentra) ls.remove(3) # Retorna y remueve según indice ls.pop(2) # Borrar lista ls.clear() ls = [1, 2, 3, 4] x = 2 # Devuelve la posicion del primer obejto X encontrado: # ls.index(x, desde[0], hasta[len(ls)]) [default] ls.index(x) # Cantidad de incidencias de x ls.count(x) # Ordena lista segun alguna funcion key=nombrefuncion ls.sort(key=None, reverse=False) # Invierte orden lista ls.reverse() # Copia lista equiv. ols = ls[:] ols = ls.copy() ``` ### Funciones listas y strings Tanto para **listas (mutables)** como para **strings (inmutables)** ```python name = 'Reberte' lista = list(name) # indexado name[0] lista[0] # Slicing name[:4] lista[:4] # len len(name) len(lista) # in 'R' in name 'R' in lista # not 'z' not in name[0] 'z' not in lista[0] # for for letra in name: print(letra) for letra in lista: print(letra) # String son inmutables lista[2] = 'o' #name[2] = '0' # TypeError 'Hola' + name name + '!!' name[:2] + 'to' + name[2:] ``` ### Listas como pilas Funcionamiento de "**pilas**" (apilar) > Último en entrar, Primero en salir **FiFo** > **LiFo** (last in first out) ```python pila = [1, 2, 3] # insterar elemento pila.append(4) pila.append(5) # sacar elemento pila.pop() #5 pila.pop() #4 pila.pop() #3 ``` ### Listas como colas > **FiFo** (first in first Out) > Diseñado para trabajar con ambos extremos de la "lista" > Se usa "collections.deque" ```python from collections import deque cola = deque(["Javier","Jimena","Jorge"]) cola.append("Jaqueline") cola.append("Jose") cola.popleft() # "Javier" cola.popleft() # "Jimena" cola # ["Jorge","Jaqueline","Jose"] # LISTAS COMO COLAS 2 # FiFo (First in First Out) cola = [1, 2, 3] cola.append(4) cola.append(5) cola.pop() #1 cola.pop() #2 # Colas eficientes en libreria estandar cola = deque([1, 2, 3]) # Agregar cola.append(4) cola.append(5) cola.popleft() #1 cola.popleft() #2 ``` ### Listas por comprension > Usualmente, se crean para generar listas donde cada elemento es el resultado > de aplicar una o mas operaciones a cada miembro de una secuencia o itreable ```pyhton # Lista de Cuadrados cuads = [] for x in range(10): cuads.append(x**2) # Lista por comprension cuads2 = [x ** 2 for x in range(10)] # Utilizando la funcion map cuads3 = list(map(lambda x: x**2, range(10))) lista = [-4, -2, 0, 2, 4] # Lista por comprensión contiene los nrs. positivos de 'lista' [x for x in lista if x >= 0] #[0, 2, 4] # Lista con los positivos usando funcion filter [2, 4] list(filter(lambda x: x > 0, lista)) # Pares y su cuadrado [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] [(x, x ** 2) for x in range(6)] # Lista de pares combinados pares = [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y] ``` ### Buscar elemento en una lista ```python ls = [1, 2, 3, 4] # Retorna el indice si encuentra el elemento ls.index(4) # lanza excepecion ValueError si no # ls.index(9) # Indicando una sublista # ls.index(x, desde[0], hasta[len(ls)]) ls.index(4, 1) #ls.index(4, 0, 2) # ValueError: 4 is not in list ls.index(4, 1, 4) ``` ### Metodos de ordenamiento ```python ls = [3, 1, 2, 9, 5, 4, 7, 8, 6] # Ordena < a > ls.sort() ls.sort(reverse=True) ls = [(1, 9), (1, 3), (1, 4), (1, 2)] ls.sort(key=lambda x: x[1]) # Revertir el orden de los elementos ls = [3, 1, 2, 9, 5, 4, 7, 8, 6] ls.reverse() # Retorna lista ordenada sorted(ls) sorted(ls, reverse=True) ls = [(1, 9), (1, 3), (1, 4), (1, 2)] sorted(ls, key=lambda x: x[1]) # Ordenar según la suma de pares de elementos, en la lista en sí, ascendente (sort(default)) ls = [(6, 2), (1, 5), (2, 3), (4, 1), (5, 2), (1, 3)] ls.sort(key=lambda x: x[0]+x[1]) ``` ### Comprension de listas 2 ```python # Creando una lista de los primeros 10 cuadrados matematicos cuads = [] for x in range(10): cuads.append(x**2) cuads # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] # Mas eficiente: cuads = list(map(lambda x: x**2, range(10))) # aún mas: cuads = [x ** 2 for x in range(10)] ``` ```python # Esta lista de comprensión combina los elementos de 2 listas # si no son iguales [(x, y) for x in [1, 2, 3] for y in [3, 1, 2] if x != y] # [(1, 3), (1, 2), (2, 3), (2, 1), (3, 1), (3, 2)] # Equivalente a: cuads = [] for x in [1, 2, 3]: for y in [3, 1, 4]: if x != y: cuads.append((x, y)) #tupla #append recive un argumento vec = [-4, -2, 0, 2, 4] # Lista con valores*2 [x * 2 for x in vec] # [-8, -4, 0, 4, 8] # Filtrar excluyendo nros. negativos [x for x in vec if x >= 0] #[0, 2, 4] # Aplicar funcion a elementos [abs(x) for x in vec] #[4, 2, 0, 2, 4] # Metodo a elemento fruta = [' Banana ',' Murtilla ',' Tuna '] [arma.strip() for arma in fruta] #['banana', 'mora de Logan', 'maracuya'] # Lista de Tuplas de dos elementps (nro y nro al cuadrado) [(x, x ** 2) for x in range(6)] # [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] # Aplanar una lista (con 2 for) vec = [[1, 2, 3], [4, 5, 6],[7, 8, 9]] [num for elem in vec for num in elem] # [1, 2, 3, 4, 5, 6, 7, 8, 9] # Pueden tener expresiones complejas y funciones anidadas from math import pi [str(round(pi, i)) for i in range(1, 6)] # ['3.1', '3.14', '3.142', '3.1416', '3.14159'] ``` ### Listas por comprension anidadas > La expresión inicial de una comprensión de listas puede ser cualquier expresión arbitraria, > incluyendo otra comprensión de listas. ```python matriz =[[1, 2, 3, 4], # ej. matrix 3x4 [5, 6, 7, 8], # lista de 3 listas de largo 4 [9,10,11,12]] # Tansponer filas y columnas: [[fila[i] for fila in matriz] for i in range(4)] # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] transp = [] for i in range(4): transp.append([fila[i] for fila in matriz]) transp # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] # es lo mismo que: transp = [] for i in range(4): # comprension de listas anidada fila_tra= [] for fila in matriz: fila_tra.append(fila[i]) transp.append(fila_tra) transp # [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] # Existen funciones predefinidias a declaraciones con flujo complejo # por ej. zip(), para el caso anterior: list(zip(*matriz)) # ** desempaquetando lista de argumentos print(list(zip(*matriz))) # [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)] ``` ### La instrucción del > Elimina uno o mas items de la lista según indice, elimina sección o > lista completa, también se usa para eliminar variables. ```python a = [-1, 1, 66.25, 333, 333, 1234.5] del a[0] # quita -1 del a[2:4] # quita 333 y 333 del a[:] # vacía la lista del a # elimina la variable ``` ---- ## Tuplas Una tupla consiste en valores separados por coma, una tupla va entre parentesis ```python tupla = 12345, 54321, 'hola!' tupla[0] #12345 tupla #(12345, 54321, 'hola!') # las tuplas pueden anidarse u = tupla, (1,2,3,4,5,6) # las tuplas son inmutables #tupla[0] = 88888 #TypeError # Pero pueden contener objetos mutables # Tuplas con objetos mutables como listas # TUPLAS INMUTABLES # LISTAS MUTABLES # Creación de tupas vacia = () single = 'hola', len(vacia) #0 len(single) #1 # Empaquetado de tupla tupla = 1234, 3421, 'hola!' # Tb es posible asignar los elementos a variables # Desempaquetado de secuencias x, y, z = tupla # Las tuplas son secuencias ordenadas de valores # ejemplos tupla = (1, 2.5, 'Hola') tupla[0] #1 tupla[1] #2.5 tupla[2] #'Hola tupla[:2] # (1, 2.5) # Tulpa vacia tupla_vacia1 = () tupla_vacia2 = tuple() # Tupla de un elemento tupla_2 = (5, ) # numero_no_tupla = (5) # longitud de tupla len(tupla) ``` ### Empaquetado y desempaquetado de tuplas ```python # Empaquetado a, b, c, = 20, "T", "A" tupla = a, b, c # Desempaquetado x, y, z = tupla ``` ---- ## Diccionarios Los diccionarios también pueden ser conocidos como "memorias asociativas o "arreglos asociativos". Los diccionarios se indexan con claves, pueden ser cualquiera de tipo inmutable, en vez de un rango numérico como en las secuencias. Las tuplas pueden usarse como claves si solamente contienen cadenas, números o tuplas; si una tupla contiene cualquier objeto mutable directa o indirectamente, no puede usarse como clave. Ni tampoco listas, ya que se modifican con **append()** y **extend()**. Los diccionarios se pueden pensar como un conjunto no ridenado de pares **clave: valor** siendo las claves **UNICAS**. ```python gente = {} vacia gente = {'pepe': 123, 'joel': 234 } ``` ### Las operaciones principales son - Guardar con una clave ```python gente['raul'] = 345 ``` - Extraer de un dict. con una clave ```python gente['joel'] # 234 ``` - Borrar con del clave ```python del gente['pepe'] ``` - Listar claves ```python list(gente.keys()) ``` - Ordenar: ```python sorted(gente.keys()) ``` - condicional busqueda: ```python 'joel' in gente #True 'raul' not in gente #False ``` ### Constructor dict() **Formas de definir un diccionario** ```python precios = {'manzana': 3.5, 'banana': 4.5, 'kiwi': 6.0, 'pera': 3.75} precios = dict(manzana=3.5, banana=4.5, kiwi=6.0, pera=3.75) precios = dict([('manzana', 3.5), ('banana', 4.5), ('kiwi', 6.0), ('pera', 3.75)]) ``` ### Acceso a elementos por claves ```python precios['manzana'] # 3.5 precios['banana'] # 4.5 precios['kiwi'] # 6.0 precios['pera'] # 3.75 #precios['melon'] # KeyError # Agregar un elemento (clave-valor) precios['melon'] = 7.5 # Actualizar un elemento (clave-valor) precios['manzana'] # 3.0 # Borrar un elemento (clave-valor) del precios['kiwi'] # Pertenencia 'banana' in precios 'sandia' not in precios ``` ### Propio diccionario a partir de 2 listas: ```python pregs = ['nombre','altura','edad'] resps = ['cilantro', '16', 'a veces'] pyr = {} for p, r in zip(pregs, resps): pyr[p] = r # En una linea pyr1 = {p: r for p, r in zip(pregs,resps)} # Mas efectivo pyr2 = dict(zip(pregs, resps)) ``` ### Metodos en los diccionarios ```python precios = {'manzana': 3.5, 'banana': 4.5, 'kiwi': 6.0, 'pera': 3.75} # Cantidad de elementos clave-valor len(precios) # Devuelve el valor de clave indicada, se puede definir una por defecto # si no existe, si no se indica None. precios.get('manzana') # 3.5 precios.get('melon') # None precios.get('melon', 0.00) # 0.00 # Si existe devuelve el valor, sino, es creado con el valor default o None # en caso de no indicarlo precios.setdefault('banana') #4.5 precios.setdefault('sandia') #None precios.setdefault('pepino', 6.6) #6.6 # Actualizacion de un diccionario precios.update({'banana': 4.0, 'durazno': 5.5}) precios.update([('durazno', 5.1)]) precios.keys() # Retorna lista con claves del diccionario precios.values() # Retorna lista con los valores del diccionario precios.items() # Retorna lista con los items del diccionario # Sacar elemento segun clave, se puede definir un default si no lanza KeyError precios.pop('manzana') precios.pop('melon', 0.00) # precios.pop('melon') # Sacar elemento segun LIFO (LAST IN FIRST OUT, estilo pila) precios.popitem() # Copia "superficial" de diccionarios precios_cp = precios.copy() # Borra los elementos del diccionario precios.clear() ``` ### Iterando diccionarios Vista dinamica de las entradas del diccionario ```python precios = {'manzana': 3.5, 'banana': 4.5, 'kiwi': 6.0, 'pera': 3.75} # Vista de Diccionarios claves = precios.keys() valores = precios.values() items = precios.items() precios['melon'] = 5.5 # Agregado melon al diccionario # Iteracion de diccionarios for fruta, precio in precios.items(): print("Precio de", fruta, ": $:", precio) # La consulta a las variables previas asignadas como # claves, valores e items. Mantienen sus valores actualizados según # diccionario (apuntan a la misma direccion de memoria?) print('\n',claves,'\n'*2, valores,'\n'*2, items) ``` > Condiciones que deben cumplir las claves en diccionarios > > Los diccionarios están implentados internamente como una tabla hash > por lo que las claves deben ser objetos **Hasheables**. > > \*\***hashable** es un obejto que tiene un valor hash > que nunca cambia durante el ciclo de vida del programa. > > Debe tener definido el metodo mágico __HASH__ > Debe poder ser comparado con otros objetos, es decir > Debe tener definido el metodo __EQ__ > Deben ser iguales cuando su hash son iguales > > Todos los objetos inmutables ofrecidos Built-In en Python son hasheables. > Ej,: **strings - numeros - tuplas - fechas** > > Los contenedores mutables como las listas, conjuntos, > los diccionarios **no** son hasheables. > > Los objetos que son definidos por instancias de clases definidas por el > usuario **son** hasheables por defecto. > > Los hash al compararse, siempre son distintos a otros obejos, > salvo a si mismos. > > Su valor hash se deriba de su ID que es único ### Resumen diccionarios ```python dict([('pepe', 1234), ('joel', 2345), ('raul', 3456)]) # Creación por comprensión de diccionarios desde expresiones arbitrarias clave/valor otro = {x: x ** 2 for x in (2, 4, 6)} # {2: 4, 4: 16, 6: 36} # Si las claves son cadenas simples, se pueden especificar usando argumentos por claves**** otro = dict(pepe=1234, joel=2345, raul=3456) # {'pepe': 1234, 'joel': 2345, 'raul': 3456} # ITERACION .items() caballeros = {'seya': 'pegaso', 'yoga': 'cisne'} for k, v in caballeros.items(): print(k, v) # Al iterar una secuencia se puede obtener tanto el índice como el valor correspondiente, # usando la finción "enumerate()" for k, v in enumerate(caballeros): print(k, v) # 0 seya # 1 yoga # Iterar sobre 2 o mas secuencias, emparejando valores con "zip()" pregs = ['nombre', 'objetivo', 'color favorito'] resps = ['Yorldan', 'volar', 'diciembre'] for p, r in zip(pregs, resps): print('Cual es tu {0}? {1}.'.format(p, r)) # Iterar en orden inverso for i in reversed(range(1, 10, 2)): print(i) # Iterar secuencia ordenada "sorted()" # sorted devuelve una nueva lista ordenada # recordatorio set() <--- conjunto canasta = ['manzana', 'naranja', 'manzana', 'pera', 'naranaja', 'banana'] for f in sorted(set(canasta)): print(f) # A veces, es mas simple y seguro crear una nueva lista, # en vez de cambiar una lista mientras se recorre. import math datos = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8] datos_filtrados = [] for valor in datos: if not math.isnan(valor): datos_filtrados.append(valor) # datos_filtrados ---> [56.2, 51.7, 55.3, 52.5, 47.8] # Recopilacion de metodos de mas arriba # gente['raul'] = 345 # otro = dict(pepe=1234, joel=2345, raul=3456) # otro = { x: x ** 2 for x in (2, 4, 6) } # Base para crear Diccionarios con dos listas pyr = {} for p, r in zip(pregs, resps): pyr[p] = r pyr1 = {p: r for p, r in zip(pregs, resps)} pyr2 = dict(zip(pregs, resps)) ``` ---- ## Generadores Son funciones especiales, devuelven una secuencia de valores, de uno en uno, en cada llamada. Son una forma sencilla y potente de iterador. Un iterador tiene siempre sus elementos disponibles, un generador los va **generando** con un llamado al metodo **__next()__** Con esto se pueden tener generadores, que generen infitinos elementos, *ej. nums. naturales.* Retornan un resultado con la sentencia **yield**. La función queda en "**pausa**" hasta que es invocada nuevamente. ### Creación de generador Un grador. de nros. 0-9 ```python def gen_10(): for n in range(10): yield n ``` Uso, hay que instanciar el generador. Luego usar la funcion **__next__()** al no quedar elementos que iterar, el generador lanza una excepción **StopIteration** ```python a_gen_10 = gen_10() # Instancia del generador a_gen_10.__next__() # 0 a_gen_10.__next__() # 1 a_gen_10.__next__() # 2 ... # 3..8 a_gen_10.__next__() # 9 a_gen_10.__next__() # Traceback (most recent call last): # File "", line 1, in # StopIteration ``` Al igual que los iteradores, los generadores se pueden "consumir" con un ciclo for. **ej. Generador nros. naturales, infinitos** ```python def naturales(): n = 1 while True: yield n n += 1 nats = naturales() ``` **ej. Sentencia "return" para indicar StopIteration** ```python def n_nats(n): i = 1 while True: if i > n: return yield i i += 1 ``` ### Generar los 100 primeros números naturales Similar a las listas por comprensión, solo que estas se escriben entre parentesis ```python # Lista por Comprensión [p for p in range(10) if p % 2 == 0] # [0, 2, 4, 6, 8] # Generador (p for p in range(10) if p % 2 == 0) # at 0x7fb25c49da50> ``` > Los generadores son útiles: > - Trabajando con estructuras infinitas. > - Trabajando con estructuras con alta carga de memoria, se puede reducir el espacio a revisar. > - Se puede retrasar su calculo hasta último momento para favorecer otros procesos. > - Se puede pasar un argumento en caso de acabar el generador. > ejemplo: `next(nats, None)`, `next(nats, 'ratas')` ### Envio de objetos a un generador con send() Esto también produce la 'generación' ```python def accumulator(): total = 0 value = None while True: # receive sent value value = yield total if value is None: break # aggregate values total += value generator = accumulator() # advance until the first "yield" next(generator) # 0 # from this point on, the generator aggregates values generator.send(1) # 1 generator.send(10) # 11 generator.send(100) # 111 # Calling next(generator) is equivalent to calling generator.send(None) # next(generator) # StopIteration ``` ### Uso de generadores ```python def gen1000(): "Genera los pri meros 1000 números." for x in range(1000): yield x primeros1000 = gen1000() for x in primeros1000: print(x, end=" - ") print('\n'*2) ``` ```python def gen_primos(cantidad=1): "Generador de números primos." cont = 1 ls_prim = [] # Comienzo ciclo infinito while cantidad > cont: es_primo = True cont += 1 if len(ls_prim) > 0: for primo in ls_prim: if cont % primo == 0: es_primo = False break if es_primo: ls_prim.append(cont) yield cont prim1000prim = gen_primos(1000) for x in prim1000prim: print(x, end=" - ") ``` ```python def num_par(n): return (x for x in range(n) if x % 2 == 0) gen = num_par(15) gen.__next__() gen.__next__() print(list(gen)) ``` ---- ## Decoradores Los decoradores son funciones, que toman por argumento una función, y devuelven otra funcion. - Ayudan a hacer codigo mas limpio - Reducen el codigo común y repetitivo - Favorecen la separacion de responsabilidades del codigo - Aumentan la legibilidad y mantenibilidad del progama Son funciones: - Reciben una funcion y devuelven otra función. - Sirven para extender funcionalidad de una func. o también para agregar funcionalidad yuxtapuesta a la misma. ej. Decorando una función, con otra que mide el tiempo de ejecución > Notar el orden: > explicit args, luego \*args, luego \*\*kwargs. > ejm. `def foo(arg1, arg2, *args, **kwargs):` ```python def smart_division(div_func): def div(a, b): if b == 0: print("No se puede dividir por cero!") return return div_func(a, b) return div @smart_division def division(a, b): return a / b r = division(1, 2) print(r) r = division(2, 0) print(r) ``` ### Decorador generico El anterior recibe 2 parametros en este vamos a pasar cualquier cantidad de argumentos ```python def log(f): def wrap(*args, **kwargs): print('Ejecutando la función', f.__name__, 'con los argumentos', ', '.join([str(arg) for arg in args])) return f(*args, **kwargs) return wrap @log def suma(a, b): return a + b print(suma(1,2), '\n') @log @smart_division def division_2(a, b): return a / b r = division_2(1, 2) print(r) r = division_2(2, 0) print(r) ``` Los decoradores sirven para un código mas legible y cohesionado. ### Mas decoradores ```python import time def time_meter(f): def wrap(*args, **kwargs): ti = time.time() result = f(*args, **kwargs) tf = time.time() etime = tf-ti print("La func.",f.__name__,"demoró",round(etime, 5),"segundos en ejecutarse") return result return wrap @time_meter def suma(a, b): time.sleep(0.2) print('retraso') return a+b suma(1,3) ``` ### Los decoradores tb pueden recibir parametros ```python def logger(debug=False): def _logger(func): def inner(*args,**kwargs): if debug: print("Modo Debug") for i, arg in enumerate(args): print("arg %d:%s" % (i,arg)) return func(*args, *kwargs) return inner return _logger @logger(True) def suma(a,b): return a+b suma(2, 5) #Modo debug #arg 0:2 #arg 1:57 #7 @logger(False) def suma(a, b): return a + b suma(2, 5) #arg 0:2 #arg 1:57 #7 # Este tieme una función anidada más, el decorador recibe parámetros propios # La 1ra función anidada recibe la función decorada. # La 3ra función anidada tiene la lógica del decorador. # Los decoradores pueden anidarse, una funcion puede tener muchos decoradores # ej. @logger(True) @time_meter def suma(a,b): return a+b suma(2, 7) print('') @time_meter @logger(True) def suma(a,b): return a+b suma(2, 7) ``` ---- ## Ejercicios Modulo 2 ### Verdureria ```python La verdulería greengrocer nos pasó su listado de precios por kilo. Utilizando una consola de Python, crear el diccionario con la lista de precios: precios = {'manzana': 3.5, 'banana': 4.5, 'kiwi': 6.0, 'pera': 3.75, 'ciruela': 2.45, 'durazno': 4.55, 'melon': 7.35, 'sandia': 9.70, 'anana': 11.25} ``` Si tenemos el siguiente ticket de una compra ``` 2 kg de manzana 2.5 kg de banana 1 kg de kiwi 3 kg de pera 1 kg de ciruela 2 kg de durazno 5 kg de melón 10 kg de sandía 3 kg de ananá ``` ¿Cuál es el precio del ticket de compra? ```python precios = { 'manzana' : 3.5, 'banana' : 4.5, 'kiwi' : 6.0, 'pera' : 3.75, 'ciruela' : 2.45, 'durazno' : 4.55, 'melon' : 7.35, 'sandia' : 9.70, 'anana' : 11.25, } pedido = { 'manzana' : 2.0, 'banana' : 2.5, 'kiwi' : 1.0, 'pera' : 3.0, 'ciruela' : 1.0, 'durazno' : 2.0, 'melon' : 5.0, 'sandia' : 10.0, 'anana' : 3.0, } sub_total = 0 for key in pedido.keys(): if key in precios.keys(): sub_total += pedido[key] * precios[key] print('TOTAL =', sub_total) d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} resp = d.get('z', 7) == 7 print(resp) resp = d.get('z') == None print(resp) resp = d.setdefault('z', 5) == 5 print(resp) resp = d.setdefault('a', 7) == 7 print(resp) resp = d['a'] == 1 print(resp) resp = d.get('a', 3) == 3 print(resp) d.update([('a', 10)]) print(d.get('a')) d.update({'a': 1, 'b': 3}) print(d.get('a'), d.get('b')) d.update((('a', 45), ('b', 54))) print(d.get('a'), d.get('b')) d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} resp = d.pop('f', 2) == 2 print(resp) print(d) resp = d.pop('c') == 3 print(resp) d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} resp = d.popitem() == 5 print(resp) d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} resp = d.pop('a', 2) == 2 print(resp) #d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} #resp = d.popitem() == (e, 5) #print(resp) d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} resp = d.pop() == 5 print(resp) espera = input('esperando') print(espera) ``` ---- ## El Gato ``` Deberás programar el juego TA-TE-TI. Cuando el programa comienza a correr, en la pantalla aparece el tablero de TA-TE-TI (de 3x3) y un input que permite al usuario elegir el símbolo “X” o el símbolo “O”. Las “X” empiezan. El usuario debe elegir la posición del tablero (esta posición debe ser correcta y no debe estar ocupada) donde poner el símbolo en el tablero y el sistema valida si el juego termina con un ganador o en empate. Si no hay ganador o la partida no terminó todavía en empate, el juego continúa preguntando al otro usuario que seleccione la posición del tablero dónde quiere poner su símbolo y así siguiendo hasta que la partida termine con un ganador o en empate. Notas: Representar el tablero como una matriz de 3x3. El juego termina en empate cuando el tablero está completo y no hay ganadores. ``` > Este archivo ha sido creado con fines didacticos y como entrega final del 2do > modulo del Curso Aprende a Programar en Python, dictado por la Universidad Austral, > a travez de Coursera > @autor: devfzn@gmail.com ```python import random import os from time import sleep clear = lambda: os.system('clear') if os.name == 'posix' else os.system('cls') limpiar_pantalla = True """ Creación de matriz base""" #matriz = [['a1', 'b1', 'c1'], ['a2', 'b2', 'c2'], ['a3', 'b3', 'c3']] matriz = [['|_','|_','|_'], ['|_','|_','|_'], ['|_','|_','|_']] # Creacción de dicionario vacío y lista de llaves. master, llaves = {}, [x+y for x in 'abc' for y in '123'] # Preguntas para solicitar entradas de usuario lado = '\tEscribe \'o\' para jugar con \'O\',\n\to \'x\' para jugar con \'X\',\n\t(\'X\' hace la primera jugada)\n\t> ' salir = '\tJugar Otra? (si/no)\n\t> ' jugada = '\tIngresa tu jugada (ej. a2)\n\t> ' tit_V = 'Ganaste, Felicitaciones!' tit_P = ' Has perdido' # Lista con tuplas de condiciones para ganar o perder el juego. ganadoras = [('a1', 'b1', 'c1'), ('a2', 'b2', 'c2'), ('a3', 'b3', 'c3'), ('a1', 'a2', 'a3'), ('b1', 'b2', 'b3'), ('c1', 'c2', 'c3'), ('a1', 'b2', 'c3'), ('c1', 'b2', 'a3')] def actualizar_matriz(): """ Actualiza los valores en la matriz según los valores en diccionario maestro :return: None """ x, y = 0, 0 # Variables para indices de matriz tablero for valor in master.values(): # Recorre los valores del diccionario if not y < 3: # Limite indice columnas y = 0 # Reinicio contador columnas x += 1 # Autoincremento de fila al llegar a 3ra columna matriz[y][x] = valor # Asigna el valor del diccionario a la matriz (casilla) y += 1 # Autoincremento de columna def dibujar_tablero(*frase): """ Muestra en pantalla un string pasado como argumento, (coordenadas y matriz de juego) :param frase: titulo a mostrar según circunstancia :return: None """ if limpiar_pantalla: clear() print('\n\t', *frase, '\n\n\t\t a b c') for x in range(len(matriz)): print('\t\t', end=str(x+1)) for y in range(len(matriz[x])): print(matriz[x][y], end='') print('|') print('\n') # ANIMACION saludo = ['\n\tBienvenido al Clasico ', '\n\n\n\t\t\"GATO!\"'] jugadas = [[0, 0], [1, 2], [2, 0], [1, 0], [1, 1], [2, 2], [0, 2]] def parp_text(repets, *texto): print(len(texto)) x, sec = 0, True while x < repets: for txt in texto: for tx in txt: clear() print('\n\t', tx) sleep(0.7) x += 1 sleep(1) def animacion(): actualizar_matriz() for x in range(len(jugadas)): if x % 2 == 0: matriz[jugadas[x][0]][jugadas[x][1]] = '|X' else: matriz[jugadas[x][0]][jugadas[x][1]] = '|O' dibujar_tablero('\"devfzn@gmail.com\"') sleep(0.5) animacion() parp_text(2, saludo) def input_usr(pregunta, respuestas): """ Solicita una entrada al usuario, recive 1 string y una lista de string :param pregunta: string Pregunta a realizar :param respuestas: [string] Lista de posibles respuestas en mayúscula :return: 'string' input de usuario validado """ resp = '' # Variable que recibe entrada de usuario while resp not in respuestas: # Valida respuesta según 'respuestas' resp = input(pregunta).upper() # Asignación entrada de usuario (mayusculas forzadas) return resp jugar = True # Variable que gobierna el ciclo principal (Juego) while jugar: # Ciclo principal global turno # for llave in llaves: # Recorre las llaves y asgina '|_'(vacío) a cada item master[llave] = '|_' slave = master.copy() # Copia superficial del diccionario maestro actualizar_matriz() # Poblar matríz con los valores del diccionario maestro dibujar_tablero(' Elige el lado X - O') # Imprime matríz en pantalla global p1 p1 = input_usr(lado, ['x', 'X', 'o', 'O']) # Asignación de entrada de usuario, P1 (Player 1) titulo = 'P1 jugando con -> ' + p1 cambio = lambda x: 'O' if x == 'X' else 'X' # Función anónima retorna el símbolo opuesto al evaluado X,O global pc pc = cambio(p1) # Asignación de símbolo a jugador PC (Player Computer) turno = 0 # Contador de turnos jugados dibujar_tablero(titulo) def turno_p1(): """ Función que recibe una entrada de usuario y la valida según la copia de las llaves del diccionario maestro. Actualiza el valor en el diccionario maestro con el symbolo seleccionado por el jugador PC y e xtrae la copia de 'slave' :return: None """ jp1 = input_usr(jugada, list(x.upper() for x in list(slave.keys()))).lower() slave.pop(jp1) master[jp1] = '|' + p1 def turno_pc(): """ Función que selecciona una llave al azar de la copia del diccionario maestro y actualiza a este último con el simbolo del jugador PC. Despues del turo nro. 2 evalúa si hay algún espacio estrategico, donde existen dos simbolos iguales, pone el tercero, priorizando los pares de symbolos afines con el bando asignado. :return: None """ if turno > 2: falta, hay_par = (), False for pos in ganadoras: a, b, c = master[pos[0]], master[pos[1]], master[pos[2]] if '|_' != a == b != c == '|_': falta = (a, pos[2]) hay_par = True if a == pc + '|_': break elif '|_' != a == c != b == '|_': falta = (a, pos[1]) hay_par = True if a == pc + '|_': break elif '|_' != c == b != a == '|_': falta = (c, pos[0]) hay_par = True if c == pc + '|_': break if hay_par: jpc = falta[1] else: jpc = ''.join(random.choice(list(slave.keys()))) else: jpc = ''.join(random.choice(list(slave.keys()))) slave.pop(jpc) master[jpc] = '|' + pc def eval_term(): """ Función que evalua si se cumplen las condiciones para terminar la partida. Compara los valores el diccionario 'maestro' según las llaves en las tuplas, de la lista 'ganadaoras'. Asigna un titulo y un valor al booleano 'termino' :return: None """ global titulo global termino for g in ganadoras: test = master[g[0]] test2 = '|' + p1 if '|_' != test == master[g[1]] == master[g[2]]: termino = True titulo = tit_V if test2 == '|X' == test else tit_V if test2 == '|O' == test else tit_P if turno > 8 and not termino: termino, titulo = True, '\t EMPATE' X = p1 == 'X' # Booleano indica si jugador 1 es 'X' termino = False # Booleano que gobierna ciclo de jugadas while not termino: # Ciclo de jugadas turno_p1() if X else turno_pc() # Alterna el turno del Player1 y PC, segun 'X' X = not X # Alterna el booleano 'X' turno += 1 eval_term() actualizar_matriz() dibujar_tablero(titulo) resp = input_usr(salir, ['N', 'NO', 'S', 'SI']) jugar = resp in 'SI' # Actualización del booleano que gobierna while principal autor = ['', '\n\n\t "devfzn@gmail.com\"'] parp_text(4, autor) ```