Dónde vive un nombre
El ámbito de un nombre es la parte del programa donde se puede usar. Un nombre creado dentro de una función es local: existe solo mientras esa función se ejecuta y es invisible fuera. Un nombre creado en el nivel superior del archivo es global: las funciones pueden leerlo. Cuando Python encuentra un nombre, busca primero en la función, luego en cualquier función envolvente, luego en el archivo y por último en los predefinidos.
rate = 0.001 # global: defined outside any function
def fee(notional):
minimum = 1.0 # local: exists only during the call
return max(minimum, notional * rate)
print(fee(36850.0)) # 36.85
# print(minimum) # would raise NameError: minimum is not definedAsignar crea un nombre local
Leer un global desde dentro de una función no es problema. Pero asignar a un nombre dentro de una función crea un nombre local nuevo, aunque exista un global con el mismo nombre: el global queda intacto. Eso protege tus datos, y es también la razón de que cambiar un estado global desde una función requiera palabras extra (global) que rara vez deberías necesitar. Pasa los valores como argumentos y devuelve los resultados con return.
# Assigning inside a function makes a new local name
balance = 1000
def deposit(amount):
balance = amount # a different, local balance
return balance
print(deposit(50)) # 50
print(balance) # 1000 (the global one is unchanged)Funciones que crean funciones
Una función puede definir otra dentro de sí misma y devolverla con return. La función interna conserva el acceso a las variables de la externa, incluso después de que esta termine. Ese conjunto de una función y los valores que recuerda es una clausura (closure). Es una forma limpia de construir una herramienta a partir de ajustes: una calculadora para acciones y otra para ETF.
# A closure remembers the variables of the function that made it
def make_fee_calculator(rate, minimum):
def fee(notional):
return max(minimum, notional * rate)
return fee
stock_fee = make_fee_calculator(0.001, 1.0)
etf_fee = make_fee_calculator(0.0005, 0.5)
print(stock_fee(36850.0)) # 36.85
print(etf_fee(36850.0)) # 18.425Estado que vive entre llamadas: nonlocal
Una clausura también puede cambiar lo que recuerda. Como asignar crearía un nombre local nuevo, la función interna declara antes nonlocal count: «este nombre pertenece a la función envolvente». Cada llamada de la función externa crea su propia memoria, así que dos contadores nunca interfieren. Así un generador de identificadores de órdenes o una media móvil guarda su estado sin ninguna variable global.
# nonlocal lets the inner function rebind the outer variable
def make_counter():
count = 0
def next_id():
nonlocal count
count += 1
return count
return next_id
order_ids = make_counter()
print(order_ids(), order_ids(), order_ids()) # 1 2 3
other = make_counter()
print(other()) # 1 (its own count)# State between calls: an exponential moving average
def make_ema(alpha):
value = None
def update(price):
nonlocal value
value = price if value is None else alpha * price + (1 - alpha) * value
return value
return update
ema = make_ema(0.5)
print(ema(100.0), ema(110.0), ema(110.0)) # 100.0 105.0 107.5- Dentro de una función, los nombres que asignas son locales; pasa los datos y devuélvelos con
return. - Una función que construye y devuelve una función convierte ajustes en una herramienta.
- Usa
nonlocalpara el estado que debe sobrevivir entre llamadas, una memoria por clausura.
A continuación: comprensiones de listas, para construir una lista nueva a partir de otra en una sola línea legible.
Lab: qué se califica
- Construir un contador que recuerde su cuenta con
make_counter25 pts - Empaquetar ajustes de comisión en una función con
make_fee_calculator25 pts - Mantener una media móvil entre llamadas con
make_ema25 pts - Crear una comprobación de precio a partir de un límite con
make_limit_checker25 pts