Functions: def, Arguments, *args, **kwargs

ফাংশন — def, আর্গুমেন্ট, *args, **kwargs

Read: ~30 min Intermediate 5 practice problems Live code runner

1. Why Functions?

A function is a named block of reusable code. Instead of writing the same logic again and again, you write it once inside a function, give it a name, and then call it whenever needed. Functions are the first and most important abstraction tool in any programming language — they let a program stay small in size while growing in capability.

Function হলো একটি নামযুক্ত পুনঃব্যবহারযোগ্য কোড ব্লক। একই logic বারবার লেখার পরিবর্তে, আপনি একবার function-এ লিখবেন, একটি নাম দেবেন, তারপর যখনই দরকার হয় সেটি call করবেন। Function হলো যেকোনো প্রোগ্রামিং ভাষার সবচেয়ে গুরুত্বপূর্ণ abstraction tool — এটি ব্যবহার করলে প্রোগ্রাম ছোট থাকে কিন্তু ক্ষমতা বাড়ে।

Python function গুলোকে first-class citizens হিসেবে ধরা হয় — এদেরকে variable-এ রাখা যায়, argument হিসেবে পাস করা যায়, এবং return করা যায়।

2. Defining a Function with def

Python-এ function লেখা হয় def keyword দিয়ে। গঠনটি অত্যন্ত সরল:

greet.py
def greet(name):
    # docstring — describes what the function does
    """Return a friendly greeting for the given name."""
    return f"Hello, {name}!"

print(greet("Arif"))
print(greet("Bangladesh"))
def keyword দিয়ে function-এর নাম ও parameter গুলো লিখুন। return statement function থেকে একটি মান ফেরত দেয়। যদি return না লেখেন, Python স্বয়ংক্রিয়ভাবে None return করে।
Anatomy of a Python Function def greet(name, greeting="Hello"): """docstring""" return f"{greeting}, {name}!" ← body is indented 4 spaces Figure 11.1 — একটি Python function-এর সব অংশ।

3. Positional vs Keyword Arguments

When you call a function, you can pass arguments by position (order matters) or by keyword (by name, order does not matter). Keyword arguments make your code much more readable.

args.py
def describe_pet(name, species, age):
    return f"{name} is a {age}-year-old {species}."

# positional — order matters
print(describe_pet("Tommy", "dog", 3))

# keyword — order does not matter, clearer at call site
print(describe_pet(species="cat", age=2, name="Mia"))

# mixed — positional first, then keyword
print(describe_pet("Ruby", age=5, species="parrot"))
Positional argument-এ order গুরুত্বপূর্ণ। Keyword argument-এ argument-এর নাম লিখে দিতে হয় — order যে কোনো হতে পারে। কোড পড়তে সহজ হয় keyword argument দিয়ে, বিশেষ করে তিনের বেশি argument থাকলে।

4. Default Arguments — এবং একটি বিখ্যাত Trap

আপনি function-এর parameter-এ default value দিতে পারেন। call করার সময় সেই argument না দিলে default-ই ব্যবহৃত হয়।

defaults.py
def power(base, exponent=2):
    return base ** exponent

print(power(5))       # 25 — default exponent=2
print(power(5, 3))    # 125
print(power(base=2, exponent=10))  # 1024
⚠️ Mutable Default Trap Never use a mutable object (list, dict, set) as a default argument. The default is evaluated once at function definition, not on every call — so the list is shared across all calls.

সতর্কতা: default argument হিসেবে list, dict বা অন্য কোনো mutable object কখনোই ব্যবহার করবেন না — এটি function define হওয়ার সময় একবার তৈরি হয় এবং সব call-এ একই object reuse হয়। পরিবর্তে None ব্যবহার করুন।
mutable_trap.py
# ❌ WRONG — shared list across calls
def bad_append(item, bag=[]):
    bag.append(item)
    return bag

print(bad_append(1))   # [1]
print(bad_append(2))   # [1, 2]  ← surprise!

# ✅ CORRECT — use None sentinel
def good_append(item, bag=None):
    if bag is None:
        bag = []
    bag.append(item)
    return bag

print(good_append(1))  # [1]
print(good_append(2))  # [2]

5. *args and **kwargs — Variable Number of Arguments

Sometimes you don't know in advance how many arguments will be passed. Python has two special syntaxes for this: *args collects extra positional arguments into a tuple, and **kwargs collects extra keyword arguments into a dict.

variadic.py
def total(*args):
    # args is a tuple of whatever was passed
    return sum(args)

print(total(1, 2, 3))             # 6
print(total(10, 20, 30, 40, 50))   # 150

def profile(**kwargs):
    # kwargs is a dict of name=value pairs
    for key, value in kwargs.items():
        print(f"{key}: {value}")

profile(name="Rafi", age=21, city="Dhaka")

# you can combine both
def describe(label, *items, **meta):
    print(f"{label}: {items}  meta={meta}")

describe("Fruits", "apple", "mango", color="mixed", count=2)
*args যেকোনো সংখ্যক positional argument একটি tuple-এ সংগ্রহ করে। **kwargs যেকোনো সংখ্যক keyword argument একটি dict-এ সংগ্রহ করে। নাম দুটি convention — চাইলে *nums বা **options লেখা যায়। তবে *args/**kwargs লিখলে সবাই সাথে সাথে বোঝে।

6. Scope — The LEGB Rule

When Python sees a name (like x), it searches four scopes in this exact order: Local → Enclosing → Global → Built-in. This is called the LEGB rule.

L — Local current function E — Enclosing (outer function) G — Global (module-level) B — Built-in (print, len, …) Figure 11.2 — LEGB lookup order.
legb.py
x = "global x"           # G

def outer():
    x = "enclosing x"    # E
    def inner():
        x = "local x"    # L
        print(x)
    inner()

outer()   # local x
print(x)  # global x
Python যখন একটি নাম খুঁজে, তখন প্রথমে current function-এর ভেতর (Local), তারপর বাইরের function (Enclosing), তারপর module-level (Global), এবং শেষে built-in names (Built-in) — এই ক্রমে খুঁজে। এটি মনে রাখুন: L-E-G-B।

7. Vocabulary (শব্দভাণ্ডার)

TermMeaningবাংলায়
ParameterA variable in the function definition.Function define করার সময় লেখা variable।
ArgumentA value passed at call time.Function call করার সময় পাস করা মান।
Return valueThe value produced by return.return statement যা দেয়।
DocstringA string literal as the first statement in a function — used as documentation.Function-এর প্রথম string literal — ডকুমেন্টেশন হিসেবে ব্যবহার হয়।
*argsPacks extra positional args into a tuple.অতিরিক্ত positional argument-গুলো tuple-এ রাখে।
**kwargsPacks extra keyword args into a dict.অতিরিক্ত keyword argument-গুলো dict-এ রাখে।
LEGBScope lookup order.Name খোঁজার ক্রম।

8. Practice Problems

প্রতিটি প্রশ্নে Show Answer চাপলে সমাধান দেখা যাবে — অনেকগুলো সরাসরি এখানেই রান করা যায়।
  1. Write a function is_even(n) that returns True if n is even.
    একটি function is_even(n) লিখুন যা n even হলে True return করবে।
    ✨ Show Answer (উত্তর দেখুন)
    ans1.py
    def is_even(n):
        return n % 2 == 0
    
    print(is_even(4))   # True
    print(is_even(7))   # False
  2. Write average(*nums) that returns the mean of any number of values.
    average(*nums) লিখুন যা যেকোনো সংখ্যক মানের গড় return করবে।
    ✨ Show Answer (উত্তর দেখুন)
    ans2.py
    def average(*nums):
        if not nums:
            return 0
        return sum(nums) / len(nums)
    
    print(average(10, 20, 30))
    print(average(5, 9, 11, 13, 17))
  3. Why is def f(x, lst=[]): considered a bug-prone pattern? Explain in 2–3 lines.
    কেন def f(x, lst=[]): লেখা bug-prone? ২–৩ লাইনে ব্যাখ্যা করুন।
    ✨ Show Answer

    The default list is evaluated once when the function is defined — it becomes a shared object across every call that does not pass lst. Any lst.append(...) persists between calls. Use lst=None and create a new list inside the body instead.

    Default list function define হওয়ার সময় একবারই তৈরি হয় এবং সব call এর মধ্যে shared থাকে। তাই lst.append পরবর্তী call-এও থেকে যায়। সমাধান: lst=None লিখে body-এর ভেতরে নতুন list তৈরি করুন।

  4. Write build_url(base, **params) that builds a query-string URL, e.g. build_url("https://api.x", q="python", page=2).
    build_url(base, **params) লিখুন যা query-string সহ একটি URL তৈরি করবে।
    ✨ Show Answer
    ans4.py
    def build_url(base, **params):
        if not params:
            return base
        query = "&".join(f"{k}={v}" for k, v in params.items())
        return f"{base}?{query}"
    
    print(build_url("https://api.x", q="python", page=2))
  5. Write a function bmi(weight_kg, height_m) and return a category: "Underweight", "Normal", "Overweight", "Obese".
    bmi(weight_kg, height_m) function লিখুন যা BMI বের করে category return করবে।
    ✨ Show Answer
    ans5.py
    def bmi(weight_kg, height_m):
        value = weight_kg / (height_m ** 2)
        if value < 18.5:
            category = "Underweight"
        elif value < 25:
            category = "Normal"
        elif value < 30:
            category = "Overweight"
        else:
            category = "Obese"
        return round(value, 1), category
    
    print(bmi(72, 1.75))

Summary — Module 11

Functions are Python's primary abstraction. You define them with def, return values with return, and call them by name. Arguments can be positional or keyword; parameters can have defaults — just avoid mutable defaults. Use *args and **kwargs for variadic calls. Name lookup follows the LEGB rule: Local, Enclosing, Global, Built-in.

Function হলো Python-এর মূল abstraction টুল। def দিয়ে define করুন, return দিয়ে মান ফেরত দিন। Argument positional বা keyword হতে পারে, default value দিতে পারেন — তবে mutable default এড়িয়ে যান। *args/**kwargs দিয়ে variadic function লিখুন। Name খোঁজার ক্রম — LEGB।

Next Module → Recursion & Lambda Expressions — self-referential thinking এবং অ্যানোনিমাস ফাংশন।