Python Series track

Week 01 · Intermediate Track

Week 1 — Advanced Functions

Go beyond basic def: write anonymous functions with lambda, understand closures, handle variable-length arguments, and use functools tools like partial and lru_cache.

Intermediate Track2 min readFree lesson

Level: Intermediate | Prerequisite: Week 9 Basics (Basic Functions)

Learning Goals

  • Accepts variable arguments with *args, **kwargs
  • Uses lambda functions
  • Utilizes higher-order functions (map, filter, sorted with key)
  • Understands the operation of closures

1. *args, **kwargs

Variable number of arguments.

def add_all(*args):           #args is a tuple
    return sum(args)

print(add_all(1, 2, 3))       # 6
print(add_all(1, 2, 3, 4, 5)) # 15

def info(**kwargs):           #kwargs is a dictionary
    for k, v in kwargs.items():
        print(f"{k}: {v}")

info(name="Hong Gil-dong", age=20)

Combinations also possible:

def f(a, b, *args, **kwargs):
    ...

2. Lambda Functions

Anonymous one-line functions. Suitable for immediate use.

square = lambda x: x * x
print(square(5))   # 25

#Usually passed as an argument to another function
nums = [1, 2, 3, 4, 5]
print(list(map(lambda x: x * 2, nums)))  # [2, 4, 6, 8, 10]

3. Higher-Order Functions

Functions that take other functions as arguments.

nums = [1, 2, 3, 4, 5]

#map: transform
print(list(map(lambda x: x * x, nums)))      # [1, 4, 9, 16, 25]

#filter: filtering
print(list(filter(lambda x: x % 2, nums)))   # [1, 3, 5]

# sorted with key
people = [("Alice", 30), ("Bob", 25), ("Charlie", 28)]
people.sort(key=lambda p: p[1])
print(people)

4. Closures

Functions defined inside another function remember outer variables.

def make_counter():
    count = 0
    def inc():
        nonlocal count    #nonlocal is needed when modifying an outer variable
        count += 1
        return count
    return inc

c = make_counter()
print(c(), c(), c())   # 1 2 3

Key Examples (examples/)

File Content
01_args_kwargs.py Variable arguments
02_lambda.py Lambda functions
03_higher_order.py map / filter / sorted
04_closure.py Closures and nonlocal

⚠️ Common Mistakes

  1. Position of *args — After regular parameters, before **kwargs.
  2. Too much logic in lambda — If it gets long, just use def. Lambdas are one line.
  3. Confusion between sorted and sort — sorted() is a new list, list.sort() modifies in place.
  4. Omitting nonlocal in closures — Using only count += 1 causes UnboundLocalError.

❓ FAQ

Q1. When should *args be used? A. When the number of arguments is not fixed. Example: print, max(1, 2, 3, ...).

Q2. Performance difference between lambda and regular functions? A. Almost none. Lambda is syntactic sugar for readability and conciseness.

Q3. Where are closures used? A. Decorators, callbacks, functions with state. A lightweight alternative to objects.

📝 Exercises (exercises/)

  • exercise1.md — stats(*nums) Mean/Variance
  • exercise2.md — Sorting student scores (sorted with key)
  • exercise3.md — make_counter call counter

Next Week

Week 2. Comprehensions and Generators — Concise repetitive expressions

Example files

The runnable files used in this lesson. Copy them into your own project and experiment.

examples/01_args_kwargs.pyPython
def add_all(*args):
    return sum(args)

print(add_all(1, 2, 3))
print(add_all(1, 2, 3, 4, 5, 6))

def info(**kwargs):
    for k, v in kwargs.items():
        print(f"{k}: {v}")

info(name="Hong Gil-dong", age=20, city="Seoul")

def log(prefix, *args, **kwargs):
    print(f"[{prefix}]", args, kwargs)

log("INFO", 1, 2, 3, user="alice", level=2)
examples/02_lambda.pyPython
square = lambda x: x * x
print(square(5))

add = lambda a, b: a + b
print(add(3, 4))

#Lambda is usually used as an argument to other functions
nums = [1, 2, 3, 4, 5]
print(list(map(lambda x: x * 2, nums)))
print(list(filter(lambda x: x > 2, nums)))
examples/03_higher_order.pyPython
nums = [1, 2, 3, 4, 5]

#map: transform all elements
squared = list(map(lambda x: x * x, nums))
print(squared)

#filter: only those that meet the condition
odds = list(filter(lambda x: x % 2, nums))
print(odds)

# sorted with key
people = [("Alice", 30), ("Bob", 25), ("Charlie", 28)]

by_age = sorted(people, key=lambda p: p[1])
print(by_age)

by_name = sorted(people, key=lambda p: p[0])
print(by_name)

#descending order
by_age_desc = sorted(people, key=lambda p: p[1], reverse=True)
print(by_age_desc)
examples/04_closure.pyPython
def make_counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

c1 = make_counter()
c2 = make_counter()  #Independent counter

print(c1(), c1(), c1())   # 1 2 3
print(c2())                #1 (separate counter)

#Function factory with closure
def multiplier(factor):
    def mul(x):
        return x * factor
    return mul

double = multiplier(2)
triple = multiplier(3)
print(double(5), triple(5))   # 10 15

Assignment

Goal

Write a function that takes variable arguments and returns the mean and variance.

Requirements

  • Function signature: def stats(*nums) -> tuple
  • Return: (Mean, Variance)
  • If there are 0 arguments, return (0, 0)

Input/Output Example

print(stats(1, 2, 3, 4, 5))   # (3.0, 2.0)
print(stats())                # (0, 0)

Assignment 2. Sort Student Scores

Goal

Sort a list of students in descending order based on their scores.

Data

students = [
    {"name": "Hong Gil-dong", "score": 85},
    {"name": "Kim Young-hee", "score": 92},
    {"name": "Lee Cheol-soo", "score": 78},
]

Requirements

  • Use sorted + key
  • Print the results (from first place)

Input/Output Example

1st place: Kim Young-hee (92 points)
2nd place: Hong Gil-dong (85 points)
3rd place: Lee Cheol-soo (78 points)

Assignment 3. Call Count Tracker

Goal

Write a closure make_counter() that accumulates the number of times a function is called.

Requirements

  • After c = make_counter(), each time c() is called, increase by 1 and return the current value
  • If you create multiple ones like c1 and c2, each is independent

Input/Output Example

c1 = make_counter()
c2 = make_counter()
print(c1())   # 1
print(c1())   # 2
print(c1())   # 3
print(c2())   # 1
print(c1())   # 4
Show the reference solution

Try the assignment yourself first — comparing your attempt with a working solution is where most of the learning happens.

solution1.pyPython
def stats(*nums):
    if not nums:
        return (0, 0)
    avg = sum(nums) / len(nums)
    var = sum((x - avg) ** 2 for x in nums) / len(nums)
    return (avg, var)

print(stats(1, 2, 3, 4, 5))
print(stats())
print(stats(10, 20, 30))
solution2.pyPython
students = [
    {"name": "Hong Gil-dong", "score": 85},
    {"name": "Kim Young-hee", "score": 92},
    {"name": "Lee Cheol-soo", "score": 78},
]

ranked = sorted(students, key=lambda s: -s["score"])
for i, s in enumerate(ranked, 1):
    print(f"{i} Rank: {s['name']} ({s['score']} points)")
solution3.pyPython
def make_counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc

c1 = make_counter()
c2 = make_counter()
print(c1(), c1(), c1())   # 1 2 3
print(c2())               # 1
print(c1())               # 4

Learn this lesson with a mentor

Work through the Python Series track on your own, or join a guided cohort at our Pitampura campus and online.

Call NowEnroll Now