Function Arguments and Attachments in Practice

The topic sits somewhere between basic Python syntax and a subtle source of bugs that tend to surface right before a deadline. Students first encounter Ejercicios Argumentos Y Adjuntos when they are asked to pass data into functions, then later when mutations start producing unexpected side effects. The confusion is consistent. An argument is simply a value supplied to a function call. A parameter is the variable declared in the function definition that receives it. People mix these up constantly, which is fine early on, but it becomes a problem when you start reading error messages like TypeError: f() takes 2 positional arguments but 3 were given. You handed three things to a function that only accepts two. That happens more often than most people want to admit. The real distinction matters when you move past simple types. Primitives like integers, strings, and booleans are passed by value in the sense that the function receives a copy of the value. Lists, dictionaries, sets, and most custom objects behave differently. The function receives a reference to the original object. Mutating the object inside the function mutates it everywhere.

I remember working through a debugging session where a student's function was supposed to calculate a running total and return it. Instead, the function was appending to a list passed as a default argument. Every subsequent call added onto the same list from the previous call. The output looked random. It was not random. The default argument was evaluated once at function definition time, not at each call. I told them to set the default to None and create the list inside the function instead. That fixed it immediately.

Positional versus keyword arguments

Positional arguments rely entirely on order. The first parameter gets the first value, the second gets the second, and so on. This is straightforward until a function has five or six parameters, at which point you forget what position four corresponds to and start passing booleans where integers belong. Keyword arguments remove that ambiguity. You name the parameter explicitly. The call becomes self-documenting. calculate_discount(price=99.99, rate=0.15, member=True) is immediately readable. There is a rule here that beginners ignore: positional arguments must come before keyword arguments in a call. Rearranging them causes a SyntaxError, and the error message is not always obvious about which one is misplaced.

Get the Full Details

argumentos y adjuntos (2) | PDF
argumentos y adjuntos (2) | PDF

Default arguments and the mutable trap

Default arguments are convenient. They are also one of the most common sources of state leakage in Python. A default value is computed once when the function is defined, then reused on every call that omits that argument. If the default is immutable, nothing bad happens. Integers, strings, tuples, and None all behave correctly. If the default is mutable, you have a problem. A list or dictionary default will persist across calls. This is not a bug in the language. It is a feature that catches people who did not expect it. The workaround is standard and boring: use None as the default, then assign a new empty container inside the function body if the argument is None. It adds three lines. It saves hours of debugging. A quick example that illustrates the whole issue:

def add_item(item, collection=[]): collection.append(item); return collection Calling add_item(1), then add_item(2), returns [1, 2], not [1] then [2]. The same list object is reused. The fix replaces the empty list default with None and initializes inside the function.

*args and kwargs

These are the mechanisms that let a function accept an arbitrary number of positional and keyword arguments. *args collects extra positional arguments into a tuple. kwargs collects extra keyword arguments into a dictionary. They are not mysterious. They are just containers with flexible labels. They become useful when you are writing wrapper functions, decorators, or any API that needs to forward arguments to another function without knowing every parameter in advance. There is a practical rule most tutorials skip: unpack a list or dictionary into a function call using * and respectively. func(*[1, 2, 3]) is equivalent to func(1, 2, 3). This shortcut is responsible for a surprising amount of clean code.

De Argumentos y Adjuntos | PDF
De Argumentos y Adjuntos | PDF

Edge case I encountered with nested defaults

I was reviewing a codebase where a developer chained defaults. A function accepted a list as a default, and inside the function, that list was passed as a default argument to another helper function. The mutation behavior compounded. Each call mutated the outer list, which was then passed unchanged into the inner function, which appended to it again. The growth was exponential relative to the number of calls. The fix was to create fresh copies at every level using list(original) or the copy module, and to prefer explicit parameters over deep default nesting. It is better to be verbose than to debug state leakage at 2am. One pitfall that is easy to miss: keyword-only arguments. Once you place a * in the parameter list, every parameter after it must be passed by keyword. This is intentional design, not an error, but it trips up people who assume positional passing still works for everything. def func(a, *, b): ... requires func(1, b=2), not func(1, 2). Another issue is the order of parameter types. Python expects them in this sequence: positional-only, positional-or-keyword, var-positional, keyword-only, var-keyword. Mixing that order produces a SyntaxError at definition time, which is actually helpful because you catch it before running anything.

Ejercicios Argumentos Y Adjuntos

When you work through exercises on this topic, start with simple parameter passing, then introduce mutations, then add defaults with mutable values, and finally layer in *args and kwargs. That progression matches the actual difficulty curve. Skipping steps creates gaps in understanding that show up later as subtle bugs rather than obvious syntax errors. Do not treat keyword arguments as optional decoration. Using them consistently, even on simple calls, forces you to think about parameter order and makes refactoring safer. When you change a parameter name or reorder arguments in a well-keyworded codebase, the calls that use keywords do not break. Positional calls do.

What this approach cannot handle

Arguments and attachments do not solve the problem of shared mutable state across modules. If two functions in different files reference the same global list, argument passing conventions will not protect you. You need explicit data flow, immutability, or a clear ownership model. The argument system assumes you are passing data intentionally, not leaking it through global references. There is also a performance consideration. Functions with many kwargs lookups are slightly slower than functions with explicit parameters, because the interpreter has to build and search a dictionary on each call. For hot loops, this matters. For normal application code, it does not. The difference is measured in microseconds, but it accumulates. The most practical takeaway is that argument handling is mostly about clarity and predictability. Get the basics right, avoid mutable defaults, use keywords for anything beyond two parameters, and create new containers inside functions instead of reusing them from defaults. Everything else is optimization.

Argumentos y Adjuntos | PDF | Asunto (gramática) | Verbo
Argumentos y Adjuntos | PDF | Asunto (gramática) | Verbo