0% found this document useful (0 votes)
6 views11 pages

Python Assignment

The document explains key concepts in Python programming, focusing on classes, instance methods, instance variables, closures, generators, and iterators. It describes how classes and instance methods encapsulate data and behavior, while closures provide memory retention for functions. Generators and iterators are highlighted for their efficiency in handling data, emphasizing their one-at-a-time value delivery.

Uploaded by

vincyyy6729
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views11 pages

Python Assignment

The document explains key concepts in Python programming, focusing on classes, instance methods, instance variables, closures, generators, and iterators. It describes how classes and instance methods encapsulate data and behavior, while closures provide memory retention for functions. Generators and iterators are highlighted for their efficiency in handling data, emphasizing their one-at-a-time value delivery.

Uploaded by

vincyyy6729
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1.

Creating Classes (≈330 words)

 A class is a structure that helps us create objects. It keeps related variables and functions
in one place so the code looks clean and organized.
 Classes are the base of Object-Oriented Programming (OOP). OOP is a style of coding
that treats real-world things (like students, phones, games) as objects in the program.
 To create a class we use the keyword class followed by a name. The name is written in
PascalCase (first letter capital), like Student, Laptop, BankAccount.
 The special function __init__() is called a constructor. It runs automatically when we
create an object from the class. Its job is to set initial values for the object.
 The word self refers to the current object. It acts like a remote control that lets the
method access that object’s own data.
 Classes can contain:
o Attributes → variables that store data
o Methods → functions that define behavior
 We can create multiple objects from one class. Every object gets its own separate
memory space for storing data.
 Classes make code reusable. Instead of writing the same logic again, we define it once
inside a class and use it many times.
 They also help in data abstraction, meaning we can hide complex details and show only
what’s needed.
 Classes support inheritance (one class using another class’s features), which avoids
repeating code.
 Python classes are dynamic, meaning we can add new variables to objects even after
creation.
 Example explained like story:
 class Car:
 def __init__(self, brand, model):
 [Link] = brand # attribute 1
 [Link] = model # attribute 2

 def show_details(self):
 print(f"My car is {[Link]} {[Link]}")

 c1 = Car("Tesla", "Cybertruck")
 c2 = Car("Tata", "Nexon")

 c1.show_details()
 c2.show_details()
o Here Car is the blueprint
o c1 and c2 are objects
o Both have same structure but different values
o show_details() is a method that uses object’s own data
 Without classes, the code becomes messy like noodles. With classes, it becomes neat like
mom’s tiffin box (with compartments, no food touching each other, harmony
maintained).
 Classes are used in almost every field: apps, automation, AI, games, data handling, and
backend systems.
 They help scale programs. Big systems like Instagram or Netflix don’t run on “print
statements only” — they run on structured classes behind the scenes.
 Classes improve readability, maintainability, modularity, and reduce errors.
 In short: Class = template, Object = actual thing made from template. Easy.

2. Instance Methods (≈340 words)

 Instance methods are functions written inside a class that work on the object (also called
an instance) of that class.
 They always take self as the first parameter. self is like an ID card of the object — it
tells the method which object it should work on.
 These methods can access and modify the object’s own data (instance variables).
 They help us define the behavior of an object. Example: A Student object can study(),
play(), or cry_before_viva(). These actions are written as instance methods.
 You can call instance methods only using an object, like [Link](). The class alone
cannot run them because it doesn’t know which student or which car you're talking about.
 They support encapsulation → keeping data and logic together safely inside objects.
 They make code reusable because every object can run the same method but use its own
different data.
 They can also take extra inputs apart from self, like deposit(self, amount) or
login(self, password) to perform dynamic tasks.
 Example:
 class Student:
 def __init__(self, name, marks):
 [Link] = name
 [Link] = marks

 def show(self):
 print(f"{[Link]} scored {[Link]}")

 def add_marks(self, bonus):
 [Link] += bonus
 print(f"New marks of {[Link]}: {[Link]}")

 s1 = Student("Yuv", 85)
 [Link]()
 s1.add_marks(5)
o show() and add_marks() are instance methods
o They both use s1's own data using self
o Adding bonus to s1 doesn’t affect other students
 Instance methods can also call other instance methods using self, like [Link]()
inside another method.
 They keep track of the object’s state automatically. You don’t need global variables or
external storage.
 They help make objects intelligent and independent, meaning every object controls its
own data and actions.
 They also help in polymorphism when inheritance is used — same method name can
behave differently in different classes (we’ll talk about that later when you reach “big
brain Python” level).
 They are memory friendly because they operate only on one object at a time.
 In real-life apps, instance methods are used for user actions, data updates, object
interactions, database modeling, and much more.
 Simple meaning: Instance variable = data of object. Instance method = logic that uses
or changes that data. They are best friends forever.
 Fun analogy: Class is a school, objects are students, instance methods are the rules that
each student follows in their own style. One studies sincerely, one sleeps sincerely —
same rules, different vibes.
 They make debugging easy because errors can be traced to a specific object.
 In short: Works on object → Instance method. Uses object’s own data → thanks to
self. Called by object → always. Done.

3. Instance Variables (≈330 words)

 Instance variables are the variables that belong to an object, not the class.
 They store data that is unique for each object. Meaning every object gets its own
personal copy of these variables.
 These variables are usually created inside the __init__() constructor using self, like
[Link], [Link], [Link].
 Since each object has its own data, changing the value in one object does NOT affect
any other object.
 You can access instance variables using an object: [Link]. Example:
[Link]
 They help maintain the state of an object during program execution.
 Python stores instance variables inside the object’s namespace dictionary (__dict__),
which makes them flexible and dynamic.
 You can even add instance variables outside the class after object creation. Python
allows it because it believes in freedom (sometimes too much freedom, but okay).
 Example:
 class Mobile:
 def __init__(self, brand, price):
 [Link] = brand
 [Link] = price

 m1 = Mobile("Samsung", 15000)
 m2 = Mobile("Nokia", 4000)

 [Link] = "Black" # added outside class, still instance variable
 print([Link], [Link], [Link])
 print([Link], [Link])
o Here brand, price, color are instance variables
o m2 has no color because it wasn’t added for that object
 Instance variables support data encapsulation, because they are tied safely inside
objects.
 They exist in memory as long as the object exists. When object is deleted, instance
variables vanish too.
 They make objects independent. One student can have 90 marks, another 40, and Python
won’t mix them up.
 They are super useful when working with multiple entities like users, products, sensors,
API data, etc.
 They are not shared across objects. If class variable is "school name", instance variable
is "student name". Big difference.
 Fun analogy: Class is a form, object is the filled form, and instance variables are the
answers you wrote inside it. Everyone writes different answers, same form, no cheating
possible.
 They improve code clarity and reduce errors caused by shared data.
 In real-world software, instance variables hold things like user profiles, object properties,
live data, configurations, etc.
 In short: Object-specific data = Instance variable. Stored using self = yes. Shared
between objects = never. Perfect.

4. Closures (≈345 words)

 A closure is a function inside another function that remembers variables from the
outer function, even after the outer function ends.
 This memory feature is possible because Python stores those outer variables in a hidden
box called __closure__.
 Closures help in data hiding → variables are not global, not accessible directly, but still
remembered safely by the inner function.
 They are used when we want a function to have a personal memory without creating a
whole class.
 The outer function must return the inner function, not call it. Returning is important —
calling it immediately won’t create a closure.
 A closure is created only if:
1. There is a nested function
2. The inner function uses a variable from the outer function
3. The outer function returns the inner function
 Example:
 def kitchen(secret_ingredient):
 def recipe():
 print("My secret ingredient is:", secret_ingredient)
 return recipe

 biryani = kitchen("love ❤ ") # outer function ended here
 biryani() # inner function still remembers the secret
o recipe() remembers secret_ingredient even after kitchen() finishes
 Closures are commonly used in:
o Decorators
o Callbacks
o Function factories (functions that create other customized functions)
 They keep the code clean by avoiding global variables.
 They are memory efficient when handling large programs because they only remember
needed variables, not everything.
 The remembered variable is not a copy, it is a reference. So if the variable changes later,
closure reflects the updated value.
 You can check closure memory using: functionName.__closure__
 They help maintain state retention. For example, making counters, saving configuration
values, delaying execution logic, etc.
 Closures make functions feel like humans with memories, but not like me — I forget
where I kept my socks every morning. Python remembers better.
 They allow creating powerful logic without OOP, but still feel structured.
 They also help in creating private variables because the outer function variables are not
accessible outside normally.
 Fun analogy: Closure is like giving your inner function a backpack � full of outer
variables. Even when outer function is gone, the inner one walks around confidently
with that bag and says “I remember everything”.
 In short:
o Nested function = yes
o Remembers outer variable = yes
o Outer function must return inner = must
o Used instead of global memory = smart move
5. Generators (≈330 words)

 A generator is a special type of function that gives values one at a time, instead of
dumping everything at once like a gossiping aunty.
 We create a generator using the keyword yield instead of return.
 When Python sees yield, it says: “Okay, I’ll pause here, give this value, and continue
when you ask again.”
 This pause-and-resume magic makes generators super memory-efficient, especially
when working with large data.
 Generators do NOT store all values in memory. They create them only when needed
(lazy loading, but the productive kind).
 Every generator function returns a generator object, which we can run using next() or
loops.
 Example:
 def countdown(n):
 while n > 0:
 yield n
 n -= 1

 c = countdown(5)
 print(next(c))
 print(next(c))
o Output: 5, then 4 (each call continues from where it paused)
 Generators automatically keep track of:
o Where they stopped
o What value to give next
o Their internal variables
 They raise StopIteration when all values are finished.
 We can also loop over them using for, because generators are iterable.
 for i in countdown(3):
 print(i)

Output: 3, 2, 1

 Benefits of generators:
o Use less RAM
o Work faster for big tasks
o Can handle infinite sequences (yes, infinite! like your assignments mam keeps
giving)
 You can convert generator output into a list using list(generatorObject) if you really
want all values at once.
 They are widely used in:
o File handling (reading line-by-line)
o Data streaming
o Large loops
o API data processing
o Pipelines
 Generator functions look normal but behave like they have patience. They don’t scream
all answers at once.
 Fun analogy:
List = you bring the whole water tank
Generator = you use tap and take water as you need. Same water, smarter delivery.
 Generators are one-time use. Once exhausted, you need to recreate them to use again.
 They are a core part of efficient Python coding, especially in backend and automation
tasks.
 In short:
o yield = pause + give value
o Memory = saved
o Speed = increased
o Infinite support = possible
o Assignment stress = slightly reduced (thanks to me )

6. Iterators (≈330 words)

 An iterator is an object that lets us go through values one by one, like flipping
Instagram reels — swipe, see, repeat.
 Technically, an iterator must have two special methods:
1. __iter__() → It prepares the object for iteration (like saying “I’m ready to
start”)
2. __next__() → It gives the next value each time you ask
 Iterators don’t load all values in memory at once. They only give you the next item when
called using next().
 Most built-in things you loop in Python (lists, tuples, strings, dictionaries) are iterables
— but not iterators themselves until we convert them using iter().
 Example:
 my_list = [10, 20, 30]
 it = iter(my_list) # now it becomes an iterator
 print(next(it))
 print(next(it))

Output: 10, 20

 Iterators remember their current position. So if you paused at 20, next time it will give
30.
 When values are finished, Python throws a small tantrum called StopIteration error,
meaning: “No more data bro, end of road.”
 You can also use iterators in loops:
 for i in it:
 print(i)
 Iterators are very useful when working with:
o Large data sets
o File reading
o Database records
o Streaming live data
o Situations where you don’t need random access (no jumping back, only forward)
 They are one-directional and one-time use. Once finished, you can’t restart unless you
recreate the iterator.
 You can build your own iterator by making a class that has __iter__() and __next__()
inside it.
 Custom Iterator Example:
 class Series:
 def __init__(self, max):
 [Link] = max
 [Link] = 1
 def __iter__(self):
 return self
 def __next__(self):
 if [Link] <= [Link]:
 val = [Link]
 [Link] += 1
 return val
 else:
 raise StopIteration

 s = Series(3)
 for i in s:
 print(i)

Output: 1, 2, 3

 Fun analogy:
Iterable = Playlist
Iterator = Song currently playing + Next button working
 In short:
o Has __iter__ & __next__ → yes
o Remembers position → yes
o Loads everything at once → nope
o Smart for big data → 100%
o Rewatch possible after end? → only if recreated
7. Assert (≈330 words)

 assert is a debugging tool used to check if something is true in your code.


 It tests a condition (assumption). If the condition is True, the program keeps running
normally.
 If the condition is False, Python stops the program and raises an AssertionError.
Basically Python says: “This is wrong, I refuse to continue.”
 It is mostly used while developing or testing code, not for user input validation in real
apps.
 Syntax is very simple:
 assert condition, "optional error message"
 The error message is optional but helpful. It gives a reason when the program crashes.
 Example 1 – passes silently:
 x = 5
 assert x == 5
 print("No problem here!")

Output: No crash, prints the message.

 Example 2 – fails loudly:


 y = 10
 assert y < 5, "y should be less than 5 but it's not!"

Output: AssertionError: y should be less than 5 but it's not!

 Assert helps you catch bugs early so errors don’t hide quietly in code and explode later
like a delayed firecracker.
 It makes sure the code behaves exactly as expected during development.
 When Python runs in optimized mode (-O flag), assert statements are ignored. So they
don’t affect final production performance.
 Common uses:
o Checking function output
o Making sure variables are in range
o Testing conditions in algorithms
o Writing unit test cases
o Confirming program invariants
 They are very useful when working with data processing, loops, logic-heavy code,
where silent errors are dangerous.
 Assert is like telling Python:
“I believe this is true. If it’s not… shut everything down.”
 Fun analogy:
It’s like a strict teacher checking homework:
If correct → “Okay, continue.”
If wrong → “Stop right there, explain yourself!”
 Advantages:
o Improves reliability
o Helps debugging
o Documents assumptions in code
o Lightweight and easy to use
 Limitations:
o Not a replacement for exception handling
o Should not be used to handle runtime errors
 In short:
o Condition true? → runs
o Condition false? → crash + error
o Used in testing? → yes
o Used for users? → nope
o Useful? → absolutely

8. Generator Expressions (≈335 words)

 A generator expression is a short, one-line way to create a generator (a function that


gives values one by one).
 It looks almost like list comprehension, but instead of [], we use () brackets.
 The biggest difference: it does NOT store all values in memory. It creates values only
when needed. This saves RAM and makes code faster.
 It follows the same lazy idea as generators: “I’ll give you the value when you ask, chill.”
 Syntax:
 gen = (expression for item in iterable)
 Example:
 squares = (x*x for x in range(5))
 print(next(squares))
 print(next(squares))

Output: 0, then 1
(Because 0²=0, 1²=1 — maths actually worked for once, wow)

 We can also loop through it:


 for i in squares:
 print(i)
 Generator expressions are best for:
o Large data sets
o File reading
o Pipelines
o When you don’t need indexing
o When you want speed + low memory use
 They are one-time use. Once finished, you must recreate them if you want to run again.
 They can even generate infinite sequences, because they don’t pre-store values.
 You can use them inside functions directly:
 total = sum(x for x in range(10))
 print(total)
 They are faster than lists because there is no memory allocation for storing all items.
 But remember: no indexing like gen[2]. Python will say: “I don’t have pockets to store
index.”
 Fun analogy:
List = Buffet (all food served, plate loaded)
Generator Expression = À la carte (food made only when you order)
 Advantages:
o Memory efficient
o Fast execution
o Cleaner syntax
o Great for looping
o Supports streaming
 Limitations:
o No indexing
o One-directional
o Can’t restart unless recreated
 They internally work using next() and raise StopIteration when done.
 In real-world programs, generator expressions are used to handle big tasks like log
analysis, sensor data, database rows, AI pipelines, etc.
 In short:
o () instead of [] → yes
o Memory saved → yes
o Fast loops → yes
o Indexing allowed → no
o One-time use → yes
o Useful for big data → double yes

You might also like