What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Putting code inside a Python function can change what its names refer to and what result reaches the caller. A function gives a block of behavior a name and a separate local scope; calling it runs the block, but printing a value is not the same as returning it. Those differences explain many surprises when code is moved into a function.
What changes when you define and call a function?
The Python tutorial states that “The keyword def introduces a function definition.” A def statement creates a function object and binds it to a name. The body does not run just because the definition is read; it runs when the function is called.
def double(number):
return number * 2
answer = double(4)
Here, double is the function name, number is a parameter, and 4 is the argument passed by the caller. The call runs the body and assigns its returned value, 8, to answer. A function can also be called from multiple places, so one implementation can replace repeated inline behavior.
Repeated code versus a function
| Approach | Duplication | Readability and reuse |
|---|---|---|
| Repeat the calculation inline | Each copy must be changed if the calculation changes. | Can be straightforward for a one-off operation, but repeated blocks make consistency harder to maintain. |
| Put the calculation in a function | Keep one implementation and call it where needed. | A meaningful name can clarify intent and makes the behavior reusable, provided the function has a clear purpose. |
A function is a structural tool, not an automatic performance improvement. For a tiny operation used once, adding a function may not make the code clearer. Its value is strongest when a named behavior is reused or gives a useful boundary to the program.
#1 Best Overall
Why does a value print but not come back?
print() displays output; return supplies a result to the code that called the function. If a function finishes without a return expression, Python returns None.
def show_total(a, b):
print(a + b)
result = show_total(2, 3) # displays 5; result is None
def calculate_total(a, b):
return a + b
result = calculate_total(2, 3) # result is 5
If another part of the program needs to store, compare, or further calculate with the result, return it. Keep printing inside the function when displaying output is itself the intended behavior. When refactoring, check whether the original statements printed a value, changed an object, or computed a value; moving them into a function does not turn those actions into a return automatically.
Rank #2
Why is my variable different inside a function?
Each function call has a local namespace. When Python looks up a name, it checks the function’s local names first, then enclosing function scopes, the module’s global namespace, and built-ins. An assignment inside a function binds a local name by default, rather than changing a caller’s variable with the same spelling.
total = 10
def set_total():
total = 20 # local to this function call
set_total()
print(total) # 10
The function’s total is local, so the module-level total remains 10. This is often a useful safety boundary: a function can use temporary names without unexpectedly rebinding names elsewhere. Python provides global and nonlocal for particular cases where assignments should bind outside the local scope, but returning a result is usually a clearer interface.
Rebinding a parameter is not the same as changing an object
Python passes arguments by assignment: a parameter becomes a local name referring to the object supplied by the caller. Rebinding that local name does not rebind the caller’s name. But if the object is mutable, an in-place change can be visible through the caller’s reference.
def rebind(items):
items = ["new"] # local name now refers to a different list
def append_item(items):
items.append("new") # changes the original list in place
values = ["old"]
rebind(values)
print(values) # ["old"]
append_item(values)
print(values) # ["old", "new"]
The first function only changes what its local parameter refers to. The second mutates the shared list object, so the caller observes the added item. If a function needs to communicate several output values, returning them together can make the interface explicit; the Python Programming FAQ describes returning a tuple as “almost always the clearest solution.”
Why can a default value persist between calls?
Python evaluates a default argument expression once, when the def statement executes—not each time the function is called. If that default is a mutable object such as a list, calls that use the default share the same object.
def add_name(name, names=[]):
names.append(name)
return names
print(add_name("Ada")) # ["Ada"]
print(add_name("Grace")) # ["Ada", "Grace"]
Use None when each call should get a fresh list, then create it inside the function:
Best Value
def add_name(name, names=None):
if names is None:
names = []
names.append(name)
return names
In this version, calls that omit names each create a new list. A caller can still pass an existing list when sharing or updating that list is intended.
How should I choose function inputs and outputs?
Parameters define the inputs a function accepts; arguments are the values supplied at a call site. Positional and keyword arguments are common ways to provide them. Python also supports positional-only and keyword-only parameters. Keyword-only parameters can help make calls clearer when a function has several optional settings.
def format_price(amount, *, currency="USD"):
return f"{currency} {amount:.2f}"
label = format_price(12, currency="CAD")
The * makes currency keyword-only, so the caller must spell out that setting. Choose names and defaults that make the intended inputs apparent; keep a function’s job and interface focused enough that a caller can understand what it does and what it returns.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Function annotations are optional metadata, not runtime type enforcement. The Python tutorial says annotations are stored in __annotations__ and otherwise do not affect the function.
What to check when a refactor changes behavior
- Names: Does an assignment now create a local variable instead of changing a name outside the function?
- Results: Does the caller need a value? If so, does the function return it, or only print it?
- Mutable objects: Is the function rebinding its parameter, or changing the passed object in place?
- Defaults: Is a mutable default being reused across calls?
- Purpose: Does the function name describe one clear behavior, and is that behavior genuinely useful to reuse or isolate?
For the language rules, see the Python Software Foundation’s Python 3.14.8 tutorial section on defining functions and its Programming FAQ entry on output parameters.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

