Por posición o por nombre
Los argumentos se pueden pasar por posición (emparejados con los parámetros en orden) o por nombre (quantity=200). Los nombres hacen legible una llamada cuando una función tiene varias entradas del mismo tipo y permiten pasar los argumentos en cualquier orden. Los argumentos posicionales van primero; una vez que usas un nombre, el resto también debe llevar nombre.
def pnl(entry, exit_price, quantity):
return (exit_price - entry) * quantity
print(pnl(184.0, 185.5, 200)) # 300.0
print(pnl(quantity=200, entry=184.0, exit_price=185.5)) # 300.0Los valores por defecto hacen opcionales los parámetros
Escribe name=value en la línea def y quien llama puede omitir ese argumento; se usa el valor por defecto. Los parámetros con valor por defecto van después de los que no lo tienen. Los valores por defecto sirven para ajustes que casi siempre son iguales, como una tarifa o un mínimo, y cualquiera puede sustituirse por su nombre.
# Parameters with a default are optional
def fee(notional, rate=0.001, minimum=1.0):
return max(minimum, notional * rate)
print(fee(36850.0)) # 36.85
print(fee(36850.0, rate=0.0005)) # 18.425
print(fee(100.0, minimum=0.5)) # 0.5Cualquier número de argumentos: *args
Un parámetro escrito *prices reúne todos los argumentos posicionales adicionales en una tupla, así que average(1, 2, 3) y average(1, 2, 3, 4, 5) funcionan. Lo contrario ocurre en la llamada: average(*quotes) desempaqueta una lista en argumentos separados.
# *prices collects the extra arguments into a tuple
def average(*prices):
return sum(prices) / len(prices)
print(average(184.0, 185.0, 186.0)) # 185.0
quotes = [184.0, 185.0]
print(average(*quotes)) # 184.5Opciones con nombre cualesquiera: **options
Del mismo modo, **options reúne los argumentos con nombre adicionales en un diccionario de nombres y valores (los diccionarios tendrán pronto su propio tema). Sirve para funciones que aceptan extras opcionales, como los ajustes de una orden. sorted(options) da los nombres en orden alfabético, de modo que la salida es predecible.
# **options collects extra named arguments into a dictionary
def describe(symbol, **options):
text = symbol
for name in sorted(options):
text += f" {name}={options[name]}"
return text
print(describe("AAPL", tif="day", limit=184.5)) # AAPL limit=184.5 tif=dayLa trampa del valor por defecto mutable
Un valor por defecto se crea una sola vez, cuando se define la función, no en cada llamada. Con un número o un texto es inofensivo. Con una lista, todas las llamadas que usan el valor por defecto comparten y cambian la misma lista. La solución habitual es usar None por defecto y crear una lista nueva dentro de la función.
# A default list is created once and shared by every call
def add_fill(fill, fills=[]):
fills.append(fill)
return fills
print(add_fill(100)) # [100]
print(add_fill(200)) # [100, 200] <- surprise: the same list
# The fix: default to None and build a new list inside
def add_fill_fixed(fill, fills=None):
if fills is None:
fills = []
fills.append(fill)
return fills
print(add_fill_fixed(100)) # [100]
print(add_fill_fixed(200)) # [200]- Usa nombres en las llamadas con varias entradas del mismo tipo.
- Valores por defecto para ajustes casi siempre iguales; nunca una lista o diccionario.
*argspara cualquier número de valores,**optionspara extras con nombre.
A continuación: ámbito y clausuras, para ver qué nombres puede ver una función y cómo puede recordar valores.
Lab: qué se califica
- Hacer opcionales la cantidad y el lado con
position_pnl25 pts - Aceptar cualquier número de precios con
average25 pts - Recibir opciones de orden con nombre mediante
describe_order25 pts - Evitar la trampa de la lista compartida con
add_fill25 pts