Skip to content
VLSI Mentor

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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
line = "UVM_ERROR @120: crc mismatch"

print(len(line))
print(line.upper())
print(sorted(["reset", "burst", "smoke"]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

  1. Evaluate the arguments. Each expression inside the parentheses is worked out, left to right, producing values.
  2. 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.
  3. Run the body, with those names in place.
  4. Hand back the result — the value given to return, which replaces the whole call expression.
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
2

Step 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
12
[2, 1]
True

That 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.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
def ping():
    return "pong"


print(type(ping))
print(type(ping()))
print(ping())
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
<class 'function'>
<class 'str'>
pong

ping 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:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
def has_errors():
    return False


if has_errors:
    print("errors found")
else:
    print("clean")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors found

The 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.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
def has_errors():
    return False


print(bool(has_errors))
print(bool(has_errors()))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
True
False

4. 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
def ping():
    return "pong"


alias = ping
print(alias())

handlers = [ping, ping]
print(handlers[0]())

named = {"check": ping}
print(named["check"]())
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
pong
pong
pong

A 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.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
def shout(text):
    return text.upper()


print(shout("axi" + "_smoke"))
print(shout(["a", "b"][0]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
def never_mind(value):
    return "the body did not run"


print(never_mind(1 / 0))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ZeroDivisionError: division by zero

The 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:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
def count_errors(text, marker):
    return 0


count_errors("abc")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TypeError: count_errors() missing 1 required positional argument: 'marker'

Too many:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
def count_errors(text):
    return 0


count_errors("abc", "UVM_ERROR")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TypeError: count_errors() takes 1 positional argument but 2 were given

Both 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:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
count = 4210
print(count(1))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TypeError: 'int' object is not callable

That 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:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
def count(items):
    return len(items)


count = 0

print(count([1, 2, 3]))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TypeError: 'int' object is not callable

The 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
def double(n):
    return n * 2


print(double(double(3)))
print(len(sorted(["b", "a"])))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
12
2

The 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

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
A: OK <class 'function'>
B: True False
C: 6
D: x True

A — 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 callable almost 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.