Python Part I · Module 11 · Functions
Calling a Function: Names, Parentheses and Arguments
You have been calling functions since Chapter 1.8. Every print, every len, every sorted and str and int was a call, and none of them needed explaining at the time because the pattern was obvious enough to copy. Now that you can write your own, it is worth converting that familiarity into a mechanism — what the parentheses mean, what happens to the values inside them, and in what order. The payoff is one specific mistake: leaving the parentheses off is not an error in Python, so the program keeps running with a function where a result should be, and the symptom appears somewhere else entirely.
Foundation15 min readPythonPart IFundamentalsFunctionsCalls
Part I · Module 11 · Chapter 11.3 · Calling a Function
1. You Have Been Doing This All Along
line = "UVM_ERROR @120: crc mismatch"
print(len(line))
print(line.upper())
print(sorted(["reset", "burst", "smoke"]))28
UVM_ERROR @120: CRC MISMATCH
['burst', 'reset', 'smoke']Three calls to three functions you did not write. Nothing in this chapter adds capability; it explains what those parentheses have been doing.
2. What a Call Does
count_errors(log) is four steps, in this order:
- Evaluate the arguments. Each expression inside the parentheses is worked out, left to right, producing values.
- Bind them to the parameters. The first argument becomes the first parameter name, and so on, inside a fresh set of names belonging to this call.
- Run the body, with those names in place.
- Hand back the result — the value given to
return, which replaces the whole call expression.
def count_marker(log, marker):
found = 0
for line in log:
if marker in line:
found += 1
return found
lines = ["UVM_ERROR @1: a", "UVM_INFO @2: b", "UVM_ERROR @3: c"]
total = count_marker(lines, "UVM_ERROR")
print(total)2Step 4 is the one that makes a call usable in an expression. count_marker(lines, "UVM_ERROR") does not merely do something — it is a value, 2, in the place where it was written. So it can go anywhere a value can:
def count_marker(log, marker):
found = 0
for line in log:
if marker in line:
found += 1
return found
lines = ["UVM_ERROR @1: a", "UVM_INFO @2: b", "UVM_ERROR @3: c"]
print(count_marker(lines, "UVM_ERROR") + 10)
print([count_marker(lines, "UVM_ERROR"), count_marker(lines, "UVM_INFO")])
print(count_marker(lines, "UVM_ERROR") > 1)12
[2, 1]
TrueThat is the same property Chapter 9.6 gave conditional expressions: a thing that produces a value belongs wherever a value is legal.
3. Naming Is Not Calling
The parentheses are what makes it a call. Without them you are talking about the function itself.
def ping():
return "pong"
print(type(ping))
print(type(ping()))
print(ping())<class 'function'>
<class 'str'>
pongping is a value of type function. ping() runs it and is a value of type str.
Printing ping directly shows something like <function ping at 0x7f...> — a description including a memory address, which differs on every run, so this chapter does not quote it as output. The type() above makes the same point and is stable.
Here is why the distinction matters more than it first appears. Forgetting the parentheses is not an error:
def has_errors():
return False
if has_errors:
print("errors found")
else:
print("clean")errors foundThe function returns False, and the program printed errors found.
if has_errors: tests the function object, not its result — and a function object is never empty, zero or None, so by Chapter 9.5's rule it counts as true. Always. This condition is true for every function ever written, no matter what it returns.
def has_errors():
return False
print(bool(has_errors))
print(bool(has_errors()))True
False4. A Function Is a Value, So It Can Be Passed Around
Because def binds a name to a value (Chapter 11.2, Section 3), everything you know about names applies:
def ping():
return "pong"
alias = ping
print(alias())
handlers = [ping, ping]
print(handlers[0]())
named = {"check": ping}
print(named["check"]())pong
pong
pongA function can be assigned to another name, stored in a list, or kept as a dictionary value — and called later through whichever name you reach it by. That is not a trick; it follows from a function being an ordinary value.
This is also exactly what results.sort(key=...) does in Chapter 11.14: you hand sort a function, without calling it, and sort calls it for you.
5. Arguments Are Evaluated Before the Call
Chapter 11.2 established that a definition does not run its body. The counterpart is worth being equally precise about: the arguments are not deferred at all.
def shout(text):
return text.upper()
print(shout("axi" + "_smoke"))
print(shout(["a", "b"][0]))AXI_SMOKE
A"axi" + "_smoke" was worked out to "axi_smoke" before shout began. The function never sees the expression; it sees the value.
So anything that would raise inside the parentheses raises before the body gets a chance to run:
def never_mind(value):
return "the body did not run"
print(never_mind(1 / 0))ZeroDivisionError: division by zeroThe body ignores its argument entirely and would have returned a string. It never ran, because step 1 of Section 2 failed.
6. The Wrong Number of Arguments
A call must supply exactly as many arguments as the definition has parameters. Too few:
def count_errors(text, marker):
return 0
count_errors("abc")TypeError: count_errors() missing 1 required positional argument: 'marker'Too many:
def count_errors(text):
return 0
count_errors("abc", "UVM_ERROR")TypeError: count_errors() takes 1 positional argument but 2 were givenBoth messages name the function, state the expected count and the supplied count, and the first names the specific parameter that was not filled. These are among the most informative errors in Python — read them rather than re-reading the call.
"Positional" in those messages means matched by position: first argument to first parameter, second to second. Chapter 11.5 introduces the other way of matching, and the word is there to distinguish them.
7. Calling Something That Is Not a Function
The parentheses mean call this, so applying them to a value that cannot be called is an error with a distinctive message:
count = 4210
print(count(1))TypeError: 'int' object is not callableThat message in the wild almost always means a name was reused. A function called count and a counter called count cannot coexist — the second assignment replaces the first, and every later call fails:
def count(items):
return len(items)
count = 0
print(count([1, 2, 3]))TypeError: 'int' object is not callableThe definition was fine, the call was fine, and the assignment between them destroyed the function. 'X' object is not callable is the signal to search the file for other assignments to that name.
8. A Call Inside a Call
Because a call is a value, a call can be an argument to another call:
def double(n):
return n * 2
print(double(double(3)))
print(len(sorted(["b", "a"])))12
2The inner call is evaluated first — Section 5's rule — so double(3) becomes 6 and double(6) becomes 12. Reading nested calls from the inside out is the reliable way.
This composability is why Chapter 11.8 insists on return over print: a function that prints cannot be nested like this, because it has no value to give the outer call.
9. Predict, Run, Observe
# A
def shout(t):
return t.upper()
print("A:", shout("ok"), type(shout))
# B
def flag():
return False
print("B:", bool(flag), bool(flag()))
# C
def add(a, b):
return a + b
print("C:", add(add(1, 2), 3))
# D
def pick():
return "x"
alias = pick
print("D:", alias(), pick is alias)The verified output:
A: OK <class 'function'>
B: True False
C: 6
D: x TrueA — the call produces a string; the bare name is a function.
B — bool(flag) is True because a function object is truthy; bool(flag()) is False because that is what it returns. Section 3's bug, stated as two values.
C — the inner call is evaluated first: add(1, 2) is 3, then add(3, 3) is 6.
D — the alias calls the same function, and is confirms both names refer to one object — Chapter 3.6's identity operator, on a function.
10. Exercises
Exercise 1 — name or call. For each, say whether it produces the function or its result: (a) len (b) len("ab") (c) sorted (d) print() (e) banner where banner is a function taking no arguments.
Exercise 2 — the missing parentheses. Write a function returning False and an if that tests it without parentheses. Run it, then add the parentheses. Explain the first result in two sentences using the word "truthy".
Exercise 3 — read the TypeErrors. Produce both argument-count errors deliberately and record the exact messages. For each, say what the message tells you that the line of code alone does not.
Exercise 4 — shadowed name. Define a function called total, then assign total = 0 below it, then call total([1,2]). Record the message and explain which of the three lines is actually the mistake.
Exercise 5 — evaluation order. Predict the output of print(double(1 + 2)) for double(n): return n * 2, then of print(double(1) + 2). Explain the difference in one sentence.
Exercise 6 — a function as a value. Store two functions in a dictionary under the keys "strict" and "loose", then call one of them by looking it up. Say in one sentence what the parentheses are attached to in your call.
Exercise 7 — nest the calls. Using a function clean(t) that strips whitespace and a function shout(t) that uppercases, write one expression that does both to " axi ". Then say which ran first and why.
Exercise 8 — count the steps. For report(count_errors(log), threshold), list the four steps of Section 2 in the order they happen, naming which call each step belongs to.
11. Summary
- The parentheses are the call. A bare name is the function itself; a name with parentheses runs it.
- A call is four steps: evaluate the arguments, bind them to the parameters, run the body, hand back the result.
- A call is a value, so it can appear anywhere a value is legal — in arithmetic, in a list, in a condition, or as another call's argument.
- Forgetting the parentheses raises nothing. You get the function object, which is always truthy, so a condition testing it is true every time.
- A function is an ordinary value and can be aliased, stored in a list, or kept in a dictionary and called later.
- Arguments are evaluated before the body runs. Deferral belongs to the block, never to the expressions that produce the arguments.
- Wrong argument counts give precise
TypeErrors naming the function, the expected count and the missing parameter. 'int' object is not callablealmost always means a name was reused, and the mistake is the assignment, not the call.- Nested calls are evaluated inside out.
The next chapter is about what a function should take in and what it should hand back.
Where this fits
Part of the Python curriculum.
