Curso de Python / Usar argumentos posicionales, por nombre y predeterminados
Los argumentos de una función pueden proporcionarse por posición o por nombre, y los valores predeterminados hacen opcionales ciertas entradas. Si cada llamada debe empezar con un estado nuevo, evita utilizar una lista u otro objeto mutable como valor predeterminado.
Hacer visible el significado de los argumentos
Los argumentos posicionales se asocian con los parámetros en orden. Los argumentos por nombre se asocian con el nombre indicado. Proporcionar dos veces el mismo parámetro es un error, igual que colocar un argumento posicional ordinario después de uno por nombre.
Los parámetros situados después de un asterisco independiente * deben pasarse por nombre. En el ejemplo, escribir currency="KRW" deja visible la unidad en la llamada y evita que una tercera posición tenga un significado poco evidente.
La referencia oficial de argumentos predeterminados describe su evaluación. La recopilación y expansión de una cantidad variable de argumentos se trata en args y kwargs.
Ejecutar opciones por nombre y listas independientes
Guarda el siguiente programa como arguments.py en UTF-8. Ejecuta python arguments.py desde la carpeta de práctica con el entorno virtual seleccionado. En macOS o Ubuntu, utiliza python3 fuera del entorno si corresponde a tu instalación.
def format_expense(name, amount, *, currency="KRW"):
return f"{name}: {amount:,} {currency}"
def append_name(name, names=None):
if names is None:
names = []
names.append(name)
return names
print(format_expense("lunch", 8000))
print(format_expense(amount=9000, name="dinner", currency="KRW"))
print(append_name("A"))
print(append_name("B"))
La salida esperada es:
lunch: 8,000 KRW
dinner: 9,000 KRW
['A']
['B']
Las llamadas a append_name() producen listas separadas cuando no se proporciona el segundo argumento. La comprobación names is None crea una lista nueva únicamente en ese caso, sin sustituir una lista vacía que el usuario de la función haya pasado expresamente.
Comprender cuándo se crea el valor predeterminado
Las expresiones predeterminadas se evalúan al ejecutarse la definición de la función, no en cada llamada. Una definición que utiliza names=[] conserva esa misma lista entre llamadas. Recibir None y crear la lista dentro del cuerpo evita compartir accidentalmente ese estado.
Guarda la siguiente comparación completa en defaults.py y ejecuta python defaults.py en la misma carpeta. Las llamadas sucesivas deben hacerse en el mismo proceso para observar qué objeto persiste:
def shared(name, names=[]):
names.append(name)
return names
def fresh(name, names=None):
if names is None:
names = []
names.append(name)
return names
print(shared("A"))
print(shared("B"))
print(fresh("A"))
print(fresh("B"))
La salida esperada muestra que la primera función conserva A cuando añade B, mientras que la segunda empieza con una lista nueva:
['A']
['A', 'B']
['A']
['B']
if not names no expresa la misma condición que if names is None: también sustituiría una lista vacía proporcionada deliberadamente. Una entrada vacía puede ser válida y compartirse de forma intencionada con quien llama.
Comprobar la interfaz y el contrato de modificación
Intenta pasar currency como tercer argumento posicional y comprueba que la función exige nombrarlo. Después crea names = [] y llama a append_name("A", names): en ese caso sí se modifica la lista recibida. Cambiar un objeto pasado expresamente no es el mismo problema que reutilizar un objeto predeterminado.
Una expresión que calcula la fecha u hora actual como valor predeterminado también puede conservar el momento de la definición. Si cada llamada necesita un dato nuevo, recíbelo como None y calcúlalo dentro del cuerpo. Si None debe ser un valor válido con significado propio, elige otro marcador que represente la ausencia del argumento.
Los ámbitos, alias y objetos mutables permiten distinguir la reasignación de un nombre local de la modificación del objeto que comparte con quien llama.




