Type Hints & Static Typing

টাইপ হিন্ট ও স্ট্যাটিক টাইপিং — আধুনিক Python-এর ভিত্তি

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

1. Types as Documentation — and Safety

Python is dynamically typed: types are checked at runtime. Type hints (PEP 484) let you add optional annotations that describe what a function expects and returns. They do not affect runtime behavior — they serve as documentation, editor assistance, and input to tools like mypy, pyright, and Pylance that check correctness without running your code.

Python dynamically typed — runtime-এ type চেক হয়। Type hint (PEP 484) যোগ করে আপনি বলে দিতে পারেন কোন ফাংশন কী নেয় ও কী দেয়। এগুলো runtime-এ কিছু করে না — কাজ করে documentation ও editor assistance হিসেবে, এবং mypy-এর মতো টুল দিয়ে কোড না চালিয়েই ভুল ধরা যায়।

2. Basic Annotations

basic.py
# Function annotation
def greet(name: str, times: int = 1) -> str:
    return (f"Hi {name}! ") * times

print(greet("Ayesha", 3))

# Variable annotation
count: int = 0
message: str = "hello"
ratio: float = 3.14

# Annotations are stored in __annotations__
print(greet.__annotations__)

3. Collection & Optional Types

In Python 3.9+ you can use builtins directly: list[int], dict[str, int].

collections.py
from typing import Optional, Union

def mean(nums: list[float]) -> float:
    return sum(nums) / len(nums)

def first_or_none(items: list[str]) -> Optional[str]:
    return items[0] if items else None

def to_int(x: Union[int, str]) -> int:
    return int(x)

print(mean([3.0, 4.0, 5.0]))
print(first_or_none(["a", "b"]))
print(to_int("42"))

# Python 3.10+: X | Y instead of Union[X, Y]
def parse_id(raw: int | str) -> int:
    return int(raw)

4. dataclass — Annotations That Build Classes

dc.py
from dataclasses import dataclass

@dataclass
class Book:
    title: str
    author: str
    pages: int = 0

b = Book("Learning Python", "Lutz", 1500)
print(b)
print(b.title, b.pages)

# Comparison, __repr__, etc. are generated for you
b2 = Book("Learning Python", "Lutz", 1500)
print(b == b2)

5. Generics with TypeVar

generic.py
from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -> T:
    return items[0]

print(first([1, 2, 3]))
print(first(["a", "b", "c"]))

# T preserves the type for the type-checker:
# first([1,2,3]) is inferred as int
# first(["a"]) is inferred as str

6. Using mypy in Practice

Install with pip install mypy, then run mypy your_script.py. mypy will report any type inconsistencies without executing the code. Teams often wire mypy into CI so bad types never reach main.

Gradual typing: you do not have to annotate everything. Start at module boundaries (public functions) and add more as you go. mypy has flags like --strict for teams that want full coverage.
example.py
# mypy would flag this:
def double(x: int) -> int:
    return x * 2

print(double(5))       # fine
# print(double("abc"))  # mypy: Argument 1 to "double" has incompatible type "str"
#                       # at runtime this returns "abcabc" which is probably not what you wanted

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

TermMeaningবাংলায়
Type hint / annotationMetadata describing expected types.প্রত্যাশিত type-এর metadata।
Optional[T]T or None.T অথবা None।
Union[A, B]Either A or B.A বা B।
GenericA type parameterized by another type.অন্য type দিয়ে parameterized type।
Static type checkerTool like mypy that checks without running.mypy-র মতো tool যা কোড না চালিয়েই চেক করে।

8. Practice Problems

  1. Annotate a function add(a, b) that returns their sum.
    add(a, b) ফাংশন annotate করুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans1.py
    def add(a: int, b: int) -> int:
        return a + b
    
    print(add(3, 4))
    print(add.__annotations__)
  2. Write a function that takes a list of strings and returns the longest — using Optional.
    List of string নিয়ে সবচেয়ে লম্বাটি return করুন (খালি হলে None)।
    ✨ Show Answer (উত্তর দেখুন)
    ans2.py
    from typing import Optional
    
    def longest(words: list[str]) -> Optional[str]:
        return max(words, key=len) if words else None
    
    print(longest(["py", "python", "c"]))
    print(longest([]))
  3. Define a @dataclass called Point with fields x, y and default 0.
    Point dataclass লিখুন — x, y; default 0।
    ✨ Show Answer (উত্তর দেখুন)
    ans3.py
    from dataclasses import dataclass
    
    @dataclass
    class Point:
        x: float = 0
        y: float = 0
    
    print(Point())
    print(Point(3, 5))
  4. Write a function accepting either an int or a str and returning its string form.
    int বা str — যেকোনোটি accept করে string return করে এমন ফাংশন লিখুন।
    ✨ Show Answer (উত্তর দেখুন)
    ans4.py
    def as_str(x: int | str) -> str:
        return str(x)
    
    print(as_str(42))
    print(as_str("hi"))
  5. Explain in 2 sentences what type hints do NOT do at runtime.
    দুই বাক্যে বলুন — type hint runtime-এ কী কী করে না।
    ✨ Show Answer (উত্তর দেখুন)

    Answer: Python does not enforce type hints at runtime — passing a string to a function annotated int will not raise an error just because of the annotation. Hints are metadata; enforcement happens in external tools like mypy, in your IDE, and in your own code if you explicitly check.

    Python runtime-এ type hint প্রয়োগ করে না — int-expected ফাংশনে string দিলে annotation-এর কারণে error হবে না। Hint কেবল metadata; enforcement হয় mypy-এর মতো tool, IDE বা আপনার নিজের explicit check-এ।

Summary — Module 28

Type hints turn Python into a (optionally) typed language. They cost a few characters and give you documentation, editor completion, and bug-catching via mypy. Use Optional for nullable returns, Union or | for multiple acceptable types, generics for polymorphic code, and dataclass to build typed records without boilerplate.

Type hint Python-কে (ঐচ্ছিকভাবে) typed ভাষায় পরিণত করে। সামান্য cost-এ documentation, editor completion ও mypy-র সাহায্যে bug-catching মেলে। Optional nullable return-এ, | multi-type-এ, generic polymorphic কোডে, dataclass boilerplate কমাতে।

Next Module → Testing — unittest, pytest, doctest।