Lecture 2.2

First-Class Functions and Arguments

Python and Big Data in Economics

Guoliang Ma
The Chow Institute, 2026

What you will learn

“Functions are first-class objects.”

Functions are also objects.

Functions as arguments.

Functions as return values.

We’ll rely on several specific use cases to introduce these topics.

2.3 Functions are first-class objects

AoL 2 (H)

First-class objects are flexible. Being first class means there is no restrictions on the use of the object. We can pass this object as an argument to a function and can return it as a return value. We can also create dictionaries to store it, etc.

When we use a function as an argument and return values of another "higher-level" functions, we are using higher-order functions.

2.3 Functions are first-class objects

Functions as return values

def intercept_1():
    a = 1
    def slope_2(x):
        return 2 * x + a
    return slope_2


linear_trans = intercept_1()
linear_trans(3)

2.3 Functions are first-class objects

Functions as arguments

def call_count(func, x=[0]):
    print(f"calling {x[0] + 1} times")
    x[0] += 1
    func()


call_count(print)
call_count(print)
call_count(print)

2.3 Functions are first-class objects

AoL 3 (M)

In-class exercise 2.3.1

Modify code example 1, so that we can select the intercept.

Modify code example 1, so that we can also select the slope.

Modify code example 2, so that we do not need default parameters.

2.3 Functions … objects (special case III)

In the call_count example, we can pass a function as an argument to the function. But this function cannot have its own parameters. How can we pass arguments to the function being counted?

def call_count(func, arg_to_called, x=[0]):
    print(f"calling {x[0]} times")
    x[0] += 1
    func(arg_to_called)


call_count(print, "hello")
call_count(print, "python")
call_count(print, "world")

2.3 Functions … objects (special case III)

AoL 3 (M)

When we are not sure about how many parameters to pass to the function, the conventional parameter names are args and kwargs. The special syntax is *args and **kwargs; the names themselves are not keywords.

The * operator. A star is known as the (un)packing operator.

In-class exercise 2.3.2

How do they differ?

a = 1, 2, 3

a, b, c = 1, 2, 3

a, b = 1, 2, 3

a, *b, c = 1, 2, 3, 4, 5

2.3 Functions … objects (special case III)

AoL 3 (M)

In-class exercise 2.3.3

Some cases deliberately contain errors. Consider and run each assignment separately.

Summarize the pattern by considering

*a, b = 1, 2, 3, 4, 5

a, *b = 1, 2, 3, 4, 5

*a, *b = 1, 2, 3, 4, 5

*a, b, c = 1, 2, 3, 4, 5

*a, b = 1

2.3 Functions … objects (special case III)

Note that a is a list but *a unpacks the list into several elements. Passing indefinite number of arguments to a function involves two steps:

collecting positional arguments in a tuple (when defining *args)

unpacking an iterable with * when making a call

To check the unpacking behavior, we can use the sep parameter.

def call_count(func, *args, x=[0]):
    print(f"calling {x[0]} times")
    x[0] += 1
    func(*args, sep=", ")


call_count(print, "hello", "python", "world")

2.3 Functions … objects (special case III)

The ** operator.

Another type of arguments is called keyword arguments, which must be passed to a function with the form param=arg. These are named arguments. Unlike * that unpacks a list, we use ** to unpack a dictionary. There are fewer use cases than the unpacking of a list.

dict1 = {"a": 1,
         "b": 2,
         "c": 3}

dict2 = {"d": 4,
         "e": 5,
         "f": 6}

combined_dict = {**dict1, **dict2}

Argument and parameter order

Ordinary positional arguments precede keyword arguments in a call:

print("hello", "Python", sep=", ")

In the positional parameter list of a function definition, required parameters come before parameters with defaults.

Keyword-only parameters follow * or *args; **kwargs, when present, comes last.

def function(required, optional=0, *args, keyword_only, **kwargs):
    ...

2.3 Functions … objects (special case III)

AoL 3 (M)

In-class exercise 2.3.4

Note that **kwargs is actually unpacking a dict. This is to say, kwargs is a dict. We learned that a dict has keys and values. Read the document about named arguments: https://docs.python.org/3/library/stdtypes.html#dict

Write a function to take the sum of several (the numbers are unknown) named arguments. For example,

def sum_of_kwargs(???):
    pass

sum_of_kwargs(Alice=5, Bob=3, Charlie=4)