Create a directory with os.mkdir()

Create a directory with os.mkdir()

EasyOS Module Programs · 5 of 49

Write a Python program to create a directory with os.mkdir().

Output
True

Approach

  1. os.mkdir() creates one folder; it fails if it already exists.

Solution

Python
import os if not os.path.exists("reports"):    os.mkdir("reports")print(os.path.isdir("reports"))
Output
True

Learn the concept

New to this topic? Read the lesson, then come back.

More os module programs

← All 49 OS Module Programs

Read an environment variable

Read an environment variable

EasyOS Module Programs · 2 of 49

Write a Python program to read an environment variable.

Output
True
development

Approach

  1. os.environ.get(name, default) or os.getenv(name, default).

Solution

Python
import os print("PATH" in os.environ)print(os.getenv("APP_MODE", "development"))
Output
True
development

Line by line

Line 4

APP_MODE is not set, so the default is returned instead of an error.

Learn the concept

New to this topic? Read the lesson, then come back.

More os module programs

← All 49 OS Module Programs

List environment variables

List environment variables

EasyOS Module Programs · 4 of 49

Write a Python program to get the list of environment variables with os.environ.

Output
True
True

Approach

  1. os.environ behaves like a dictionary.

Solution

Python
import os names = sorted(os.environ)print(len(names) > 0)print("PATH" in names)for name in names[:0]:    print(name, "=", os.environ[name])
Output
True
True

Line by line

Line 3

sorted() of the mapping gives the variable names.

Watch out

The loop is limited to [:0] here on purpose: environment values often contain paths, user names and secrets, so print them only on your own machine.

Learn the concept

New to this topic? Read the lesson, then come back.

More os module programs

← All 49 OS Module Programs

Set an environment variable

Set an environment variable

EasyOS Module Programs · 3 of 49

Write a Python program to set an environment variable for the current process.

Output
testing
child sees: testing

Approach

  1. Assign to os.environ; child processes inherit it.

Solution

Python
import osimport subprocessimport sys os.environ["APP_MODE"] = "testing"print(os.environ["APP_MODE"])child = subprocess.run([sys.executable, "-c", "import os; print(os.environ['APP_MODE'])"],                       capture_output=True, text=True)print("child sees:", child.stdout.strip())
Output
testing
child sees: testing

Line by line

Line 5

The value lives only in this process and the processes it starts; it does not change system settings.

Learn the concept

New to this topic? Read the lesson, then come back.

More os module programs

← All 49 OS Module Programs

Get the current working directory

Get the current working directory

EasyOS Module Programs · 1 of 49

Write a Python program to get the current working directory.

Output
1
True

Approach

  1. os.getcwd() returns the folder the program runs in.

Solution

Python
import os cwd = os.getcwd()print(os.path.basename(cwd))print(os.path.isabs(cwd))
Output
1
True

Line by line

Line 3

The full path depends on your computer, so the example prints only the last folder name.

Line 5

getcwd() always returns an absolute path.

Learn the concept

New to this topic? Read the lesson, then come back.

More os module programs

← All 49 OS Module Programs

Python RegEx

Python Tutorial › Modules › RegEx

Python RegEx

IntermediateLesson 40 of 4714 min read12 runnable examples

A regular expression (regex) is a small pattern language for finding and extracting text: every email address in a page, every number in a log, every date in a report. Python’s re module runs these patterns for you.

In this lesson
  • search, match, fullmatch, findall and sub
  • Character classes and quantifiers
  • Capture groups and named groups
  • Flags and compiled patterns

Your first regex

Write patterns as raw strings (r"...") so backslashes reach the regex engine unchanged.

Python
import re text = "Order 4521 shipped on 2026-11-02, order 4522 pending"match = re.search(r"\d+", text)      # first run of digitsprint(match.group(), match.start(), match.end()) print(re.findall(r"\d+", text))     # every run of digits
Output
4521 6 10
['4521', '2026', '11', '02', '4522']

The main functions

FunctionReturns
re.search(p, s)First match anywhere, or None
re.match(p, s)Match only at the start, or None
re.fullmatch(p, s)Match only if the whole string fits
re.findall(p, s)List of all matches (or of groups)
re.finditer(p, s)Iterator of match objects
re.sub(p, repl, s)String with matches replaced
re.split(p, s)List split on the pattern
Python
import re print(re.match(r"\d+", "123abc"))print(re.match(r"\d+", "abc123"))print(bool(re.fullmatch(r"\d{6}", "411001")), bool(re.fullmatch(r"\d{6}", "41100")))print(re.sub(r"\s+", " ", "too    many   spaces"))print(re.split(r"[,;]\s*", "a, b;c ,d"))
Output
<re.Match object; span=(0, 3), match='123'>
None
True False
too many spaces
['a', 'b', 'c ', 'd']
Tip

Always check for None before calling .group() on the result of search or match: if m := re.search(p, s): print(m.group()).

Character classes

PatternMatches
\d / \Da digit / not a digit
\w / \Wa word character (letter, digit, _) / not
\s / \Swhitespace / not
.any character except newline
[aeiou]one of the listed characters
[a-z0-9]a character in the ranges
[^0-9]any character NOT listed
Python
import re s = "Room B-12, floor 3; call +91 98765 43210"print(re.findall(r"[A-Z]", s))print(re.findall(r"[aeiou]", s))print(re.findall(r"[^\w\s]", s))
Output
['R', 'B']
['o', 'o', 'o', 'o', 'a']
['-', ',', ';', '+']

Quantifiers

PatternMeaning
*0 or more
+1 or more
?0 or 1 (optional)
{3}exactly 3
{2,4}2 to 4
Python
import re print(re.findall(r"colou?r", "color colour colr"))print(re.findall(r"\d{2,3}", "1 12 123 1234"))print(re.findall(r"go+gle", "ggle gogle google gooogle"))
Output
['color', 'colour']
['12', '123', '123']
['gogle', 'google', 'gooogle']

Quantifiers are greedy: they take as much as possible. Add ? to make them lazy:

Python
import re html = "<b>bold</b> and <i>italic</i>"print(re.findall(r"<.+>", html))     # greedy: one huge matchprint(re.findall(r"<.+?>", html))    # lazy: each tag
Output
['<b>bold</b> and <i>italic</i>']
['<b>', '</b>', '<i>', '</i>']

Anchors and boundaries

^ is the start, $ the end, and \b a word boundary:

Python
import re print(re.findall(r"\bcat\b", "cat catalog concat cat."))print(bool(re.search(r"^ERROR", "ERROR: disk full")), bool(re.search(r"\.py$", "test_login.py")))
Output
['cat', 'cat']
True True

Groups

Brackets capture part of the match. findall returns the groups when the pattern has them.

Python
import re log = "2026-11-02 ERROR db; 2026-11-03 WARN cache"for m in re.finditer(r"(\d{4})-(\d{2})-(\d{2}) (\w+)", log):    print(m.group(0), "->", m.group(1), m.group(4)) print(re.findall(r"(\d{4})-\d{2}-\d{2} (\w+)", log))
Output
2026-11-02 ERROR -> 2026 ERROR
2026-11-03 WARN -> 2026 WARN
[('2026', 'ERROR'), ('2026', 'WARN')]

Named groups make patterns self-documenting:

Python
import re m = re.search(r"(?P<user>[\w.]+)@(?P<domain>[\w.-]+)", "contact: asha.k@sqatools.in today")print(m.group("user"), m.group("domain"))print(m.groupdict())
Output
asha.k sqatools.in
{'user': 'asha.k', 'domain': 'sqatools.in'}

Use groups in a replacement with \1 or \g<name>:

Python
import reprint(re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", "Due 2026-11-02 and 2026-12-25"))
Output
Due 02/11/2026 and 25/12/2026

Flags

Python
import re text = "Python\npython\nPYTHON"print(re.findall(r"python", text, flags=re.IGNORECASE))print(re.findall(r"^p\w+", text, flags=re.I | re.M))     # ^ at every line start
Output
['Python', 'python', 'PYTHON']
['Python', 'python', 'PYTHON']

Compile reusable patterns

Python
import re EMAIL = re.compile(r"^[\w.+-]+@[\w-]+(\.[\w-]+)+$")for e in ["asha@sqatools.in", "bad@", "ravi.k+test@mail.co.uk", "no spaces@x.com"]:    print(e, bool(EMAIL.match(e)))
Output
asha@sqatools.in True
bad@ False
ravi.k+test@mail.co.uk True
no spaces@x.com False
Watch out

Regex is great for patterns in text, but do not use it to parse HTML or JSON. Use html.parser, BeautifulSoup or json instead.

Escape special characters

Characters like . * + ? ( ) [ ] { } ^ $ | and the backslash have special meanings. Escape them with a backslash, or let re.escape() do it:

Python
import re price = "Rs. 1,499.50 (incl. tax)"print(re.findall(r"\d[\d,]*\.\d+", price))print(re.escape("1+1=2?"))
Output
['1,499.50']
1\+1=2\?

Check your understanding

Predict the output

import res = "a1b22c333"print(re.findall(r"\d", s), re.findall(r"\d+", s), re.sub(r"\d+", "#", s))

Quick quiz

1. What is the difference between re.match and re.search?

2. What does \d{3} match?

3. Why write patterns as raw strings like r"\d+"?

4. What does re.findall return when the pattern has one group?

Exercise: extract phone numbers

Find all 10-digit Indian mobile numbers (starting with 6, 7, 8 or 9) in the text, allowing an optional +91 and a space or hyphen after the first 5 digits.

Input
"Call 98765-43210 or +91 91234 56789; old: 12345 67890"
Expected output
98765-43210 -> 9876543210
+91 91234 56789 -> 9123456789
Hint 1

Start with (?:\+91\s?)? for the optional country code; (?: ) groups without capturing.

Hint 2

Then [6-9]\d{4}[\s-]?\d{5}.

Program Practice

Python regex FAQ

What is the re module in Python?

re is the standard-library module for regular expressions. It provides search, match, findall, sub, split and compile.

How do I extract numbers from a string in Python?

re.findall(r"\d+", text) returns every run of digits as strings. Use r"-?\d+(?:\.\d+)?" to include negatives and decimals.

What does re.compile do?

It turns a pattern into a reusable object. It makes code clearer when the same pattern is used many times; Python also caches recently used patterns automatically.

How do I make a regex case-insensitive?

Pass flags=re.IGNORECASE (or re.I), or start the pattern with (?i).

Python Modules & pip

Python Tutorial › Modules › Modules & pip

Python Modules & pip

IntermediateLesson 35 of 4712 min read6 runnable examples

A module is simply a .py file whose code you can reuse with import. Python ships with hundreds of modules (the standard library), and pip installs thousands more from PyPI. This lesson shows how to use both, and how to organise your own code into modules.

In this lesson
  • The different import styles
  • Create and import your own module
  • What if __name__ == “__main__” means
  • Install packages with pip in a virtual environment

Import a module

Python
import mathprint(math.sqrt(81)) from math import pi, floorprint(round(pi, 4), floor(7.9)) import statistics as statsprint(stats.mean([4, 8, 15, 16, 23, 42]))
Output
9.0
3.1416 7
18
StyleUse it asWhen
import mathmath.sqrt()Default; clear where names come from
from math import sqrtsqrt()You use a few names often
import numpy as npnp.array()Long names with a standard alias
from math import *sqrt()Avoid: hides where names come from

Explore a module

Python
import randomnames = [n for n in dir(random) if not n.startswith("_")]print(len(names) > 20)print("choice" in names, "shuffle" in names)print(random.choice.__doc__.splitlines()[0])
Output
True
True True
Choose a random element from a non-empty sequence.

Create your own module

Any .py file is a module. Save this as pricing.py:

pricing.py
TAX_RATE = 0.18 def with_tax(amount):    return round(amount * (1 + TAX_RATE), 2) def discount(amount, percent):    return round(amount * (1 - percent / 100), 2)

Then import it from another file in the same folder:

shop.py
import pricingfrom pricing import discount print(pricing.with_tax(1000))print(discount(1000, 15))print(pricing.TAX_RATE)
Output
1180.0
850.0
0.18

if __name__ == “__main__”

When a file is run directly, its __name__ is "__main__". When it is imported, __name__ is the module’s name. This lets a file be both a reusable module and a runnable script:

greeter.py
def greet(name):    return f"Hello, {name}" print("__name__ is", __name__) if __name__ == "__main__":    print(greet("from the command line"))
Output
__name__ is __main__
Hello, from the command line
app.py
import greeterprint(greeter.greet("from app.py"))
Output
__name__ is greeter
Hello, from app.py

When app.py imports greeter, the top-level print runs with __name__ set to greeter, but the code under the if does not.

Packages

A package is a folder of modules. Import modules from it with dots:

Terminal
myshop/    __init__.py    pricing.py    cart.pymain.py          ->  from myshop.pricing import with_tax

The standard library

ModuleUse it for
os, pathlib, shutilFiles, folders and paths
sysInterpreter details, command-line arguments
datetime, timeDates, times and timers
json, csvReading and writing data files
reRegular expressions
collections, itertoolsExtra containers and iterator tools
random, math, statisticsNumbers
loggingLog messages
unittestTesting (pytest is the popular third-party choice)

Install packages with pip

pip downloads packages from PyPI. Always run it through the Python you are using: python -m pip install requests.

Terminal
$ python -m pip --versionpip 26.2.2 from C:\Python3\Lib\site-packages\pip (python 3.15)

Use a virtual environment

A virtual environment is a private folder of packages for one project, so different projects can use different versions. Create one and check that its Python is used:

Terminal
$ python -m venv .venv$ .venv\Scripts\python -c "import sys; print(sys.prefix.endswith('.venv'))"True

Activate it so python and pip use it automatically:

  • Windows: .venv\Scripts\activate
  • macOS and Linux: source .venv/bin/activate

Then install and record your packages:

  • pip install requests pytest
  • pip freeze > requirements.txt saves the exact versions
  • pip install -r requirements.txt recreates them on another machine
Tip

Add .venv/ to .gitignore. Commit requirements.txt (or pyproject.toml) instead, so others can rebuild the environment.

Check your understanding

Quick quiz

1. What is a Python module?

2. What is __name__ when a file is run directly?

3. Why use python -m pip instead of plain pip?

4. Which file lists a project’s packages for others to install?

Program Practice

Python modules FAQ

What is the difference between a module and a package?

A module is one .py file. A package is a folder that groups modules (traditionally with an __init__.py file).

What does if __name__ == “__main__” do?

It runs the code below it only when the file is executed directly, not when it is imported by another file.

What is pip in Python?

pip is the package installer. It downloads packages from the Python Package Index (PyPI): python -m pip install package-name.

Why should I use a virtual environment?

It isolates each project’s packages, so upgrading a package for one project cannot break another, and requirements.txt stays accurate.

Python Polymorphism & Encapsulation

Python Tutorial › Object-Oriented Python › Polymorphism & Encapsulation

Python Polymorphism & Encapsulation

IntermediateLesson 33 of 4711 min read6 runnable examples

Polymorphism means “many forms”: different objects respond to the same method call in their own way. Encapsulation means keeping an object’s data behind its methods so it cannot be put into an invalid state. Together with inheritance they are the core ideas of object-oriented programming.

In this lesson
  • Polymorphism with overriding and duck typing
  • Operator overloading with special methods
  • Private attributes and name mangling
  • Getters and setters with @property

Polymorphism through overriding

Each class implements the same method name. Code that calls the method does not need to know which class it is dealing with.

Python
class Shape:    def area(self):        raise NotImplementedError class Circle(Shape):    def __init__(self, r):        self.r = r    def area(self):        return round(3.14159 * self.r ** 2, 2) class Square(Shape):    def __init__(self, side):        self.side = side    def area(self):        return self.side ** 2 for shape in [Circle(1), Square(3), Circle(2)]:    print(type(shape).__name__, shape.area())
Output
Circle 3.14
Square 9
Circle 12.57

Duck typing

Python does not require a shared parent class. If an object has the method you call, it works. “If it walks like a duck and quacks like a duck, it is a duck.”

Python
class PdfReport:    def export(self):        return "report.pdf" class CsvReport:    def export(self):        return "report.csv" def save_all(reports):    for r in reports:        print("saved", r.export()) save_all([PdfReport(), CsvReport()])
Output
saved report.pdf
saved report.csv

Built-in functions are polymorphic too: len() works on strings, lists and dicts because each type implements __len__.

Python
for thing in ["abc", [1, 2], {"a": 1}, range(10)]:    print(type(thing).__name__, len(thing))
Output
str 3
list 2
dict 1
range 10

Operator overloading

Special methods let your own classes work with +, ==, < and friends:

Python
class Money:    def __init__(self, amount):        self.amount = amount     def __add__(self, other):        return Money(self.amount + other.amount)     def __lt__(self, other):        return self.amount < other.amount     def __repr__(self):        return f"Money({self.amount})" a, b = Money(250), Money(100)print(a + b)print(a < b, sorted([a, b]))
Output
Money(350)
False [Money(100), Money(250)]
OperatorSpecial method
a + b__add__
a - b__sub__
a * b__mul__
a == b__eq__
a < b__lt__
len(a)__len__
str(a)__str__

Encapsulation: protecting data

Python has no true private attributes, but it has two conventions:

  • _name (one underscore): “internal, please do not touch from outside”.
  • __name (two underscores): Python renames it to _ClassName__name (name mangling), so it is hard to reach by accident.
Python
class Wallet:    def __init__(self):        self._currency = "INR"      # internal by convention        self.__balance = 0          # name-mangled     def add(self, amount):        self.__balance += amount     def balance(self):        return self.__balance w = Wallet()w.add(500)print(w.balance(), w._currency)print(w._Wallet__balance)          # still reachable if you insistprint(w.__balance)
Output
500 INR
500
Traceback (most recent call last):
  File "main.py", line 16, in <module>
    print(w.__balance)
          ^^^^^^^^^^^
AttributeError: 'Wallet' object has no attribute '__balance'. Did you mean '.balance' instead of '.__balance'?

Getters and setters with @property

@property lets you validate values while keeping simple attribute syntax for the caller:

Python
class Product:    def __init__(self, name, price):        self.name = name        self.price = price          # goes through the setter below     @property    def price(self):        return self._price     @price.setter    def price(self, value):        if value < 0:            raise ValueError("price cannot be negative")        self._price = value     @property    def price_with_tax(self):       # read-only computed attribute        return round(self._price * 1.18, 2) p = Product("Mouse", 349)p.price = 399print(p.price, p.price_with_tax) try:    p.price = -5except ValueError as e:    print("Error:", e)
Output
399 470.82
Error: price cannot be negative
Tip

Start with plain public attributes. Switch to @property only when you need validation or a computed value; callers do not need to change their code.

Check your understanding

Predict the output

class Cat:    def speak(self): return "meow"class Robot:    def speak(self): return "beep" print([x.speak() for x in (Cat(), Robot())])

Quick quiz

1. What does duck typing mean?

2. What does __add__ enable?

3. What happens to self.__secret inside class Box?

Exercise: temperature with validation

Create a Thermostat with a target property that only accepts values from 16 to 30 and raises ValueError otherwise.

Input
set target to 24, then try 35
Expected output
24
Rejected: 35 is outside 16-30
24
Hint 1

Store the real value in self._target inside the setter.

Program Practice

48 Python OOP Programs

Every program has a step-by-step explanation, colour-coded code and its real output.

Start practising →
Related sets:All practice sets

Polymorphism and encapsulation FAQ

What is polymorphism in Python with an example?

It is the ability of different objects to respond to the same call. len("abc") and len([1, 2]) both work, and shape.area() returns the right result for a Circle or a Square.

Does Python have private variables?

Not strictly. A leading underscore marks an attribute as internal, and a double underscore triggers name mangling. Both are conventions that discourage outside access.

What is @property in Python?

A decorator that turns a method into an attribute-like getter. Add @name.setter to run validation when the attribute is assigned.

Does Python support method overloading?

Not by signature. Define one method with default or variable arguments (*args) instead. Operator overloading is supported through special methods such as __add__.

Python Inheritance

Python Tutorial › Object-Oriented Python › Inheritance

Python Inheritance

IntermediateLesson 32 of 4711 min read8 runnable examples

Inheritance lets a new class reuse and extend an existing one. The child class gets all the parent’s attributes and methods, and can add its own or change how some of them behave. Page Object frameworks use this to share common page code in a BasePage.

In this lesson
  • Create a child class
  • Extend __init__ with super()
  • Override methods
  • Multiple inheritance and the MRO

A parent and a child

Put the parent class in brackets after the child’s name. The child inherits everything from the parent.

Python
class Vehicle:    def __init__(self, brand):        self.brand = brand     def start(self):        return f"{self.brand} engine started" class Car(Vehicle):        # Car inherits from Vehicle    pass c = Car("Tata")print(c.start())print(isinstance(c, Car), isinstance(c, Vehicle))
Output
Tata engine started
True True

Add attributes with super()

To add new attributes, define __init__ in the child and call the parent’s __init__ with super(), so the parent’s setup still happens.

Python
class Vehicle:    def __init__(self, brand):        self.brand = brand class Car(Vehicle):    def __init__(self, brand, seats):        super().__init__(brand)     # let Vehicle set brand        self.seats = seats          # then add Car's own data c = Car("Mahindra", 7)print(c.brand, c.seats)
Output
Mahindra 7
Watch out

If the child defines __init__ and forgets super().__init__(...), the parent’s attributes are never set and you get AttributeError later.

Override methods

A method with the same name in the child replaces the parent’s version. Call super().method() to reuse the parent’s code inside the new one.

Python
class Employee:    def __init__(self, name, salary):        self.name = name        self.salary = salary     def annual_pay(self):        return self.salary * 12     def describe(self):        return f"{self.name} earns {self.annual_pay()} a year" class Manager(Employee):    def __init__(self, name, salary, bonus):        super().__init__(name, salary)        self.bonus = bonus     def annual_pay(self):                     # override        return super().annual_pay() + self.bonus staff = [Employee("Asha", 50000), Manager("Ravi", 80000, 100000)]for person in staff:    print(person.describe())
Output
Asha earns 600000 a year
Ravi earns 1060000 a year

describe() is defined only in Employee, yet for a Manager it calls the overridden annual_pay(). Python always looks up the method on the actual object.

A real example: page objects

Python
class BasePage:    url = "/"     def __init__(self, base_url):        self.base_url = base_url     def open(self):        return f"GET {self.base_url}{self.url}" class LoginPage(BasePage):    url = "/login"     def login(self, user):        return f"{self.open()} -> sign in as {user}" class CartPage(BasePage):    url = "/cart" print(LoginPage("https://shop.test").login("asha"))print(CartPage("https://shop.test").open())
Output
GET https://shop.test/login -> sign in as asha
GET https://shop.test/cart

Multilevel inheritance

A child can itself be a parent:

Python
class Animal:    def breathe(self):        return "breathing" class Mammal(Animal):    def feed(self):        return "feeding milk" class Dog(Mammal):    def bark(self):        return "woof" d = Dog()print(d.breathe(), "|", d.feed(), "|", d.bark())
Output
breathing | feeding milk | woof

Multiple inheritance and the MRO

A class can inherit from several parents. When two parents define the same method, Python follows the method resolution order (MRO): the child first, then the parents from left to right.

Python
class Flyer:    def move(self):        return "flying" class Swimmer:    def move(self):        return "swimming" class Duck(Flyer, Swimmer):    pass print(Duck().move())print([cls.__name__ for cls in Duck.__mro__])
Output
flying
['Duck', 'Flyer', 'Swimmer', 'object']
Tip

Multiple inheritance is mostly used for small “mixin” classes that add one feature, such as logging. Keep hierarchies shallow.

Checking relationships

Python
class A: passclass B(A): pass print(issubclass(B, A), issubclass(A, B))print(isinstance(B(), A))
Output
True False
True

Abstract base classes

An abstract class defines methods that every child must implement. You cannot create an object from it directly.

Python
from abc import ABC, abstractmethod class Shape(ABC):    @abstractmethod    def area(self):        ... class Square(Shape):    def __init__(self, side):        self.side = side    def area(self):        return self.side ** 2 print(Square(4).area())Shape()
Output
16
Traceback (most recent call last):
  File "main.py", line 15, in <module>
    Shape()
    ~~~~~^^
TypeError: Can't instantiate abstract class Shape without an implementation for abstract method 'area'

Check your understanding

Predict the output

class A:    def hello(self):        return "A"class B(A):    def hello(self):        return "B+" + super().hello()class C(B):    pass print(C().hello())

Quick quiz

1. How do you call the parent’s __init__ from a child?

2. What is method overriding?

3. For class D(B, C), where is a method looked up after D?

Exercise: savings account

Create SavingsAccount that inherits from Account, adds an interest_rate, and has an add_interest() method.

Input
SavingsAccount("Meena", 1000, 0.05)
Expected output
Meena 1050.0
Hint 1

Call super().__init__(owner, balance) first.

Program Practice

48 Python OOP Programs

Every program has a step-by-step explanation, colour-coded code and its real output.

Start practising →
Related sets:All practice sets

Python inheritance FAQ

What does super() do in Python?

super() gives access to methods of the parent class (strictly, the next class in the MRO), most often to call the parent’s __init__ or an overridden method.

Does Python support multiple inheritance?

Yes. A class can list several parents. Python resolves name clashes with the method resolution order (C3 linearisation), which you can inspect with ClassName.__mro__.

What is the difference between inheritance and composition?

Inheritance models “is a” (a Manager is an Employee). Composition models “has a” (a Car has an Engine) by storing another object as an attribute. Prefer composition when the relationship is not truly “is a”.

Python Iterators

Python Tutorial › Functions › Iterators

Python Iterators

IntermediateLesson 28 of 479 min read8 runnable examples

Every for loop in Python uses an iterator behind the scenes. Knowing how iterators work explains why some objects can be looped over only once, and lets you write your own objects that work with for.

In this lesson
  • Iterables vs iterators
  • iter(), next() and StopIteration
  • Build a custom iterator class
  • Useful tools from itertools

Iterable vs iterator

  • An iterable is anything you can loop over: a list, string, tuple, dict, set, file or range.
  • An iterator is the object that actually hands out the items, one at a time, and remembers its position.

iter() gets an iterator from an iterable, and next() asks it for the next item:

Python
colors = ["red", "green", "blue"]it = iter(colors) print(next(it))print(next(it))print(next(it))
Output
red
green
blue

When there are no items left, next() raises StopIteration:

Python
it = iter([1])print(next(it))print(next(it))
Output
1
Traceback (most recent call last):
  File "main.py", line 3, in <module>
    print(next(it))
          ~~~~^^^^
StopIteration

Pass a default to next() to avoid the error:

Python
it = iter([])print(next(it, "no more items"))
Output
no more items

How a for loop works

A for loop is a while loop that calls iter() once and next() until StopIteration:

Python
items = ["a", "b", "c"] it = iter(items)while True:    try:        item = next(it)    except StopIteration:        break    print(item)
Output
a
b
c

Iterators are used up

An iterator moves forward only. Once it is exhausted it stays empty. A list can be looped over many times because each for loop asks it for a fresh iterator.

Python
squares = map(lambda x: x * x, [1, 2, 3])    # map returns an iteratorprint(list(squares))print(list(squares))      # already used up nums = [1, 2, 3]print(sum(nums), sum(nums))   # a list gives a new iterator each time
Output
[1, 4, 9]
[]
6 6

Write your own iterator

A class becomes an iterator by defining __iter__() (returning itself) and __next__() (returning the next item or raising StopIteration):

Python
class Countdown:    def __init__(self, start):        self.current = start     def __iter__(self):        return self     def __next__(self):        if self.current <= 0:            raise StopIteration        value = self.current        self.current -= 1        return value for n in Countdown(3):    print(n)print(list(Countdown(5)))
Output
3
2
1
[5, 4, 3, 2, 1]
Tip

Writing a class like this takes a dozen lines. A generator function does the same job in three; see the next lesson, Generators.

Infinite iterators and itertools

Iterators can be infinite because they produce values only when asked. The itertools module has many ready-made ones:

Python
import itertools counter = itertools.count(start=100, step=10)print([next(counter) for _ in range(3)]) print(list(itertools.islice(itertools.cycle("AB"), 5)))print(list(itertools.chain([1, 2], (3, 4), "56")))print(list(itertools.combinations("ABC", 2)))print(list(itertools.product([0, 1], repeat=2)))
Output
[100, 110, 120]
['A', 'B', 'A', 'B', 'A']
[1, 2, 3, 4, '5', '6']
[('A', 'B'), ('A', 'C'), ('B', 'C')]
[(0, 0), (0, 1), (1, 0), (1, 1)]

Built-ins that return iterators

map(), filter(), zip(), enumerate(), reversed() and open() all return iterators. They are lazy: no work happens until you ask for items.

Python
pairs = zip(["a", "b", "c"], [1, 2, 3])print(next(pairs))print(list(pairs))       # continues from where next() left off
Output
('a', 1)
[('b', 2), ('c', 3)]

Check your understanding

Predict the output

it = iter("abc")next(it)print(list(it), list(it))

Quick quiz

1. Which function gets the next item from an iterator?

2. What happens when an iterator has no more items?

3. Which two methods make a class an iterator?

Exercise: even number iterator

Write a class Evens(limit) that iterates over the even numbers from 0 up to and including limit.

Input
Evens(10)
Expected output
[0, 2, 4, 6, 8, 10]
Hint 1

Store the next value in self.n and add 2 each time.

Program Practice

20 Python Iterator & Generator Programs

Every program has a step-by-step explanation, colour-coded code and its real output.

Start practising →
Related sets:All practice sets

Python iterators FAQ

What is the difference between an iterable and an iterator?

An iterable can produce an iterator (lists, strings, dicts). An iterator produces the items one at a time with next() and remembers its position. Every iterator is also iterable.

Why can I loop over a list twice but not over map()?

A list creates a new iterator for each loop. map() is itself an iterator, so once its items are consumed it is empty.

How do I make a class iterable in Python?

Define __iter__() returning an iterator. The easiest way is to make __iter__ a generator method using yield.