<jupyter_start><jupyter_text>Introducción a la Programación en PythonEn este taller revisaremos brevemente las propiedades y ventajas que ofree Python para el aprendizaje de programación. Python es un lenguaje de programación interpretado multiparadigma (Imperativo, Funcional, Orientado a Objetos).Puede ser ejecutado de diferentes formas:- por línea de comando- a través de un IDE- interactivamentePara el desarrollo de este tutorial, utilizaremos Python 3.7. Las versiones 3.x no son "backward" compatibles con versiones de Python 2.x. Es recomendable trabajar en Python 3.x.  ExpresionesEn el interprete podemos manejar directamente expresiones. Al ser interpretado permite generar los resultados interactivamente.<jupyter_code>1024 + 512
x = 1.2
x ** 2<jupyter_output><empty_output><jupyter_text>Tipos de DatosPython maneja de forma nativa tipos de datos básicos y estructuras de datos más complejas:- Enteros: `int`- Reales: `float`- Complejos: `complex`- Lógicos: `bool`- Texto: `str`<jupyter_code>int('5')
float('5.4')
float('Inf')
float('-Inf')
a = complex(1, 1)
a
a.conjugate()
a.real
a.imag
str(5)<jupyter_output><empty_output><jupyter_text>Sin embargo, en Python todos los datos son objetos. Por ejemplo, los datos de tipo `float` o `str` poseen varios métodos *built-in*.<jupyter_code>(2.0).is_integer()
(-2.3).is_integer()
'hola'.capitalize()<jupyter_output><empty_output><jupyter_text>Operadores LógicosPython maneja los operadores lógicos básicos en todo lenguaje de programación:- ```True / False```- ```not```- ```and```- ```or```- ```, >=```- ```==```- ```is, in```<jupyter_code>not False
(False or (not False)) and (not True)
((3 + 4) < 2) or ((2 ** 4) >= 4)
2 in [1, 2, 5, 6]
4 == 5<jupyter_output><empty_output><jupyter_text>Operadores Matemáticos<jupyter_code>1 + 4
9 - 5
print(44 / 9)  # División
print(44 // 9)  # División entera
print(44 % 9)  # Módulo
3 ** 3<jupyter_output><empty_output><jupyter_text>Operadores Bitwise- `x | y`: bitwise or of x and y- `x ^ y`: bitwise exclusive or of x and y- `x & y`: bitwise and of x and y- `x << n`: x shifted left by n bits- `x >> n`: x shifted right by n bits- `~x`: the bits of x inverted<jupyter_code>a = 60
b = 13
bin(a)  # 0010 1100
bin(b)  # 0000 1101
bin(a & b)  # 12 = 0000 1100
bin(a ^ b)  # 49 = 0011 1101<jupyter_output><empty_output><jupyter_text>Operadores de TextoPython acepta válido como una cadena de caracteres o *string* a cualquier secuencia entre comillas simples `' '` o dobles `" "`.<jupyter_code>'Canta' + "gallo"
"Leru" * 10
len('supercalifragilisticoespialidoso')
'amarillo'[4]
'amarillo'[4:6]
# Este es un comentario
"""
Este es un comentario
mas largo para hacer docstrings.
"""
'amarillo'[-1]
'dante' in 'ayudante'
'dante' in 'profesor'<jupyter_output><empty_output><jupyter_text>Funciones Built-In<jupyter_code>abs(4 - 5)
len('Inacap')
min(4.3, 3.1)
round(54.6)
type(3.2)
pow(3, 2)<jupyter_output><empty_output><jupyter_text>Funciones de I/O<jupyter_code>nombre = input('Ingrese nombres: ')
print('El nombre es', nombre)<jupyter_output>El nombre es Benito<jupyter_text>La función input simpre retorna un string. Debe ser transformada (casting) al tipo de variable que se necesita.<jupyter_code>numero = int(input('Ingrese numero: '))
type(numero)
print('El numero es ', numero)<jupyter_output>El numero es  40<jupyter_text>Podemos dar formato al texo utilizando el método ```format()```. Los indices en `{indice}` dispuestos en la plantilla tienen relación con el orden de parametros asignadas en el método `format`.<jupyter_code>print('El nombre es {1} y el appellido {0} y su edad es {2:.2f} años'.format('pedro', 'piedra', 23.4645))<jupyter_output>El nombre es piedra y el appellido pedro y su edad es 23.46 años<jupyter_text>Si ningún indice es asignado a los elementos definidos por `{}` el orden será el mismo con que se pasaron los parámetros al método `format`.<jupyter_code>print('El nombre es {} y el appellido {} y su edad es {:.2f} años'.format('pedro', 'piedra', 23.4645))<jupyter_output>El nombre es pedro y el appellido piedra y su edad es 23.46 años<jupyter_text>Estructuras de ControlEn general todas las estructuras en Python se manejan por indentación. El estándar son 4 espacios o un tabulador.  Estructuras Condicionales: IF / ELIF / ELSEEl uso de estructuras de control condicional en Python es a través de IF/ELSE/ELIF. EL patrón queda como:```pythonif condicion_1:    elif condicion_2:    elif condicion_3:    else:    ```  Ciclos: FOR y WHILEEn Python al igual que otros lenguajes, el control de ciclos se realiza a través de la sentencia ```for```. Para eso requiere un rango de datos provisto por la función ```range(inicio, término, pasos)```. Por defecto ```range``` siempre entreva un rango de números desde $0$ hasta $n-1$ con pasos de 1.<jupyter_code># Range es un generador, al usar list() forzamos a que retorne 
# la lista de números generada. Es solo para fines didácticos, 
# no es necesario de hacer esto en la práctica.

list(range(10))  
list(range(2, 10))
list(range(2, 10, 2))<jupyter_output><empty_output><jupyter_text>El patrón para los ciclos `for`es el siguiente.```pythonfor variable_de_control in rango:    ```<jupyter_code>for i in range(10):
    print(i)<jupyter_output>0
1
2
3
4
5
6
7
8
9<jupyter_text>Los ciclos por `for` pueden estar anidados.<jupyter_code>for i in range(5):
    for j in range(3):
        print(i, j)<jupyter_output>0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
3 0
3 1
3 2
4 0
4 1
4 2<jupyter_text>En general, la sentencia `for` de Python funciona para cualquier tipo de variable que sea iterable. Por ejemplo, podemos iterar directamente sobre string:<jupyter_code>for letra in 'palabra':
    print(letra)
# La variable de control persiste luego de que el ciclo ha concluido.
letra<jupyter_output><empty_output><jupyter_text>Para hacer estructuras de repetición en los cuáles se desconoce a prior el número de iteraciones Python tiene la estructura de ```while``` que funciona bajo el siguiente patrón:```pythonwhile condicion_de_parada:    ```<jupyter_code>acc = 0
while acc < 5:
    acc = acc + 2  
    # acc += 2 # Se puede hacer operaciones aritméticas abreviadamente similar a i++ en C+++
    print(acc)<jupyter_output>2
4
6<jupyter_text>Interrupción de CiclosLos ciclos pueden ser interrumpidos mediante las sentencias:- `break`: interrumpe completamente el ciclo- `continue`: salta la iteración<jupyter_code>n = 1

es_primo = True

for d in range(2, n):
    if n % d == 0:
        es_primo = False
        break

print(es_primo)
# Imprimir números impares del 1 al 20
for i in range(1, 20):
    if i % 2 == 0:
        continue
    print (i)<jupyter_output>1
3
5
7
9
11
13
15
17
19<jupyter_text>Estructuras de DatosPython también incorpora de forma nativa un conjunto de estructuras de datos que facilitan el manejo de datos.  TuplasLas tuplas son estructuras de datos secuenciales y ordenadas. Los datos mantienen el orden con que originalmente fueron creadas.<jupyter_code>triangulo = ((5, 1), (2, 4), (-2, 0))
triangulo<jupyter_output><empty_output><jupyter_text>Las tuplas son inmutables, es decir, los contenidos en ella no pueden ser modificados una vez que ya han sido creados. Si esto ocurre Python levantará una excepción de tipo indicando que no soporta la asignación de nuevos datos.<jupyter_code>triangulo[0] = (4, 3)
personaje = ('<NAME>',
             (1848, 4, 3),
             (1879, 5, 21))
nombre, nacimiento, defuncion = personaje
an, mn, dn = nacimiento
ad, md, dd = defuncion
ad - an
if nacimiento < defuncion:
    print('mayor')<jupyter_output>mayor<jupyter_text>ListasLas listas son estructuras de datos secuenciales y ordenadas. Son mutables, es decir, que los elementos almacendados en la lista pueden cambiar o pueder ser asignados dinámicamente a lo largo de la ejecución del programa.<jupyter_code>colores = []  # Lista vacía, tamnbien colores = list()

# Agregar colores a la lista usando append
colores.append('rojo')
colores.append('amarillo')
colores.append('verde')
colores.append('azul')
colores.append('naranja')
colores
print(colores[2])  # retorna el tercer ítem de la lista
print(colores.index('amarillo'))
colores.append('negro')
colores
colores.pop()
colores
print(colores)
del colores[2]  # Elimina elemento indicado
print(colores[2])
colores.insert(3, 'gris')  # Inserta elementos
print(colores)
colores.sort()  # Sort() ordena internamente la lista y no retorna nada.
print(colores)
# Extend
colores.extend(['celeste', 'negro'])
colores
# Slices
print(colores[1:3])
# Iterar sobre la lista
for i in colores:
    print(i)
a = list('palabra')
a[0] = 't'
''.join(a)
# Crear listas por comprensión
a = [a[0] for a in ['limon', 'naranja', 'pera']]
a
# Copiar lista y cambiar valores
tmp = list(colores)
tmp[0] = 'blanco'
tmp
id(tmp)
id(colores)
colores<jupyter_output><empty_output><jupyter_text>DiccionariosLos diccionarios son estructuras de datos del tipo `llave: valor`. Los valores son mutables, pero la llave debe un tipo de dato inmutable. Además, la llave debe ser única.<jupyter_code>telefonos = {
    'Juan': 5552437,
    'Pedro': 5551428,
    'Carla': 5550012
}
telefonos['Juan']<jupyter_output><empty_output><jupyter_text>Cuando se asigna un valor a una llave el compartamiento es:- si la llave no existe, se crea en el diccionario y se le asigna el valor,- si la llave ya existe, se actualiza al valor asignado<jupyter_code># Creación de diccionarios
d = {}  # o dict()
d['a'] = 5
d['x'] = 6
d['m'] = 8
d['a'] = 10  # Este último valor es el que prevalece
d<jupyter_output><empty_output><jupyter_text>Los valores asignados se obtienen haciendo referencia a la llave.<jupyter_code>d['a']
patas = {
    'humano': 2, 
    'pulpo': 8, 
    'perro': 4, 
    'gato': 4, 
    'cienpies': 100}
patas
list(patas)  # Transformarlo a lista
'perro' in patas  # Verifica si existe llave
len(patas)<jupyter_output><empty_output><jupyter_text>Es posible iterar sobre los diccionarios. Por defecto, la iteración actúa sobre las llaves.<jupyter_code># Recorrer diccionarios
for llave in patas:
    print(llave)
# Los mismo pero llamando explicitamente el método que expone las llaves.
for llave in patas.keys():
    print(llave)<jupyter_output>humano
pulpo
perro
gato
cienpies<jupyter_text>Pero, también es posible hacerlo sobre los valores usando el método `values()`.<jupyter_code># Recorrer diccionarios
for valor in patas.values():
    print(valor)<jupyter_output>2
8
4
4
100<jupyter_text>Con el método `items()` es posible exponer tanto llaves y valores, desempaquetando la tupla retornada.<jupyter_code># Recorrer diccionarios
for llave, valor in patas.items():
    print(llave, valor)<jupyter_output>humano 2
pulpo 8
perro 4
gato 4
cienpies 100<jupyter_text>ConjuntosLos conjuntos son estructuras de datos agrupar colecciones de objetos, en general similares entre si, aunque Python es flexible en relación al tipo de objeto o dato. Funcionan similares a los conjuntos en matemáticas. Son estructuras de datos no ordenadas ni secuenciales.<jupyter_code>colores = {'rojo', 'gris', 'azul', 'gris'}  # set([])
colores
# Creación de conjuntos
a = set()
a.add(19)
a.add(12)
a.add(8)
a.add(12)  # Objetos repetidos solo serán ingresados una sola vez.
a
a.remove(19)
a
9 in a
# Operaciones en conjuntos
a = {1, 2, 3, 4}
b = {2, 4, 6, 8}

print(a & b)  # Y
print(a | b)  # O
print(a - b)  # Diferencia
print(a ^ b)  # Diferencia simiétrica
print({1, 2} < a)  # Comparación<jupyter_output>{2, 4}
{1, 2, 3, 4, 6, 8}
{1, 3}
{1, 3, 6, 8}
True
{'fraction_non_alphanumeric': 0.10999387951385853, 'fraction_numerical': 0.030077817609512985, 'mean_word_length': 5.01050972149238, 'pattern_counts': {'":': 0, '<': 107, '<?xml version=': 0, '>': 105, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '28', 'dir': 'jupyter-structured-clean-dedup', 'id': '68340', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 4555, 'n_tokens_neox': 4324, 'n_words': 1415, 'path': 'material/taller_python_01_sentencias.ipynb', 'repo_name': 'cpieringer/intro_python', 'size': '11442'}