Syllabus
Unit 03 • 9 Class HoursTU Final Exam Core

Object-Oriented & GUI Programming

Tribhuvan University (TU MCA504) syllabus अनुसार यो युनिटले पाइथनको पूर्ण Object-Oriented Programming (OOP) आर्किटेक्चर, आधुनिक पाइथन प्याराडाइमहरू (Iterators, Generators, Decorators) र Tkinter मा आधारित डेस्कटप GUI विकासलाई समेट्छ।

परीक्षा रणनीतिक महत्त्व (Exam Weightage):TU परीक्षामा यो युनिटबाट कम्तीमा एउटा ८ वा १० नम्बरको लामो प्रश्न (जस्तै: "Explain Inheritance with MRO or demonstrate Tkinter GUI with components") र १ देखि २ वटा ४ नम्बरका संक्षिप्त प्रश्नहरू (जस्तै: "Differentiate between Iterator and Generator with code" वा "Explain Decorators with an example") अनिवार्य रूपमा सोधिन्छ।
Section 01

Classes, Objects & The `__init__` Constructor

पाइथनमा सबै कुरा (even integers, functions, and modules) वस्तु (Object) हुन्। Class भनेको कुनै पनि Object सिर्जना गर्ने लजिकल ब्लुप्रिन्ट (Blueprint) हो, र Object भनेको उक्त ब्लुप्रिन्टको मेमोरीमा अवस्थित वास्तविक उदाहरण (Instance) हो।

१. `__init__` Constructor र `self` को भूमिका

जब कुनै क्लासबाट नयाँ अब्जेक्ट बनाइन्छ (उदा. s1 = Student("Aayush", 24)), पाइथनले आन्तरिक रूपमा दुईवटा काम गर्छ:

  1. `__new__(cls)`: Memory को Heap Area मा नयाँ object को लागि space reserve गर्छ (Object Creation)।
  2. `__init__(self, ...)`: भर्खरै बनेको object का attributes initialize गर्छ (Object Initialization)।
  3. `self` Parameter: यो कुनै keyword होइन तर conventional first argument हो जसले current object को Memory Address (Current Instance Reference) लाई point गर्छ। जब तपाईं s1.display() call गर्नुहुन्छ, Python ले internally त्यसलाई Student.display(s1) मा bind गर्छ।
FIGURE 3.1: Class Blueprint vs Heap Object Instantiation & `self` BindingTU EXAM SKETCH
+-----------------------------------------------------------------------------------+
|  CLASS BLUEPRINT (Code Segment / Type Object)                                     |
|  class Student:                                                                   |
|      college = "TU IOST"  <--- [Class Attribute: Shared across all instances]    |
|      def __init__(self, name, roll):                                              |
|          self.name = name                                                         |
|          self.roll = roll                                                         |
|      def display(self): ...                                                       |
+-----------------------------------------------------------------------------------+
             |
             | Instantiation: s1 = Student("Bikash", 101)
             |                s2 = Student("Sarita", 102)
             v
+------------------------------------+      +------------------------------------+
| HEAP OBJECT 1: (id: 0x7fa12)       |      | HEAP OBJECT 2: (id: 0x7fa99)       |
| s1.__dict__ = {                    |      | s2.__dict__ = {                    |
|   "name": "Bikash",                |      |   "name": "Sarita",                |
|   "roll": 101                      |      |   "roll": 102                      |
| }                                  |      | }                                  |
| [self resolves to 0x7fa12]         |      | [self resolves to 0x7fa99]         |
+------------------------------------+      +------------------------------------+

परीक्षा टिप: परीक्षामा Class र Object को फरक सोध्दा माथिको जस्तै Heap Memory र __dict__ को रेखाचित्र कोरेर self ले सम्बन्धित instance को memory address बोक्छ भनी देखाउँदा पूर्ण अङ्क प्राप्त हुन्छ।

२. Instance Variables vs Class Variables

TU परीक्षामा पटक-पटक सोधिने प्रश्न हो: "Differentiate between class variables and instance variables with code."

class Student:
    # 1. Class Variable: Class भित्र तर कुनै method बाहिर परिभाषित
    # सबै instance ले यही shared memory साझा गर्छन्
    university_name = "Tribhuvan University"

    def __init__(self, student_name, roll_no):
        # 2. Instance Variables: self मार्फत बाँधिएका
        # प्रत्येक object को आफ्नै छुट्टै प्रतिलिपि हुन्छ
        self.name = student_name
        self.roll = roll_no

s1 = Student("Sunil", 1)
s2 = Student("Alina", 2)

print(s1.name, "|", s1.university_name) # Sunil | Tribhuvan University
print(s2.name, "|", s2.university_name) # Alina | Tribhuvan University

# Class variable परिवर्तन गर्दा सबैमा असर पर्छ:
Student.university_name = "TU Institute of Science"
print(s1.university_name) # TU Institute of Science
नेपालीमा सार: Class Variable सिंगो क्लासको लागि एउटै मात्र मेमोरीमा रहन्छ र सबै अब्जेक्टले त्यसलाई सेयर गर्छन्। Instance Variable चाहिँ प्रत्येक अब्जेक्ट (Object) को आफ्नै अलग-अलग हुन्छ जसलाई self.variable_name ले तोकिन्छ।
Section 02

Inheritance, `super()` & Method Resolution Order (MRO)

Inheritance (उत्तराधिकार) ले एउटा क्लासका गुण, विशेषता र विधिहरू अर्को क्लासमा पुनःप्रयोग (Code Reusability) गर्न अनुमति दिन्छ। पाइथनले निम्न ५ प्रकारका इनहेरिटेन्स समर्थन गर्छ:

1. Single Inheritance:Class B inherits from Class A.
2. Multilevel Inheritance:Class C inherits from B, which inherits from A.
3. Multiple Inheritance:Class C inherits directly from A and B.
4. Hierarchical Inheritance:Classes B and C inherit from base Class A.

The Diamond Problem & C3 Linearization (MRO)

जब कुनै चाइल्ड क्लासले दुईवटा त्यस्ता प्यारेन्ट क्लासहरूबाट इनहेरिट गर्छ जसको साझा मूल (Common Ancestor) हुन्छ, त्यसलाई Diamond Problem भनिन्छ। पाइथनले यो अस्पष्टता समाधान गर्न C3 Linearization Algorithm प्रयोग गर्दछ, जसलाई Method Resolution Order (MRO) भनिन्छ।

FIGURE 3.2: Diamond Inheritance & C3 MRO Traversal OrderTU HIGH-YIELD
                        +-------------------+
                        |      class A      |
                        |    def info():    |
                        +-------------------+
                               /     \
                              /       \
                             /         \
             +-------------------+   +-------------------+
             |      class B(A)   |   |      class C(A)   |
             |    def info():    |   |    def info():    |
             +-------------------+   +-------------------+
                             \         /
                              \       /
                               \     /
                        +-------------------+
                        |   class D(B, C)   |
                        +-------------------+

C3 Linearization Search Order for d = D():
1. D (Current Class)
2. B (First Parent listed in class definition)
3. C (Second Parent listed in class definition)
4. A (Common Ancestor Base)
5. object (Python root object)

Python Expression: D.mro() or D.__mro__

MRO Rule: "Children precede their parents, and multiple parents are searched in the exact left-to-right order declared in the class definition tuple."

`super()` को प्रयोग सहितको कोड उदाहरण

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        return f"I am {self.name}, aged {self.age}."

class Student(Person):
    def __init__(self, name, age, roll_no, semester):
        # super() ले Parent class को __init__ लाई कल गर्छ
        super().__init__(name, age)
        self.roll = roll_no
        self.semester = semester

    def introduce(self):
        # Method Overriding: Parent को method विस्तार गरिएको
        parent_msg = super().introduce()
        return f"{parent_msg} Roll: {self.roll}, Sem: {self.semester}"

std = Student("Pooja Sharma", 23, "MCA-05", "3rd Sem")
print(std.introduce())
# Output: I am Pooja Sharma, aged 23. Roll: MCA-05, Sem: 3rd Sem
Section 03

Abstraction (ABC) & Polymorphism

Abstraction (अमूर्तीकरण): आवश्यक फिचरहरू मात्र बाहिर देखाउने र आन्तरिक जटिलताहरू लुकाउने विधि हो। पाइथनमा Abstraction लागू गर्न abc (Abstract Base Classes) मोड्युल र @abstractmethod डेकोरेटर प्रयोग गरिन्छ।

Golden Rule of Abstract Classes: Abstract Class को सिधै Object बनाउन मिल्दैन (e.g. Shape() triggers TypeError)। यसका सबै abstract method हरू चाइल्ड क्लासले अनिवार्य रूपमा override गर्नै पर्छ।
from abc import ABC, abstractmethod
import math

class Shape(ABC):
    @abstractmethod
    def area(self):
        """सबै चाइल्ड क्लासले area() विधि परिभाषित गर्नै पर्छ"""
        pass

    @abstractmethod
    def perimeter(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return math.pi * (self.radius ** 2)

    def perimeter(self):
        return 2 * math.pi * self.radius

# c = Shape()  # TypeError: Can't instantiate abstract class Shape
c = Circle(7)
print(f"Area: {c.area():.2f}") # Area: 153.94

Polymorphism: Duck Typing & Magic Methods (Dunder)

Polymorphism (बहुरूपता): एउटै नाम भएको विधि (Method) वा अपरेटरले परिस्थिति अनुसार फरक-फरक व्यवहार गर्नु हो। पाइथनमा यसका दुई मुख्य स्वरूप छन्:

  1. Duck Typing: "If it walks like a duck and quacks like a duck, it is a duck." पाइथनले कुनै अब्जेक्ट कुन क्लासको हो भनी कडा टाइप चेकिङ गर्दैन, बरु उक्त अब्जेक्टसँग आवश्यक विधि छ कि छैन मात्र हेर्छ।
  2. Operator Overloading (Magic Methods): अपरेटरहरू (जस्तै +, -, ==) लाई हाम्रा आफ्नै क्लास अनुसार काम गराउन dunder methods (__add__, __sub__, __eq__, __str__) ओभरलोड गरिन्छ।
class Point2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # + अपरेटर ओभरलोड गर्न __add__ विधि
    def __add__(self, other):
        return Point2D(self.x + other.x, self.y + other.y)

    # print() गर्दा सुन्दर फर्म्याट दिन __str__
    def __str__(self):
        return f"Point({self.x}, {self.y})"

p1 = Point2D(3, 4)
p2 = Point2D(5, 7)
p3 = p1 + p2  # आन्तरिक रूपमा Point2D.__add__(p1, p2) कल हुन्छ
print(p3)     # Point(8, 11)
Section 04

Custom Exception Classes

पाइथनमा सबै Built-in Exceptions हरू (जस्तै ValueError, KeyError, TypeError) BaseException वा Exception क्लासका सन्तान हुन्। आफ्नो प्रोग्रामको आवश्यकता अनुसार नयाँ अपवाद बनाउन Exception क्लासलाई इनहेरिट गरिन्छ र raise किवर्डबाट फाल्न सकिन्छ।

# १. Custom Exception Class बनाउने
class InsufficientBalanceError(Exception):
    def __init__(self, balance, amount):
        super().__init__(f"रकम अपुग भयो! ब्यालेन्स रु {balance} मात्र छ, तर रु {amount} झिक्न खोजियो।")
        self.balance = balance
        self.amount = amount

# २. बिजनेस लजिकमा प्रयोग गर्ने
class BankAccount:
    def __init__(self, initial_balance):
        self.balance = initial_balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientBalanceError(self.balance, amount)
        self.balance -= amount
        return self.balance

# ३. try-except ब्लकले सुरक्षित रूपमा ह्यान्डल गर्ने
account = BankAccount(1000)
try:
    account.withdraw(2500)
except InsufficientBalanceError as err:
    print(f"[त्रुटि समातियो]: {err}")
finally:
    print("खाता विवरण सुरक्षित बन्द गरियो।")
नेपालीमा सार: सामान्य एरर (जस्तै ZeroDivisionError) बाहेक हाम्रा प्रोजेक्टमा हुने व्यावसायिक नियम उल्लंघन (जस्तै उमेर १८ भन्दा कम हुनु, बैंकमा पैसा नपुग्नु) लाई स्पष्ट देखाउन आफ्नै Custom Exception बनाइन्छ।
Section 05

Iterators & Generators (`yield` Paradigm)

TU MCA504 परीक्षाको सबैभन्दा लोकप्रिय प्रश्नमध्ये एक हो: "What is an Iterator? How does a Generator differ from an Iterator? Explain the yield statement."

१. Iterator Protocol (`__iter__` र `__next__`)

पाइथनमा कुनै पनि वस्तुलाई लुप गर्न सकिने बनाउन Iterator Protocol पूरा गर्नुपर्छ:

  • __iter__(): यसले स्वयं Iterator अब्जेक्ट फिर्ता (return) गर्छ।
  • __next__(): यसले क्रमैसँग अर्को मान दिन्छ। यदि अब कुनै मान बाँकी छैन भने यसले StopIteration एक्सेप्सन उठाउँछ (जसलाई for लुपले चुपचाप समातेर लुप अन्त्य गर्छ)।
FIGURE 3.3: Iterator vs Generator (`yield`) Execution State MachineTU FAVORITE
STANDARD FUNCTION (return):
Call func() --------> Executes logic --------> return val (Stack frame destroyed!)

GENERATOR FUNCTION (yield):
Call gen()  --------> Returns Generator Object (NO code runs yet!)
next(gen)   --------> Runs until 'yield val 1' ---> Pauses & freezes local variables
next(gen)   --------> Resumes from freeze point --> Runs until 'yield val 2'
next(gen)   --------> No more yields -----------> Raises StopIteration

MEMORY FOOTPRINT COMPARISON (10 Million Integers):
List:      [x for x in range(10_000_000)]  ===> ~85.2 Megabytes RAM (Immediate)
Generator: (x for x in range(10_000_000))  ===> ~112 Bytes RAM     (Lazy on-demand)

मुख्य भिन्नता: सामान्य फङ्सनमा return ले काम सकिएपछि फङ्सनलाई बन्द गरी मेमोरी खाली गर्छ। तर yield ले चालु अवस्था (Local variables and instruction pointer) freeze गरेर मान बाहिर पठाउँछ र अर्को next() मा त्यहीँबाट सुचारु हुन्छ।

कस्टम Iterator र Generator को कोड तुलना

# १. CUSTOM ITERATOR CLASS (Class-based Approach)
class CountdownIterator:
    def __init__(self, start):
        self.current = start

    def __iter__(self):
        return self

    def __next__(self):
        if self.current <= 0:
            raise StopIteration
        val = self.current
        self.current -= 1
        return val

# २. GENERATOR FUNCTION WITH YIELD (Function-based Approach)
def countdown_generator(start):
    while start > 0:
        yield start
        start -= 1

# दुवैको नतिजा समान हुन्छ तर Generator धेरै छरितो र सफा हुन्छ:
for n in countdown_generator(3):
    print(n, end=" ")  # Output: 3 2 1
Section 06

Decorators & Closures

Decorator भनेको कुनै पनि फङ्सनको मूल कोड (Source Code) मा परिमार्जन नगरी त्यसको कार्यक्षमता (Behavior) थप्ने वा विस्तार गर्ने उच्च-स्तरीय फङ्सन (Higher-Order Function) हो। यो Closure को सिद्धान्तमा आधारित हुन्छ।

सिन्ट्याक्सको रूपमा लेखिने @my_decorator वास्तवमा निम्न कोडको संक्षिप्त रूप (Syntactic Sugar) मात्र हो:

say_hello = my_decorator(say_hello)
FIGURE 3.4: Decorator Closure Wrapping PipelineFLOW DIAGRAM
Caller calls: greet("Ram")
      |
      v
+-----------------------------------------------------------------+
| WRAPPER FUNCTION (Outer Enclosing Scope Closure)                |
| 1. Execute PRE-HOOK: Check authentication or start timer        |
| 2. Call ORIGINAL: func(*args, **kwargs) ---> executes greet()   |
| 3. Execute POST-HOOK: Log audit or calculate execution elapsed  |
| 4. Return result                                                |
+-----------------------------------------------------------------+
      |
      v
Result returned to caller

परीक्षामुखी Decorator कोड उदाहरण (Execution Timer)

import time
import functools

def calculate_time(original_func):
    """कुनै पनि function कति सेकेन्ड चल्यो भनी नाप्ने डेकोरेटर"""
    @functools.wraps(original_func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        # मूल फङ्सन चलाउने
        result = original_func(*args, **kwargs)
        end_time = time.time()
        print(f"[{original_func.__name__}] ले {end_time - start_time:.6f} सेकेन्ड लियो।")
        return result
    return wrapper

@calculate_time
def compute_heavy_sum(n):
    return sum(i * i for i in range(n))

val = compute_heavy_sum(500000)
# Output: [compute_heavy_sum] ले 0.038412 सेकेन्ड लियो।
नेपालीमा सार: @functools.wraps(original_func) ले डेकोरेट गरिएपछि पनि मूल फङ्सनको नाम र डकुमेन्टेसन (__name__, __doc__) मेटिन दिँदैन। यो वास्तविक सफ्टवेयर र परीक्षा दुवैमा अति उत्तम अभ्यास मानिन्छ।
Section 07

GUI Programming & Tkinter Architecture

पाइथनमा डेस्कटप एप्लिकेसन निर्माणका लागि विभिन्न लाइब्रेरीहरू छन्:

  • Tkinter: पाइथनको आधिकारिक स्ट्यान्डर्ड लाइब्रेरी (Tcl/Tk को बन्धन)। MCA504 को मूल पाठ्यक्रम यही हो किनकि यो कुनै अतिरिक्त इन्स्टलेसन बिना तुरुन्त चल्छ।
  • PyQt / PySide: Qt फ्रेमवर्कमा आधारित शक्तिशाली व्यावसायिक GUI टुलकिट।
  • wxPython & Kivy: नेटिभ कम्पोनेन्ट र मोबाइल/मल्टी-टच स्क्रिनका लागि उपयोगी।

Tkinter का ३ आधार स्तम्भहरू (Core Concepts)

  1. The Root Window (`tk.Tk()`): सबै विजेटहरू अट्ने मुख्य कन्टेनर विन्डो।
  2. Geometry Managers (Layout):
    • pack(): विजेटहरूलाई ठाडो (Vertical) वा तेर्सो (Horizontal) ब्लकको रूपमा लहरै राख्छ।
    • grid(row=r, column=c): तालिका (Table/Matrix) जस्तै पङ्क्ति र स्तम्भमा व्यवस्थित गर्छ (फारम डिजाइनका लागि सर्वोत्तम)।
    • place(x=..., y=...): पिक्सेलको यकिन स्थान (Absolute Coordinates) मा राख्छ।
  3. The Event Loop (`root.mainloop()`): यो विन्डोलाई प्रयोगकर्ताका इभेन्टहरू (Button Click, Keypress, Mouse move) कुर्न अनन्त लुपमा सञ्चालन गरिरहने इन्जिन हो।
FIGURE 3.5: Tkinter Event-Driven Architecture & Widget TreeHIERARCHY & FLOW
+-------------------------------------------------------------------------+
| OS EVENT QUEUE (Mouse Clicks, Keystrokes, Window Resize)               |
+-------------------------------------------------------------------------+
                                   |
                                   v
+-------------------------------------------------------------------------+
| ROOT WINDOW: root = tk.Tk()                                             |
| Starts root.mainloop() (Infinite Non-blocking Event Dispatcher)        |
|                                                                         |
|   +-------------------------- Frame: main_frame --------------------+   |
|   |  Label(main_frame, text="Username:")                            |   |
|   |  Entry(main_frame)                                              |   |
|   |  Button(main_frame, text="Submit", command=handle_click) ------+   |
|   +-----------------------------------------------------------------+   |
+-------------------------------------------------------------------------+
                                                                     |
                                  Event Triggered: <Button-1>        |
                                                                     v
                                                    +---------------------+
                                                    | Callback Function:  |
                                                    | def handle_click()  |
                                                    +---------------------+
Section 08

Complete Tkinter Widget Showcase

TU पाठ्यक्रममा तोकिएका सबै विजेटहरू (Widgets) को भूमिका, सिन्ट्याक्स र परीक्षामा सोधिने कोड:

1. Label & 2. Button

Label ले स्क्रिनमा स्थिर टेक्स्ट वा फोटो देखाउँछ; Button ले थिच्दा command मार्फत फङ्सन चलाउँछ।

lbl = tk.Label(root, text="स्वागतम!", font=("Arial", 12), fg="gold", bg="#111")
lbl.pack(pady=5)

def on_click():
    lbl.config(text="बटन थिचियो!")

btn = tk.Button(root, text="Click Me", command=on_click, relief="raised")
btn.pack(pady=5)

3. Entry & 4. Text (Single-line vs Multi-line)

Entry एक-पङ्क्तिको इनपुट (जस्तै नाम, पासवर्ड) का लागि हो; Text धेरै हरफ भएको लामो इनपुट (जस्तै प्रतिक्रिया, बायो) का लागि हो।

# Single-line Entry
ent = tk.Entry(root, width=30)
ent.pack()
entered_text = ent.get()  # भित्रको टेक्स्ट निकाल्ने

# Multi-line Text
txt = tk.Text(root, height=4, width=30)
txt.pack()
txt_content = txt.get("1.0", tk.END)  # पङ्क्ति १ क्यारेक्टर ० देखि अन्त्यसम्म

5. Frame (Container Layout)

सम्बन्धित विजेटहरूलाई एउटा बक्स वा प्यानल भित्र समूहबद्ध गर्न Frame प्रयोग गरिन्छ।

top_frame = tk.Frame(root, padx=10, pady=10, relief="groove", borderwidth=2)
top_frame.pack(fill="x")

# अब विजेटहरू सिधै root मा होइन, top_frame भित्र राखिन्छन्:
lbl_inside = tk.Label(top_frame, text="Frame भित्रको लेबल")
lbl_inside.pack()

6. Checkbutton & 7. Radiobutton

Checkbutton ले बहु-विकल्प छनोट (Multiple Independent Selections) गर्छ; Radiobutton ले साझा variable मार्फत एउटा मात्र विकल्प (Mutually Exclusive Single Choice) छनोट गर्छ।

# Checkbutton (स्वतन्त्र छनोट)
agree_var = tk.BooleanVar()
chk = tk.Checkbutton(root, text="सर्तहरू मञ्जुर छन्", variable=agree_var)
chk.pack()

# Radiobutton (साझा variable ले गर्दा एउटा मात्र चुनिन्छ)
gender_var = tk.StringVar(value="Male")
rb1 = tk.Radiobutton(root, text="पुरुष", variable=gender_var, value="Male")
rb2 = tk.Radiobutton(root, text="महिला", variable=gender_var, value="Female")
rb1.pack()
rb2.pack()

8. Listbox (With Scrollbar Support)

धेरै विकल्पहरूको सूची देखाउन र चयन गर्न Listbox प्रयोग गरिन्छ।

lb = tk.Listbox(root, selectmode="single", height=4)
lb.pack()

courses = ["Python MCA504", "Data Structures", "Web Tech", "Database Systems"]
for c in courses:
    lb.insert(tk.END, c)

def show_selected():
    selected_index = lb.curselection()
    if selected_index:
        print("चयन गरिएको विषय:", lb.get(selected_index))

9. Menu & 10. Menubutton (Top Bar & Dropdowns)

डेस्कटप विन्डोको शीर्ष भागमा File, Edit जस्ता ड्रपडाउन मेनु बनाउन Menuroot.config(menu=menubar) प्रयोग गरिन्छ।

menubar = tk.Menu(root)
filemenu = tk.Menu(menubar, tearoff=0) # tearoff=0 ले मेनु छुट्टिन दिँदैन
filemenu.add_command(label="New Project", command=lambda: print("New"))
filemenu.add_command(label="Save", command=lambda: print("Saved"))
filemenu.add_separator()
filemenu.add_command(label="Exit", command=root.quit)

menubar.add_cascade(label="File", menu=filemenu)
root.config(menu=menubar)
Section 09

Full Model Tkinter Exam Project: Student Registration System

TU परीक्षामा प्रायः सोधिने लामो प्रयोगात्मक प्रश्न: "Write a complete Python Tkinter program to design a Student Registration Form containing Label, Entry, Radiobutton, Checkbutton, Listbox, and a Submit Button with validation."

import tkinter as tk
from tkinter import messagebox

class StudentRegistrationApp:
    def __init__(self, root):
        self.root = root
        self.root.title("TU MCA Student Registration System")
        self.root.geometry("460x540")
        self.root.resizable(False, False)

        # Main Title Header
        title = tk.Label(root, text="TU MCA Student Enrollment", font=("Helvetica", 14, "bold"), fg="#333")
        title.pack(pady=10)

        # 1. Container Form Frame
        form_frame = tk.Frame(root, padx=15, pady=10)
        form_frame.pack(fill="both", expand=True)

        # 2. Name Entry (grid layout)
        tk.Label(form_frame, text="Full Name:", font=("Arial", 10)).grid(row=0, column=0, sticky="w", pady=6)
        self.name_entry = tk.Entry(form_frame, width=28)
        self.name_entry.grid(row=0, column=1, pady=6)

        # 3. Roll Number Entry
        tk.Label(form_frame, text="Roll Number:", font=("Arial", 10)).grid(row=1, column=0, sticky="w", pady=6)
        self.roll_entry = tk.Entry(form_frame, width=28)
        self.roll_entry.grid(row=1, column=1, pady=6)

        # 4. Gender (Radiobuttons)
        tk.Label(form_frame, text="Gender:", font=("Arial", 10)).grid(row=2, column=0, sticky="w", pady=6)
        self.gender_var = tk.StringVar(value="Male")
        gender_frame = tk.Frame(form_frame)
        gender_frame.grid(row=2, column=1, sticky="w")
        tk.Radiobutton(gender_frame, text="Male", variable=self.gender_var, value="Male").pack(side="left", padx=2)
        tk.Radiobutton(gender_frame, text="Female", variable=self.gender_var, value="Female").pack(side="left", padx=2)

        # 5. Course Elective (Listbox)
        tk.Label(form_frame, text="Specialization:", font=("Arial", 10)).grid(row=3, column=0, sticky="nw", pady=6)
        self.course_listbox = tk.Listbox(form_frame, height=3, width=28, selectmode="single")
        for course in ["Data Science & ML", "Cyber Security", "Cloud Computing"]:
            self.course_listbox.insert(tk.END, course)
        self.course_listbox.selection_set(0)
        self.course_listbox.grid(row=3, column=1, pady=6)

        # 6. Terms Agreement (Checkbutton)
        self.terms_var = tk.BooleanVar()
        self.terms_chk = tk.Checkbutton(form_frame, text="I accept the TU terms and code of conduct", variable=self.terms_var)
        self.terms_chk.grid(row=4, column=0, columnspan=2, pady=10, sticky="w")

        # 7. Action Button
        self.submit_btn = tk.Button(root, text="Register Student", bg="#2e7d32", fg="white", font=("Arial", 10, "bold"), padx=10, pady=5, command=self.handle_submit)
        self.submit_btn.pack(pady=10)

    def handle_submit(self):
        name = self.name_entry.get().strip()
        roll = self.roll_entry.get().strip()
        gender = self.gender_var.get()
        terms = self.terms_var.get()

        selected_course_idx = self.course_listbox.curselection()
        course = self.course_listbox.get(selected_course_idx) if selected_course_idx else "None"

        # Validation Logic
        if not name or not roll:
            messagebox.showerror("Validation Error", "Name and Roll Number cannot be empty!")
            return

        if not terms:
            messagebox.showwarning("Terms Required", "Please accept terms and conditions.")
            return

        success_msg = f"Registration Successful!\n\nName: {name}\nRoll: {roll}\nGender: {gender}\nTrack: {course}"
        messagebox.showinfo("Success", success_msg)

if __name__ == "__main__":
    root_window = tk.Tk()
    app = StudentRegistrationApp(root_window)
    root_window.mainloop()
नेपालीमा सार: यो पूर्ण प्रोजेक्टलाई परीक्षामा लेख्दा tk.Tk(), Frame, grid(), Radiobutton, Listbox, र messagebox सबै समेटिने हुनाले ८ देखि १० नम्बरको प्रश्नमा पूरै अंक सुरक्षित हुन्छ।
Section 10 • Examination Hall Blueprint

TU Exam Q&A Bank: 10 High-Yield Model Answers

प्रत्येक उत्तरमा द्रुत रिभिजनका लागि 5-Point Quick-Grab Memory Points र परीक्षामा लामो उत्तर लेख्नका लागि Paragraph Elaboration Blueprint समावेश गरिएको छ।

Q1TU Model • Class, Object & `self` (5 Marks)

What is a class and an object in Python? Why is the `self` parameter explicitly passed in methods?

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Class as Blueprint: Class is a user-defined template; Object is a concrete allocated instance in heap memory.
  • Explicit vs Implicit: Unlike C++ or Java (`this`), Python deliberately makes `self` explicit to follow the Zen of Python ("Explicit is better than implicit").
  • Address Holder: `self` stores the memory address of the calling instance (e.g., `id(self)` matches `id(obj)`).
  • Syntactic Transformation: `obj.method(x)` is internally converted by CPython to `ClassName.method(obj, x)`.
  • Convention, Not Keyword: `self` is not a reserved Python keyword; any valid identifier can be used, but `self` is strictly universally followed.

Paragraph Blueprint for Exam: सुरुमा Class र Object को परिभाषा लेख्नुहोस् (Class = Logical Blueprint, Object = Physical Entity in Heap Memory)। त्यसपछि self किन चाहिन्छ भनी व्याख्या गर्नुहोस्। जब एउटै क्लासबाट सयौँ objects बन्छन्, कुन object को variable लाई modify गरिँदैछ भनी identify गर्न Python लाई instance को Memory Address चाहिन्छ।

उदाहरणका रूपमा देखाउनुहोस् कि emp1 = Employee("Hari") गर्दा emp1.get_name() कल हुनु भनेको पृष्ठभूमिमा Employee.get_name(emp1) कल हुनु हो। यही कारणले गर्दा method definition मा पहिलो parameter अनिवार्य रूपमा self लेख्नुपर्छ।

नेपालीमा सार: self ले "यो कुन अब्जेक्ट हो" भनेर चिनाउने काम गर्छ। s1.show() लेख्दा पाइथनले आफै Student.show(s1) बनाएर s1 लाई self मा हालिदिन्छ।
Q2TU Model • Multiple Inheritance & MRO (8 Marks)

Explain Multiple Inheritance in Python. How does Method Resolution Order (MRO) solve the Diamond Problem using the C3 Linearization Algorithm?

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Definition: Multiple inheritance occurs when a child class derives directly from more than one parent class (`class Child(ParentA, ParentB)`).
  • Diamond Problem: Ambiguity occurs when ParentA and ParentB both inherit from GrandParent and override the same method.
  • C3 Linearization: Python 2.3+ replaced depth-first search with C3 algorithm ensuring monotonicity and preserving local precedence.
  • Inspection Methods: MRO can be verified at runtime using `Child.__mro__` (tuple) or `Child.mro()` (list).
  • Traversal Order: Always searches Left-to-Right among siblings, and children are strictly visited before parents.

Paragraph Blueprint for Exam: सुरुमा Diamond Problem को रेखाचित्र (Diagram 3.2 जस्तै) कोर्नुहोस् जहाँ A बेस क्लास हो, B(A)C(A) चाइल्ड हुन्, र D(B, C) दुवैबाट इनहेरिट गर्छ।

त्यसपछि C3 Linearization का ३ नियमहरू लेख्नुहोस्: (१) Child precedes Parents (२) Multiple parents follow declaration order (Left-to-right) (३) Common base ancestors come last। अन्तमा print(D.__mro__) को आउटपुट देखाउनुहोस्: [D, B, C, A, object]

नेपालीमा सार: दुईवटा बाबु क्लासमा एउटै नामको फङ्सन भए कुन चलाउने भन्ने विवाद C3 MRO ले देब्रेबाट दायाँ (Left-to-Right) र सन्तान पहिले अनि बाबु पछि (Child first) को नियम लगाएर समाधान गर्छ।
Q3TU Model • Iterator vs Generator (6 Marks)

Differentiate between an Iterator and a Generator in Python. Explain how `yield` achieves lazy memory evaluation.

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Protocol vs Syntax: An Iterator is implemented via a Class using `__iter__()` and `__next__()`; a Generator is a function using `yield`.
  • Termination Handling: Iterators manually raise `StopIteration`; Generators raise `StopIteration` automatically upon function exit.
  • Execution Suspension: `yield` freezes local variables and instruction pointer without destroying the call stack.
  • Lazy Evaluation: Values are generated one by one on-demand in $O(1)$ space rather than pre-computed in $O(N)$ memory.
  • Boilerplate Reduction: Generators avoid writing class boilerplate with state-tracking instance variables.

Paragraph Blueprint for Exam: उत्तरलाई दुई स्तम्भको तुलना तालिका (Comparison Table) बाट सुरु गर्नुहोस्: (Implementation, Keyword used, Memory overhead, Ease of writing)।

त्यसपछि yield को आन्तरिक कार्यप्रणाली देखाउनुहोस्। सामान्य return ले stack frame नष्ट गर्छ, तर yield ले stack frame लाई heap मा generator object भित्र सुरक्षित (frozen) राख्छ र अर्को next() मा त्यहीँबाट सुचारु गर्छ।

नेपालीमा सार: Iterator बनाउन पुरै क्लास र __next__ लेख्नुपर्छ, तर Generator मा एउटा सामान्य फङ्सन भित्र yield लेखिदिए पुग्छ। यसले करोडौँ डाटा भए पनि कम्प्युटरको RAM भरिन दिँदैन।
Q4TU Model • Decorators & Closures (5 Marks)

What are decorators in Python? Explain with a practical code example how closures make decorators possible.

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • First-Class Functions: In Python, functions can be passed as arguments, assigned to variables, and returned from other functions.
  • Closure Definition: An inner function that retains access to variables in its enclosing outer scope even after the outer function has finished executing.
  • Metaprogramming Role: Decorators dynamically wrap and modify the behavior of a callable without permanently mutating its source code.
  • Syntactic Sugar: `@decorator` on line 1 is identical to `func = decorator(func)`.
  • Practical Use Cases: Authentication checks, API logging, caching/memoization, execution profiling.

Paragraph Blueprint for Exam: First-class citizen सिद्धान्तको व्याख्या गर्नुहोस्। त्यसपछि एउटा सफा डेकोरेटर कोड लेख्नुहोस् (जस्तै def my_logger(func): def wrapper(*args, **kwargs): ...)।

*args**kwargs किन प्रयोग गरिएको हो प्रस्ट्याउनुहोस् (जसले गर्दा डेकोरेटर जुनसुकै संख्याका आर्गुमेन्ट लिने फङ्सनसँग मिल्छ)। अन्तमा functools.wraps को महत्व उल्लेख गर्नुहोस्।

नेपालीमा सार: डेकोरेटर भनेको फङ्सनलाई सिँगार्ने (wrapper) फङ्सन हो। यसले पुरानो फङ्सनलाई नचलाईकन त्यसको अघि वा पछि नयाँ काम (जस्तै लग राख्ने वा टाइम नाप्ने) थपिदिन्छ।
Q5TU Model • Abstraction & ABC (5 Marks)

How is data abstraction implemented in Python using the `abc` module? What happens if a subclass fails to implement an abstract method?

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • No Native Keyword: Python lacks an `abstract` keyword; abstraction is implemented via the `abc` module.
  • Core Decorator: `@abstractmethod` decorator marks methods that derived concrete classes must override.
  • Instantiation Prevention: Python prevents instantiating any class containing at least one un-overridden abstract method.
  • TypeError Raised: Attempting instantiation raises `TypeError: Can't instantiate abstract class with abstract methods`.
  • Contract Enforcement: Ensures a rigid API contract across software frameworks and enterprise plugins.

Paragraph Blueprint for Exam: Abstraction को परिभाषा लेख्नुहोस् र पाइथनमा from abc import ABC, abstractmethod कसरी प्रयोग हुन्छ देखाउनुहोस्।

त्यसपछि Shape बेस क्लास र Rectangle चाइल्ड क्लासको उदाहरण दिनुहोस्। यदि Rectangle ले area() मेथड ओभरराइड गरेन भने TypeError आउँछ भनी एरर मेसेज स्पष्ट कोडसहित उल्लेख गर्नुहोस्।

नेपालीमा सार: Abstract Class ले एउटा नियम (Contract) बनाउँछ। त्यो क्लासबाट बन्ने सबै चाइल्ड क्लासले ती नियम (abstract methods) पालना नगरेसम्म पाइथनले ती चाइल्ड क्लासको अब्जेक्ट बन्नै दिँदैन।
Q6TU Model • Polymorphism & Operator Overloading (5 Marks)

Explain Polymorphism in Python with special reference to Operator Overloading and Magic (Dunder) methods.

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Core Meaning: Polymorphism means "many forms"—the ability of different types to respond to the same interface or operator.
  • Operator Mapping: Every Python operator maps directly to an underlying dunder method (`+` ➔ `__add__`, `*` ➔ `__mul__`, `==` ➔ `__eq__`).
  • Custom Type Extension: User-defined classes can participate natively in arithmetic expressions like integers or floats.
  • String Representation: `__str__` is intended for human-readable output (`print(obj)`); `__repr__` is for developer debugging.
  • Duck Typing Paradigm: Focuses on what an object can do (`hasattr`) rather than its explicit class hierarchy inheritance.

Paragraph Blueprint for Exam: Polymorphism का दुई पाटा लेख्नुहोस्: Method Overriding र Operator Overloading। त्यसपछि ComplexNumber वा Vector2D क्लास बनाएर __add____str__ ओभरलोड गरी देखाउनुहोस्।

जब v1 + v2 लेखिन्छ, कम्पाइलरले type(v1).__add__(v1, v2) कल गर्छ भन्ने आन्तरिक म्यापिङ व्याख्या गर्दा प्राविधिक गहिराइ झल्किन्छ।

नेपालीमा सार: + ले दुई संख्यालाई जोड्छ भने दुई शब्दलाई जोडेर एउटै बनाउँछ। हामीले आफ्नै क्लास (जस्तै Complex Number) मा __add__ लेखेर + अपरेटरलाई आफू अनुकूल काम गराउनु नै Operator Overloading हो।
Q7TU Model • Custom Exception Handling (4 Marks)

How do you define and raise a user-defined custom exception class in Python? Explain with a complete try-except-finally block.

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Inherit from Exception: Custom exception classes must subclass the built-in `Exception` (or a descendant, not `BaseException`).
  • Explicit Trigger: Custom exceptions are triggered using the `raise` keyword when a business rule fails.
  • try Block: Encloses risky code that might trigger the violation.
  • except Block: Catches the specific custom exception instance and extracts error diagnostics.
  • finally Guarantee: Always runs regardless of whether an exception was raised, handled, or uncaught (used for resource cleanups).

Paragraph Blueprint for Exam: class InvalidAgeException(Exception): pass जस्तो छोटो र स्पष्ट क्लास बनाउनुहोस्। त्यसपछि एउटा check_voter_eligibility(age) फङ्सन लेखी if age < 18: raise InvalidAgeException("Must be 18+ to vote") देखाउनुहोस्।

अन्तमा try ... except InvalidAgeException as e ... finally ब्लक लेखेर finally सधैं चल्ने कुरा उल्लेख गर्नुहोस्।

नेपालीमा सार: पाइथनको Exception क्लासलाई इनहेरिट गरेर आफ्नै एरर बनाइन्छ र नियम नमिल्दा raise गरेर फालिन्छ। यसलाई try-except ले सुरक्षित रूपमा सम्हाल्छ।
Q8TU Model • Tkinter Geometry Managers (5 Marks)

Compare the three Geometry Managers in Tkinter: `pack()`, `grid()`, and `place()`. When should you use which?

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • pack(): Linear stack manager. Packs widgets against window cavities (TOP, BOTTOM, LEFT, RIGHT). Best for simple single-column/toolbar layouts.
  • grid(): 2D tabular matrix manager. Arranges widgets into rows and columns with `sticky`, `columnspan`, and `rowspan`. Standard choice for forms.
  • place(): Coordinate-based absolute/relative manager. Positions widgets at explicit `x`, `y` pixel offsets. Prone to breaking across different screen resolutions.
  • Fatal Conflict: Never mix `pack()` and `grid()` inside the exact same parent container (causes infinite geometry recalculation deadlock).
  • Sub-framing Best Practice: Complex applications place separate Frames, using `grid()` inside individual frames and `pack()` for top-level panels.

Paragraph Blueprint for Exam: तीनवटै Geometry Manager को तुलना तालिका बनाउनुहोस् (Parameters, Positioning Mechanism, Responsiveness, Recommended Use Cases)।

सबैभन्दा महत्त्वपूर्ण प्राविधिक चेतावनी लेख्नुहोस्: एउटै विन्डो वा कन्टेनरमा pack()grid() सँगै मिसाउन पाइँदैन। फारम (Forms) र डाटा इन्ट्री स्क्रिनका लागि सधैं grid() उत्तम मानिन्छ।

नेपालीमा सार: pack() ले एकपछि अर्को चाङ लगाएर राख्छ, grid() ले रो र कोलम मिलाएर टेबल जस्तै राख्छ, र place() ले पिक्सेल नापेर राख्छ। फारम बनाउँदा सधैं grid() चलाउनुपर्छ।
Q9TU Model • Tkinter Event Handling & Bindings (5 Marks)

Explain Event Handling in Tkinter. Differentiate between widget `command` callbacks and the `bind()` method.

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Event-Driven Flow: GUI applications are idle until user interaction pushes an event to the main event loop (`mainloop`).
  • command Callback: Built directly into widgets like `Button` or `Checkbutton`; triggers on default primary action (click) and takes a parameter-less function.
  • bind() Flexibility: Universal method available on all widgets; binds arbitrary low-level events (`<Button-1>`, `<KeyPress-Return>`, `<Motion>`).
  • Event Object Injection: Handlers wired via `bind()` automatically receive an `event` object containing `event.x`, `event.y`, `event.char`, and `event.widget`.
  • Lambda Usage: Passing custom arguments to `command` callbacks requires `command=lambda: handler(arg1, arg2)`.

Paragraph Blueprint for Exam: commandbind() बीचको भिन्नता प्रस्ट पार्नुहोस्। command ले कुनै Event Object पठाउँदैन, तर bind("<Button-1>", callback) ले माउस कुन पिक्सेलमा थिचियो (event.x, event.y) भन्ने विस्तृत अब्जेक्ट पठाउँछ।

उदाहरणका लागि एउटा बटनमा क्लिक गर्दा र किबोर्डको Enter थिच्दा एउटै फङ्सन चल्ने कोड देखाउनुहोस्: root.bind("<Return>", lambda event: submit())

नेपालीमा सार: बटन थिच्दा सिधै काम गर्न command=my_func प्रयोग हुन्छ। तर किबोर्डको Enter थिच्दा वा माउसको दायाँ क्लिक गर्दा जस्ता विस्तृत काम गर्न widget.bind() प्रयोग गर्नुपर्छ।
Q10TU Model • Tkinter Menu & Menubutton (5 Marks)

How do you implement a top-level menu bar with cascading drop-down sub-menus and separators in Tkinter?

5-POINT QUICK-GRAB MEMORY ANCHORS:
  • Top-Level Container: Created via `menubar = tk.Menu(root)` and assigned to the window using `root.config(menu=menubar)`.
  • Sub-Menu Creation: Child menus are instances of `tk.Menu(menubar, tearoff=0)`.
  • tearoff=0 Parameter: Prevents the menu from being unpinned/detached into a floating separate window (standard desktop UX).
  • Cascading Attachment: Bound to the parent menubar using `menubar.add_cascade(label="File", menu=file_menu)`.
  • Separators & Commands: Items are added via `.add_command(label=..., command=...)` and grouped cleanly using `.add_separator()`.

Paragraph Blueprint for Exam: एउटा मानक डेस्कटप विन्डोको मेनुबार कोड लेख्नुहोस् जसमा File मेनु भित्र (New, Open, Save, Separator, Exit) र Help मेनु भित्र (About) राखिएको होस्।

tearoff=0 किन लेख्नुपर्छ भनी प्रस्ट्याउनुहोस् (पाइथनको Tcl/Tk ले डिफल्टमा ड्यास लाइन देखाउँछ, tearoff=0 ले यसलाई हटाएर आधुनिक लुक दिन्छ)।

नेपालीमा सार: tk.Menu(root) बनाएर root.config(menu=...) मा हालेपछि विन्डोको माथि File, Edit जस्ता मेनुहरू बन्छन्। add_cascade ले ती मेनुलाई तल ड्रपडाउन हुने बनाउँछ।