Apuntes_Python/01_curso/Modulo_1/README.md

2036 lines
41 KiB
Markdown

**Ir a:**
[*Repositorio*](https://gitea.kickto.net/devfzn/Apuntes_Python),
[*Modulo 2*](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_2#modulo-2-python-basico)
## Modulo 1 - Python basico
#### [Indice](#modulo-1-python-basico)
- [Primeros Pasos](#primeros-pasos)
- [Tipos de Datos](#tipos-de-datos)
- [Modulo Math](#modulo-math)
- [Condicionales](#condicionales)
- [Funciones](#funciones)
- [Expresiones Lambda](#expresiones-lambda)
- [Docstrings](#docstrings)
- [Ejemplos print, if, for, range y while](#ejemplos-print-if-for-range-while)
- [Sentencias brake, else y continue](#sentencias-brake-else-y-continue)
- [Entorno Virtual](#entorno-virtual)
- [import](#import)
- [modulo fibo](#modulo-fibo)
- [Iteradores](#iteradores)
- [Debugger](#debugger)
- [Ejercicios](#ejercicios)
- [Actividad 1](#actividad-1)
- [Actividad Dados](#actividad-dados)
## Primeros Pasos
Hola Mundo!
```python
print("Hola Mundo")
```
Entrada de usuario
```python
nombre = input("Ingresa tu nombre: ")
print("Hola", nombre, "!")
```
Ejemplo fibo
```python
# Serie de Fibonacci: La suma de dos elementos define el sgte.
a, b = 0, 1
while b < 10:
print(b, end=', ')
a, b = b, a+b
```
Print básico
```python
a = input("ingresa un número: ")
b = input("ingresa otro número: ")
a = int(a)
b = int(b)
c = a * b
print("La Multiplicación de los números",a,"y",b,"es",c)
a = input("ingresa un número: ")
b = input("ingresa otro número: ")
a = int(a)
b = int(b)
c = a + b
print("La SUMA de los números",a,"y",b,"es ",c)
```
### Operaciones aritméticas
**Division sin resto** ` // `
```python
4//3
# 1
```
**Resto** ` % `
```python
4%3
# 1
```
**Potencia** ` ** `
```python
# 5 al cuadrado
5 ** 2
# 2 a la potencia de 7
2 ** 7
```
**Última expresion** ` _ `
```python
1+3
# 4
3 + _
# 7
```
**Redondeo** `round("número", "decimales")`
```python
round(8.6786346, 1)
# 8.7
```
Además de **int** y **float**, Python soporta otros como **Decimal** y **Fraction**, además
tiene soporte integrado para **números complejos**.
> usa **j** o **J** para indicar la parte imaginaria, ej.
> **` 3+5+j `**
### Strings
Cadena Cruda **r'cadena'**
```python
print(r'C:\\algun\directorio')
print('\t',r'~/Documentos')
print("""...\
Fin de linea
es automatico
puedes evitarlo con \\
""")
```
Las cadenas de texto pueden ser *operadas* con **` + `** y **` \ `**
```python
3 * 'al' + 'mendra'
# 'alalalmendra'
palabra = 'Python'
palabra[0]
# 'P'
palabra[5]
#'n'
# último caracter
palabra[-1]
# 'n'
# penúltimo caracter
palabra[-2]
# 'o'
palabra[-6]
# 'P'
# caracteres desde pos 0 (incluida) a 2 (exluida)
palabra[0:2]
# 'Py'
# caracteres desde pos 2 (incluida) a 5 (exluida)
palabra[2:5]
# 'tho'
palabra[:2] + palabra[2:]
# 'Python'
palabra[:4] + palabra[4:]
# 'Python'
len(palabra)
# 6
```
### Listas
```python
# definir
cuadrados = [1, 4, 9, 16]
# sumar listas
cuadrados + [36, 49, 64, 81, 100]
# modificar lista
cubos = [1, 8, 27, 65, 125 ] # cubos[3] debiera ser 64
cubos[3] = 64
# Agregar el cubo de 6
cubos.append(216)
# y el cubo de 7
cubos.append(7 ** 3)
```
```python
letras = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
# reemplazar algunos valores
letras[2:5] = ['C', 'D', 'E']
# borrarlas
letras[2:5] = []
# reemplazar los elementos por una lista vacia
letras[:]
# Largo( lista )
len(letras)
# Listas agurapdas
a = ['a', 'b', 'c']
n = [1, 2, 3]
x = [a, n]
x # [['a', 'b', 'c'], [1, 2, 3]]
x[0] # ['a', 'b', 'c']
x[0][1] # 'b'
```
[1-1_primeros_pasos.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-1_primeros_pasos.py)
----
# Tipos de Datos
Consola python: `python -i`
```python
>>> type(8)
<class 'int'>
>>> type(10.5)
<class 'float'>
>>> type(True)
<class 'bool'>
>>> type('hola')
<class 'str'>
>>> type(3+4j)
<class 'complex'>
```
### Variables
- Tipado dinámico
- CaseSensitive
```python
>>> numero = 4
>>> type(numero)
<class 'int'>
>>> numero = 4.5
>>> type(numero)
<class 'float'>
>>> nada = None
>>> type(nada)
<class 'NoneType'>
```
**Expresiones**:
* ` 1 + 1 ` : Expresión que combina **dos valores** y **un operador**.
* ` numero + 1 ` : Expresión que combina **una variable**, **un valor** y **un operador**.
### Operadores:
* **Unarios** y **Binarios**, que requieren uno o dos operandos.
- Operadores **Aritmeticos**: **`+` `-` `*` `/` `//` `%` `**`**
- Operadores **Asignación**: **`=` `+=` `-=` `*=` `/=` `//=` `%=` `**=`**
- Operadores **Comparación**: **`==` `!=` `<` `<=` `>` `>=`**
- Operadores **Lógicos**: **`and` `or` `not`**
Ejemplos operadores de comparación
|Ejm. op.|Resultado|
|-|-|
|`1 == 1 `|True |
|`1 != 1 `|False|
|`1 > 2 `|False|
|`2 > 3 `|False|
|`1 >= 1 `|True|
|`2 <= 3 `|True|
|`a == b`|False|
|`a != b`|True|
|`a < b `|True|
|`1 < 2 < 3 `|True|
### Tablas de Verdad
#### and
|Var. A|Op.|Var. B|Resultado
|-|-|-|-|
| `True` | **and** | `True` | True |
| `True` | **and** | `False` | False |
| `False` | **and** | `True` | False |
| `False` | **and** | `False` | False |
#### or
|Var. A|Op.|Var. B|Resultado
|-|-|-|-|
| True | **or** | True | True |
| True | **or** | False | True |
| False | **or** | True | True |
| False | **or** | False | False |
#### not
| Op. | Var. | Resultado |
|-|-|-|
| **not** | True | False |
| **not** | False | True |
### Precedencia de operadores
| Orden Predecendencia|Operadores|
|:-:|---------------|
| 1 | `**` |
| 2 | ` * `, ` / `, ` % `, ` // ` |
| 3 | ` + `, ` - ` |
| 4 | ` <= `, ` < `, ` > `, ` >= `|
| 5 | ` == `, ` != ` |
| 6 | ` not `, ` or `, `and ` |
| 7 | ` = `, ` %= `, ` /= `, ` -= `, ` += `, ` *= `, ` **= ` |
[1-2a_tipos_datos.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-2a_tipos_datos.py)
----
## Modulo Math
```python
import math
```
Constantes:
```python
pi, e, tau, inf, nan ( math.pi ; math.cos(0) )
```
#### Funciones math
|Función|Detalle|Ejemplo|
|-|-|-|
|ceil | Redondea al sgte. entero | `ceil(3.2) # 4`|
|floor | Redondea al entero anterior| `floor(3.2) # 3`|
|ceil | Valor absoluto | `fabs(-4) # 4`|
|factiorial | Func. factorial | `factorial(4) # 24`|
#### Funciones de potencia y logarítmicas
|Función|Detalle|Ejemplo|
|-|-|-|
|exp | e^x | `exp(1) # e` |
|expm1 | (e^x) -1 | `exp(1)e -1 # e-1` |
|log | logaritmo natural | `log(e) # 1` |
|log2 | logaritmo en base 2 | `log(2) # 1` |
|log10 | logaritmo en base 10 | `log(10) # 1` |
|pow | Potencia | `pow(3,2) # 9` |
|sqrt | Raíz cuadrada | `sqrt(9) # 3` |
#### Funciones trigonométricas
|Función|Detalle|Ejemplo|
|-|-|-|
|acos | arco coseno | `acos(1) # 0` |
|asin | arco seno | `asin(0) # 0` |
|atan | arco tangente | `atan(0) # 0` |
|cos | coseno | `cos(pi) # -1` |
|hypot | hipotenusa | `hypot(1,1) # 1.14121356...` |
|sin | seno | `sin(pi/2) # 1` |
|tan | tangente | `tan(pi/4) # 0.99999999...` |
Consola de python: `python -i`
```python
>>> import math
>>> help(math)
>>> math.sqrt(16)
4.0
>>> math.log(math.e)
1.0
```
## Modulo Random
Forma parte de la libreria estandar de python
Consola de python: `python -i`
```python
>>> import random
>>> random.random()
0.1430076482629129
>>> random.random()*10
6.753608889973483
>>> (random.random()*10)%6+1
2.279082688613001
>>> (int(random.random()*10)%6+1)
4
>>> (int(random.random()*10)%6+1)
4
>>> (int(random.random()*10)%6+1)
6
>>> (int(random.random()*10)%6+1)
4
>>> (int(random.random()*10)%6+1)
3
>>> clear
```
### Choice
Consola de python: `python -i`
```python
>>> random.choice([1,2,3,4,5,6])
1
>>> random.choice([1,2,3,4,5,6])
1
>>> random.choice([1,2,3,4,5,6])
2
>>> random.choice([1,2,3,4,5,6])
4
>>> random.choice(['Rojo', 'Verde', 'Azul])
random.choice(['Rojo', 'Verde', 'Azul])
>>> random.choice(['Rojo', 'Verde', 'Azul'])
'Verde'
>>> random.choice(['Rojo', 'Verde', 'Azul'])
'Verde'
>>> random.choice(['Rojo', 'Verde', 'Azul'])
'Rojo'
>>> random.choice(['Rojo', 'Verde', 'Azul'])
'Verde'
```
### Choices
Consola de python: `python -i`
```python
>>> random.choices([1,2,3,4,5,6], k=2)
[4, 6]
>>> random.choices([1,2,3,4,5,6], k=2)
[4, 3]
>>> random.choices([1,2,3,4,5,6], k=2)
[3, 4]
```
[1-2b_libreria_math.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-2b_libreria_math.py)
----
## Condicionales
```python
x = 2
if x >= 0:
print('El número',x,'es positivo')
else:
print('El número',x,'es negativo')
# El número 2 es positivo
```
#### Condicionales Encadenados
```python
if x >= 0:
print('El número',x,'es positivo')
elif x < 0:
print('El número',x,'es negativo')
else:
print('El número es igual a cero')
# El número 2 es positivo
```
#### Condicionales Anidados
```python
x = 0
if x > 0:
print('El número',x,'es positivo')
else:
if x < 0:
print('El número',x,'es negativo')
else:
print('El número es igual a cero')
# El número es igual a cero
```
#### Mas ejemplos
```python
x = 1
if x > 0:
print('El número es positivo')
# El número es positivo
```
```python
x = -1
if x > 0:
print('El número es positivo')
```
```python
x = 1
if x % 2 == 0:
print('El número',x,'es par')
else:
print('El número',x,'es impar')
# El número 1 es impar
```
```python
x = 4
if x % 2 == 0:
print('El número',x,'es par')
else:
print('El número',x,'es impar')
# El número 4 es par
```
```python
x = 3
print('El número',x,'es par') if x % 2 == 0 else print('El número',x,'es impar')
# El número 3 es impar
```
#### Otros ejemplos de encadenado
```python
x = 1
y = 2
if x < y:
print(x,'es menor q', y)
elif x > y:
print(x,'es mayor q', y)
else:
print(x,'es igual a', y)
# 1 es menor q 2
```
```python
x = 3
if x < y:
print(x,'es menor q', y)
elif x > y:
print(x,'es mayor q', y)
else:
print(x,'es igual a', y)
# 3 es mayor q 2
```
```python
x = 2
if x < y:
print(x,'es menor q',y)
elif x > y:
print(x,'es mayor q',y)
else:
print(x,'es igual a', y)
# 2 es igual a 2
```
```python
x = 5
if x == y:
print(x,'es igual a',y)
else:
if x < y:
print(x,'es menor q',y)
else:
print(x,'es mayor q',y)
# 5 es mayor q 2
```
[1-3a_condicionales.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-3a_condicionales.py)
----
## Funciones
- **FUNCION**
Es una secuencia de sentencias que realiza una operación.
Las mismas tienen un nombre y pueden recibir o no parámetros y
devolver o no resultados.
ej.
```python
def cero():
return 0
cero() # 0
cero() + 1 # 1
c = cero()
c # 0
```
```python
def suma_uno(un_numero):
return un_numero + 1
suma_uno(3)
# 4
suma_uno(cero())
#1
def suma(a, b):
resultado = a + b
return resultado
def suma(a, b):
resultado = a + b
return resultado
def maximo_2(a, b):
"Devuelve el máximo entre a y b"
maximo = a
if b > a:
maximo = b
return maximo
def maximo_3(a, b, c):
"Devuelve el máximo enter a, b, y c"
return maximo_2(a, maximo_2(b,c))
print(maximo_2(2,5))
# 5
print(maximo_3(6, 1, 5))
# 6
```
## Parametros de función
```python
def peso(masa, gravedad=9.8):
"Fórmula del peso"
return masa * gravedad
```
#### Parametros opcionales
```python
print("Peso en la tierra:", peso(10))
# Peso en la tierra: 98.0
print("Peso en la luna:", peso(10, 1.63))
# Peso en la luna: 16.299999999999997
```
#### Parámetros con palabras claves (o argumentos nombrados)
```python
print("Peso en la luna:", peso(10, gravedad=1.63))
# Peso en la luna: 16.299999999999997
print("Peso en la luna:", peso(masa=10, gravedad=1.63))
# Peso en la luna: 16.299999999999997
print("Peso en la luna:", peso(gravedad=1.63, masa=10))
# Peso en la luna: 16.299999999999997
```
> Los parámetros posicionales **no pueden ir despues de un keyword**
> ```python
> print("Peso en la luna:", peso(masa=10, 1,63))
> # SyntaxError: positional argument follows keyword argument
> ```
### Lista de parámetros
```python
def suma_numeros(*args):
"Suma los números pasados por párametro"
return sum(args)
print("6 + 7 + 8 =", suma_numeros(*[6,7,8]))
# 6 + 7 + 8 = 21
print("6 + 7 + 8 =", suma_numeros(6,7,8))
# 6 + 7 + 8 = 21
```
### Diccionario de parámetros
```python
def imprimir_ticket(*args, **kwargs):
"Imprime el ticket de una compra"
print("Detalle Ticket")
for item, precio in kwargs.items():
print(item, ":", precio)
```
### Argumentos de función
- Distintas formas de pasar los argumentos
- Definir funciones anónimas o expresiones lambda
#### Definiendo Funcion Fibonacci (hasta limite determinado)
```python
# *def para definir la funcion
def fibo(n):
"""Muestra la serie Fibonacci hasta n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
fibo(2000)
# 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
```
- **return**:
Devuelve un valor en una función, **sin una expresión** como argumento
retorna **None**, si se alcanza el fuba de una función, también retorna **None**.
```python
f = fibo
f(1000)
# 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
print(f(0))
# None
type(f)
# <class 'function'>
```
#### Fibo 2
```python
def fibo2(n):
"""Devuelve una lista con la serie de Fibonacci hasta n."""
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
f100 = fibo2(100)
f100
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
```
#### Ejemplo de función que llama a otra
```python
def fib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a+b
return a
print(fib(35))
def fibo(n):
a = fib(n-1) + fib(n-2)
return a
print(fibo(35))
```
#### Función que recibe entrada de usuario
```python
def pedir_confirmacion(prompt, reintentos=4, msj='Intenta nuevamente'):
while True:
ok = input(prompt)
if ok in ('s', 'S', 'si', 'Si', 'SI'):
return True
if ok in ('n', 'no', 'No', 'NO'):
return False
reintentos -= 1
if reintentos < 0:
raise ValueError('Respuesta de usuario invalida')
print(msj)
```
```python
> pedir_confirmacion('¿Quieres Salir?')
> ¿Quieres Salir?no
> False
> pedir_confirmacion('Sobreescribir?', 2, 'eeey! si o no?')
> Sobreescribir?o
> eeey! si o no?
> Sobreescribir?no
> False
```
#### Levantando excepción **ValueError**
```python
> pedir_confirmacion('¿Sobreescribir?', 2)
> ¿Sobreescribir?e
> Intenta nuevamente
> ¿Sobreescribir?3
> Intenta nuevamente
> ¿Sobreescribir?3
> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 10, in pedir_confirmacion
ValueError: Respuesta de usuario invalida
```
Los valores por omisión son evaluados en el momento de la definición de la función,
en el ámbito de la definición, entonces:
```python
i = 5
def f(arg=i):
print(arg)
i = 6
f()
# 5
f(6)
# 6
f()
#5
```
El valor por omisión es evaluado solo una vez. Existe una diferencia cuando
el valor por omisión es un objeto mutable como una lista, diccionario, o
instancia de la mayoría de las clases. Por ejemplo.
La siguiente función acumula los argumentos que se le pasan en subsiguientes llamadas:
```python
def f(a, L=[]):
L.append(a)
return L
print(f(1)) #[1]
print(f(2)) #[1, 2]
print(f(3)) #[1, 2, 3]
```
Si no se quiere que el valor por omisión sea compartido entre subsiguientes
llamadas, la función se puede escribir así:
```python
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
print(f(1))
# [1]
print(f(2))
# [2]
print(f(3))
# [3]
print(f(1, [1,2,3]))
# [1, 2, 3, 1]
```
(o **argumentos nombrados**) de la forma `keyword = value`. Por ejemplo:
```python
def loro(tension, estado='muerto', accion='explotar', color='Azul Nordico'):
print("-- Este loro no va a", accion, end=' ')
print("si le aplicas", tension, "voltios.")
print("-- Hermoso plumaje", color)
print("-- Está", estado,"!")
```
- 1 argumento posicional
```python
loro(1000)
# -- Este loro no va a explotar si le aplicas 1000 voltios.
# -- Hermoso plumaje Azul Nordico
# -- Está muerto !
```
- 1 argumento nombrado
```python
loro(tension=1000)
# -- Este loro no va a explotar si le aplicas 1000 voltios.
# -- Hermoso plumaje Azul Nordico
# -- Está muerto !
```
- 2 argumentos nombrados
```python
loro(tension=1000000, accion='volar')
# -- Este loro no va a volar si le aplicas 1000000 voltios.
# -- Hermoso plumaje Azul Nordico
# -- Está muerto !
```
- 2 argumentos nombrados
```python
loro(accion='volar', tension=1000000)
# -- Este loro no va a volar si le aplicas 1000000 voltios.
# -- Hermoso plumaje Azul Nordico
# -- Está muerto !
```
- 3 args posicionales
```python
loro('un millón', 'despojado de vida', 'saltar')
# -- Este loro no va a saltar si le aplicas un millón voltios.
# -- Hermoso plumaje Azul Nordico
# -- Está despojado de vida !
```
- 1 arg. posicional y 1 nombrado.
```python
loro('mil', estado='viendo crecer las flores desde abajo')
# -- Este loro no va a explotar si le aplicas mil voltios.
# -- Hermoso plumaje Azul Nordico
# -- Está viendo crecer las flores desde abajo !
```
#### Llamadas invalidas
```python
loro()
# falta argumento obligatorio
loro(tension=5.0, 'muerto')
# argumento posicional luego de uno nombrado
loro(110, tension=220)
# valor duplicado para el mismo argumento
loro(actor='Juan Garau')
# nombre del argumento desconocido
```
Cuando un parámetro formal de la forma **nombre** está presente al final,
recibe un diccionario (ver *tipos integrados*) conteniendo todos los argumentos
nombrados excepto aquellos correspondientes a un parámetro formal.
Esto puede ser combinado con un parámetro formal de la forma **nombre**, que
recibe una **tupla** conteniendo los argumentos posicionales además de la lista de
parámetros formales. **` *nombre `** debe ocurrir antes de **` **nombre `**.
Ejemplo:
```python
def ventadequeso(tipo, *argumentos, **palabrasclave):
print("-- ¿Tiene", tipo,"?")
print("-- Lo siento, nos quedamos sin", tipo)
for arg in argumentos:
print(arg)
print("-" * 40)
for c in palabrasclave:
print(c, ":", palabrasclave[c])
```
```python
ventadequeso("Limburger", "Es muy liquido, sr.",
"Realmente es muy muy liquido, sr.",
cliente="Juan Garau",
vendedor="Miguel Paez",
puesto="Venta de Queso")
#- ¿Tiene Limburger ?
#- Lo siento, nos quedamos sin Limburger
# Es muy liquido, sr.
# Realmente es muy muy liquido, sr.
# ----------------------------------------
# cliente : Juan Garau
# vendedor : Miguel Paez
# puesto : Venta de Queso Argentino
```
#### Listas de argumentos arbitrarios
Una función puede ser llamada con un número arbitrario de argumentos.
Estos serán organizados en una tupla.
Antes del número variable de argumentos, cero o más argumentos normales
pueden estar presentes.
```python
def muchos_items(archivo, separador, *args):
archivo.write(separador.join(args))
```
Generalmente, argumentos de cantidad variable son útilmos en la lista de
parametros formales, porque toman el remanente de argumentos q se pasan a la
función.
Cualquier parametro que suceda luego del +args solo sera del tipo **nombrado**,
es decir, solo se pueden utilizar nombradros y no posicionales.
```python
concatenar("tierra", "marte", "venus")
# 'tierra/marte/venus'
concatenar("tierra", "marte", "venus", sep=" @ ")
# 'tierra @ marte @ venus'
```
#### Desempaquetando una lista de argumentos
Cuando los argumentos ya pertences a una lista o tupla, se pueden desempaquetar
para llamar una funcion que requiere argumetnoss posicionaes separados.
ej. `range()` espera los argumentos inicio y fin.
También se puede llamar a la función con el operador para desempaquetar argumentos
de una lista o tulpa **`*`**
```python
# llamada normal con argumentos separados
list(range(3, 6))
# [3, 4, 5]
# argumentos desempaquetados de la lista
args = [3, 6]
list (range(*args))
# [3, 4, 5]
```
Los **diccionarios** pueden entregar argumentos nombrados con el operador ` ** `
```python
def loro(tension, estado='rostizado', accion='apestar'):
print("-- Este loro no va a", accion, end=' ')
print("si toca", tension, "voltios.", end=' ')
print("Está", estado, "!")
d = {"tension": "cinco mil", "estado": "demacrado", "accion": "VOLAR"}
loro(**d)
# -- Este loro no va a VOLAR si toca cinco mil voltios. Está demacrado !
```
[1-3b_funciones.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-3b_funciones.py)
----
## Expresiones Lambda
Funciones anónimas, pequeñas son creadas con **lambda**.
```python
# retorna la suma de sus dos argumentos
lambda a, b: a + b
```
Las funciones Lambda pueden ser usadas en cualquier lugar donde sea requerido
un objeto de tipo función.
Están sintácticamente restringidas a una sola expresión.
Semánticamente, son solo azúcar sintáctica para definiciones normales de
funciones.
Al igual que las funciones anidadas, las funciones lambda pueden hacer
referencia a variables desde el ámbito que la contiene.
```python
def hacer_incrementador(n):
return lambda x: x + n
f = hacer_incrementador(42)
f(0)
# 42
f(1)
# 43
f(10)
# 52
```
```python
import time
f = lambda x: x + 1
print("Tipo de f:", type(f))
# Tipo de f: <class 'function'>
print("f(3)=", f(3))
# f(3)= 4
def funcioN_time(f, *args):
start_time = time.time()
result = f(*args)
end_time = time.time()
print("Tiempo de ejecución: ", end_time - start_time, "milisegundo(s)")
return result
print("f(5) =", funcioN_time(f, 5))
# Tiempo de ejecución: 2.86102294921875e-06 milisegundo(s)
f(5) = 6
```
[1-3c_expresiones_lambda.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-3c_expresiones_lambda.py)
----
## Docstrings
### Ejemplo de un **docstring multi-línea**
```python
def mi_funcion():
"""Esta funcion solo muestra documentacion.
Nada mas.
"""
pass
print(mi_funcion.__doc__)
# Esta funcion solo muestra documentacion.
#
# Nada mas.
```
**Anotación de funciones**
Se almacenan en el atributo ***__annotations__*** de la función como un
diccionario y no tienen efecto enninguna otra parte de la función.
Las anotaciones de los parámetros se definen luego de dos puntos después del
nombre del parámetro, seguido de una expresión que evalúa al valor de la
anotación.
Las anotaciones de retorno son definidas por el literal **` -> `**, seguidas
de una expresión, entre la lista de parámetros y los **` : `** que marcan el
final de la declaración **` def `**.
El siguiente ejemplo tiene **un argumento posicional, uno nombrado, y el valor
de retorno anotado**.
```python
def f(jamon: str, huevos: str = 'huevos') -> str:
print("Anotaciones:", f.__annotations__)
print("Argumentos:", jamon, huevos)
return jamon + ' y ' + huevos
f('carne')
# Anotaciones: {'jamon': <class 'str'>, 'huevos': <class 'str'>, 'return': <class 'str'>}
# Argumentos: carne huevos
# 'carne y huevos'
```
[1-3d_cadena_de_txt_de_documentacion.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-3d_cadena_de_txt_de_documentacion.py)
----
## Ejemplos print, if, for ,range, while
### print
```python
print("El número es: ", 5)
# El número es: 5
```
```python
print(1,2,3,4,5, sep=', ')
# 1, 2, 3, 4, 5
```
```python
print(1,2,3,4,5, sep='-')
# 1-2-3-4-5
```
```python
# Cambio salto de lina por end=''
print(1,2,3,4,5, sep=' - ', end='')
# 1 - 2 - 3 - 4 - 5
```
```python
print([1,2,3,4,5])
# [1, 2, 3, 4, 5]
```
### if
Consola python: `python -i`
```python
x = int(input("Ingresa un entero: "))
# Ingresa un entero: 42
x = 42
if x < 0:
x = 0
print('Negativo cambiado a cero')
elif x == 0:
print('Cero')
elif x == 1:
print('Simple')
else:
print('Más')
'Más'
```
### for
Midiendo cadenas de texto
```python
palabras = ['gato','ventana','defenestrado']
for p in palabras:
print(p, len(p))
# gato 4
# ventana 7
# defenestrado 12
for p in palabras[:]:
if len(p) > 6:
palabras.insert(0, p)
palabras
# ['defenestrado', 'ventana', 'gato', 'ventana', 'defenestrado']
```
```python
for i in range(10):
print(i, end=' ')
print('\n')
for i in 'Hola Mundo!':
print(i, end=' - ')
print('\n')
def contador(n):
c = 0
for i in range(n):
c += 1
return c
contador(10)
print(contador(10),'\n')
def sumatoria(numeros):
acum = 0
for n in numeros:
acum += n
return acum
print(sumatoria([1,2,3,4,5]), '\n')
def tabla_multip(numero):
"Imprime la tabla de multiplicar"
for indice in [1, 2, 3, 4, 5, 6, 7, 8, 9 ,10]:
print(f"{numero} * {indice} = {numero * indice}")
tabla_multip(2)
```
### range
```python
range( desde<0>, hasta<definir>, paso<1> )
<Valores por defecto>
```
```python
for x in range(10):
print(x, end=' ')
# 0 1 2 3 4 5 6 7 8 9
```
```python
for x in range(1,10):
print(x, end=' ')
# 1 2 3 4 5 6 7 8 9
```
```python
for x in range(1,10,2):
print(x, end=' ')
# 1 3 5 7 9
```
```python
for x in range(10,0,-1):
print(x, end=' ')
# 10 9 8 7 6 5 4 3 2 1
```
```python
for x in range(2):
print(i)
# 0
# 1
# 2
```
```python
range(5, 10)
# 5, 6, 7, 8, 9
```
```python
range(0, 10, 3)
# 0, 3, 6, 9
```
```python
range(-10, -100, -30)
# -10, -40, -70
```
```python
a = ['Mary','tenía','un','corderito']
for i in range(len(a)):
print(i, a[i])
# 0 Mary
# 1 tenía
# 2 un
# 3 corderito
```
#### Crear lista a partir de objeto iterable
```python
# list(enumerate())
list(range(5))
# [0, 1, 2, 3, 4]
```
### Ciclo while
```python
import time
def suma_n(n):
"Suma los números de 1 a n"
result = 0
x = n
while x > 0:
result += x
x -= 1
return result
print(suma_n(5))
```
```python
def ciclo_infinito():
"Imprime el número 1 unfinitas veces"
i = 1
while i <= 10:
print(i, end=" ")
time.sleep(.5)
#ciclo_infinito()
```
[1-4a_if_for_range_while.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4a_if_for_range_while.py)
----
## Sentencias brake, else y continue
```python
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n,'es igual a',x,'*',n/x)
break
else:
# "else" de un ciclo "for"
# Si no encuentra un factor
print(n, 'es un número primo')
# 2 es un número primo
# 3 es un número primo
# 4 es igual a 2 * 2.0
# 5 es un número primo
# 6 es igual a 2 * 3.0
# 7 es un número primo
# 8 es igual a 2 * 4.0
# 9 es igual a 3 * 3.0
```
```python
for num in range(2, 10):
if num % 2 == 0:
print("Encontré un número par", num)
# "continue" continua con la sgte. iteracion del ciclo for
continue
print("Encontré un número", num)
# Encontré un número par 2
# Encontré un número 3
# Encontré un número par 4
# Encontré un número 5
# Encontré un número par 6
# Encontré un número 7
# Encontré un número par 8
# Encontré un número 9
```
#### else, break
```python
def buscar_numero_en(numero, lista):
for i, item in enumerate(lista):
if item == numero:
indice = i
break
else:
indice = -1
return indice
print( buscar_numero_en(1, [2,3,1,4,5]))
# 2
print( buscar_numero_en(1, [2,6,3,4,5]))
# -1
```
La sentencia **pass** no hace nada, se puede usar cuando una sentencia es requerida
por la sintáxis, pero no se requiere ningúna acción, ej.
```python
# Espera hasta una interrupción de teclado [Ctrl]+[C]
while True:
pass
```
Es usada normalmente para crear **clases** en su mínima expresión
```python
class MyClaseVacia:
pass
```
Otro lugar donde se puede usar "pass" es como marca de para una función o un
cuerpo condicional (ej. en código nuevo), te permite pensar a un nivel de
abstracción mayor.
El pass se ignora silenciosamente:
```python
class initlog(*args):
pass # Recordar implementar esto!!!
```
```python
def a_function(x):
result = 0
if x > 0 and x < 5:
result = x ** 2
elif x >= 5 and x < 10:
pass
else:
result = (x ** 4) + 1
return result
print(a_function(2))
print(a_function(7))
print(a_function(12))
```
[1-4b_brake-else-continue.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4b_brake-else-continue.py)
----
## Entorno Virtual
ej. **tutorial-env**
#### Crear Entorno Virtual
```bash
python3 -m venv tutorial-env
```
#### Activar Entorno Virtual
```bash
source tutorial-env/bin/activate
```
#### Acceder a la consola de Python en el entorno virtual
```bash
(tutorial-env) python
Python 3.8.2 (default, Apr 27 2020, 15:53:34)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
import sys
sys.path
['',
'/usr/lib/python38.zip', '/usr/lib/python3.8',
'/usr/lib/python3.8/lib-dynload',
'/Coursera1/modulo4/tutorial-env/lib/python3.8/site-packages'
]
```
[1-4c_entorno_virtual.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4c_entorno_virtual.py)
----
### import
```python
import sentencia_break
sentencia_break.buscar_numero_en(1, [3,2,1,0])
# 2
```
```python
from sentencia_break import buscar_numero_en
buscar_numero_en(1, [3,5,2,1,6])
# 3
```
```python
from sentencia_break import buscar_numero_en as bn
bn(1, [5,7,9,3,9,1,0])
# 5
```
Crear archivo **` __init__.py `** en carpeta modulo4, acceder a la consola
de python un nivel mas arriba en el árbol de directorios.
```python
import modulo4
from modulo4 import sentencia_break
from modulo4.sentencia_break import buscar_numero_en as bn
bn(4,[0,1,2,3,4,5,6])
# 4
```
Python tiene una manera de poner definiciones en un archivo y usarlos en un
script o en una instancia interactiva del intérprete.
Tal archivo es llamado módulo, las definiciones de un módulo pueden ser
importadas a otros módulos o al módulo principal.
Un módulo contiene definiciones y declaraciones de Python, el nombre del
archivo es ***modulo***.py
**` __name__ `** : variable global que contiene el nombre del modulo.
Usando módulo de ejemplo creado como ***[fibo.py](#modulo-fibo)***
Consola python: `python -i`
```python
>>> import fibo
>>>
>>> fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib(100)
1 1 2 3 5 8 13 21 34 55 89
>>> fibo.__name__
'fibo'
>>> # Se puede usar un variable local asignandole la funcion
>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
Cada módulo tiene su propio espacio de nombres usado de forma global por todas
las funciones definidas en el módulo.
Se pueden modificar las variables globales de un módulo **`nombre_modulo.nombre_item`**.
Los módulos pueden importar otros módulos.
Una variante de la declaración import que importa los nombres de un módulo
directamente al espacio de nombres del módulo que hace la importación.
```python
>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
Variante para importar todos los nombres que un módulo define:
```python
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
```
La práctica de importar **` * `** de un módulo o paquete es mal vista. Ya que, frecuentemente
genera un código poco legible. Sin embargo, está bien usarlo en sesiones interactivas.
#### Recargar modulo:
```python
import importlib
importlib.reload(modulename)
```
#### Ejecutando módulos como scripts
```bash
python fibo.py <argumentos>
```
El codigo en el módulo es ejecutado como si fuese importado producto de : **`__name__ = "__main__"`**.
Si agregamos al final del modulo [fibo.py](#modulo-fibo)
```python
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
```
en terminal:
```bash
$ python fibo.py 50
1 1 2 3 5 8 13 21 34
```
Si el módulo se importa ese código no se ejecuta:
```
>>> import fibo
>>>
```
Importar módulos individuales
```python
import sound.effects.echo
# uso
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4){1}
```
Otra alternativa para importar el submódulos es:
```python
from sound.effects import echo
# uso
echo.echofilter(input, output, delay=0.7, atten=4
```
[1-4d_import_modulos_paquetes.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4d_import_modulos_paquetes.py)
----
## Modulo fibo
Modulo para obtener los números de fibonacci
***./fibo.py***
```python
def fib(n): # escribe la serie Fibonacci hasta n
a, b = 0, 1
while b < n:
print(b, end=' ')
a, b = b, a+b
print()
def fib2(n): # devuelve la serie Fibonacci hasta n
resultado = []
a, b = 0, 1
while b < n:
resultado.append(b)
a, b = b, a+b
return resultado
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
```
[fibo.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/fibo.py)
----
## Iteradores
Tipos de datos que pueden ser recorridos secuencialmente mediante el uso del ciclo for.
Los objetos iterables dében responder los mensajes: **`__iter__`** y **`__next__`**
- **` __iter__ `** : retorna un objeto iterador.
- **` __next__ `** : retorna el próximo elemento de la secuencia.
ej:
```python
lista = [1, 2, 3, 4, 5]
for elemento in lista:
print('\t ',elemento, end=' ')
# 1 2 3 4 5
```
**`for`** llama a la función **`iter()`** de la **`lista`** (objeto iterable)
y recibe un elemento definido por **`__next__`**.
Cuando no hay mas elementos __next__ levanta una excepción del tipo
**Stoplteration** que notifica al ciclo for que debe finalizar.
Conociendo el uso interno del ciclo for podemos crear iteradores propios.
**`__next__`** : debe contiener la lógica de como acceder al siguiente elemento
de la secuencia.
**`__iter__`** y **`__next__`** : y todos aquellos metodos que comienzan y
terminan con **doble guión** bajo, su proposito es ser invocado por Python
internamente, en este ejemplo por el ciclo for.
Ejemplo de un iterador que recorre elementos de una lista en sentido inverso.
```python
class Reversa:
"""
Iterador inverso.
"""
def __init__(self, datos):
self.datos = datos
self. indice = len(datos)
def __iter__(self):
return self
def __next__(self):
if self.indice == 0:
raise StopIteration()
self.indice -= 1
return self.datos[self.indice]
for elemento in Reversa([1, 2, 3, 4]):
print(elemento, end=' ')
```
`python -v`
```python
>>> lista = [1, 2, 3]
>>> it = iter(lista)
>>> it
<list_iterator object at 0x7fce335ce610>
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>>next(it)
Traceback (most recent call last):
File "/usr/lib/python3.8/code.py", line 90, in runcode
exec(code, self.locals)
File "<input>", line 1, in <module>
StopIteration
```
```python
class Iterator:
"""
Iterador, retorna elementos de
posiciones pares de una lista
"""
def __init__(self, data):
self.data = data
self.indice = 0
def __iter__(self):
return self
def __next__(self):
if self.indice >= len(self.data):
raise StopIteration()
elem = self.data[self.indice]
self.indice += 2
return elem
it = Iterator([1, 2, 3, 4, 5, 6])
for e in it:
print('\t', e)
# 1
# 3
# 5
```
[1-4e_iteradores.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4e_iteradores.py)
----
## Debugger
```python
import pdb
```
#### Breakpoint en la linea donde se requiera:
```python
pdb.set_trace()
```
#### Comandos para tomar control de la ejecución
|Comando|Detalle|
|-|-|
|h(elp)|Muestra la ayuda de todos los comandos que provee pdb.|
|s(tep)|Ejecuta la línea actual, si hay una llamada de función se mete dentro del código <br> de la función para poder seguir la ejecución de la misma.|
|n(ext)|Continúa la ejecución hastala próxima línea.|
|r(eturn)|Continúa la ejecución hasta el return de la función actual.|
|c(ontinue)|Continúa la ejecución hasta el próximo breakpoint o hasta el fin del programa.|
|l(ist)|Muestra el código del archivo actual.|
|p|Evalúa la expresión pasada como parámetro, en el contexto actual e imprime su valor.|
|q(uit)|Sale del depurador. El programa es abortado.|
### Ayuda del debugger
```
> (Pdb) h
Documented commands (type help <topic>):
========================================
EOF c d h list q rv undisplay
a cl debug help ll quit s unt
alias clear disable ignore longlist r source until
args commands display interact n restart step up
b condition down j next return tbreak w
break cont enable jump p retval u whatis
bt continue exit l pp run unalias where
Miscellaneous help topics:
==========================
exec pdb
```
ej. breakpoint **`pdb.set_trace()`**
```python
pdb.set_trace() # <-- Breakpoint
def a_function(a_number):
"""
La función recibe un número @a_number y:
Si es par:
Si es múltiplo de 10:
devuelve el número dividido en 2
Si es múltiplo de 8:
devuelve el número dividido en 4
si es otro resta 1
Si es impar:
Si es múltiplo de 3:
devuelve el número multiplicado por 11
Si es múltiplo de 7:
devuelve el número multiplicado por 23
si es otro suma 1
"""
pdb.set_trace() # <-- Breakpoint
result = None
if a_number %2 == 0:
if a_number % 10 == 0:
result = a_number / 2
elif a_number % 8 == 0:
result = a_number - 1
else:
result = a_number -1
else:
if a_number % 3 == 0:
result = a_number * 11
elif a_number % 7 == 0:
result = a_number * 23
else:
result = a_number + 1
return result
result_1 = a_function(20)
print(result_1)
print('END')
```
[1-4f_debugger.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4f_debugger.py)
----
## Ejercicios
### Actividad 1
En la consola interactiva de Python o en un script de Python,
escribir un programa para resolver el siguiente problema:
¿Cuál es el resultado de sumar los primeros 50 números pares?
(Desde el 2 inclusive hasta el 100 inclusive)
```python
def eval():
"""
Imprime la suma de los primeros 50 pares de 2 a 100
"""
var = 0
for i in range(2,101):
if i % 2 == 0:
var += i
print(var)
eval()
# 2550
```
[1-4g_actividad_evaluada.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-4g_actividad_evaluada.py)
----
### Actividad Dados
#### Requerimientos
Crear un programa que simule la tirada de dados.
Cada vez que ejecutamos el programa, éste elegirá dos números aleatorios
entre el 1 y el 6.
El programa deberá imprimirlos en pantalla, imprimir su suma y preguntarle
al usuario si quiere tirar los dados otra vez.
```python
from random import random # importe de la función random() del modulo random
def tirar_dados():
"""Retorna una lista de 3 enteros [dado1, dado2, dado1 + dado2]"""
# llamado a random.random() y se define un "rango"
dado1 = int((random() * 10) % 6 + 1)
dado2 = int((random() * 10) % 6 + 1)
suma_dados = dado1 + dado2
return [dado1, dado2, suma_dados]
# Variable usada para indicar el término de la ejecución
continuar = True
while continuar:
# Asignación de la lista retornada por la función tirar_dados()
dados = tirar_dados()
# Formateo de texto según valores en la lista dados[]
print('''
Lanzando dados!
dado 1 -> [{0}]
dado 2 -> [{1}]
---------------
TOTAL --> [{2}]
'''.format(dados[0], dados[1], dados[2]))
# Pregunta y asignación, simula un "si por defecto"
respuesta = input('¿Tirar dados nuevamente? [SI/no]: ').upper()
# Lista de posibles respuestas de usuario para finalizar el programa
if respuesta in 'NO':
# Indica el fin del ciclo while y finaliza el programa.
continuar = False
quit()
```
[1-5_evaluacion_dados.py](https://gitea.kickto.net/devfzn/Apuntes_Python/src/branch/master/01_curso/Modulo_1/1-5_evaluacion_dados.py)