October 2, 2026
–
Guides

50 Python Interview Questions (With Answers That Actually Help)

why companies keep asking python interview questions (and what they actually test)

you're preparing for a tech interview. you've seen the job description — it mentions python. now you're wondering which questions actually come up and what depth the interviewer expects.

here's the honest answer: most python interviews don't test whether you memorised the documentation. they test whether you can explain how things work, catch what's wrong in a piece of code, and write something functional under a time limit.

this guide covers 50 python interview questions across four levels — basics, intermediate, object-oriented, and coding problems. each answer is written the way you'd explain it in a real conversation, not the way a textbook defines it. if something needs code, the code is included.

at the end, you'll find a link to weekday's interview question generator — it builds practice sets tailored to the role you're applying for.

a. python basics — the questions every interviewer starts with

these are warm-up questions. interviewers use them to check whether you've actually written python or just listed it on your resume. get comfortable explaining these in your own words.

1. what is python, and why do developers use it?

python is a high-level, interpreted language. "high-level" means you write code closer to how humans think. "interpreted" means the code runs line by line without a separate compilation step.

developers use it because the syntax is readable, the standard library covers most common tasks, and the ecosystem around data, web, and automation is massive. it's the most-used language on github for a reason.

2. what's the difference between a list and a tuple?

a list is mutable — you can add, remove, or change items after creating it. a tuple is immutable — once created, it stays the same.

use a tuple when you want to protect data from accidental changes, like coordinates or database connection settings. use a list when the collection needs to grow or shrink.

coordinates = (28.6139, 77.2090)   # tuple — won't change
shopping_cart = ["notebook", "pen"]  # list — items get added and removed

3. how does python manage memory?

python uses automatic memory management through reference counting and a garbage collector. every object has a count of how many variables point to it. when that count drops to zero, the memory is freed.

the garbage collector handles circular references — cases where two objects point to each other and neither count reaches zero on its own.

4. what are python's built-in data types?

the ones you'll use daily: int, float, str, bool, list, tuple, dict, set, and NoneType. interviewers sometimes ask you to name them quickly — it's a baseline check.

5. explain the difference between == and is

== checks whether two objects have the same value. is checks whether they are the exact same object in memory.

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)   # True — same values
print(a is b)   # False — different objects in memory

this trips up beginners more than you'd expect. if your code behaves differently from what you intended, check whether you used is when you meant ==.

6. what does the pass statement do?

it does nothing. literally. you use it as a placeholder when python's syntax requires a statement but you haven't written the logic yet.

def process_payment():
   pass  # will implement after the api docs arrive

7. how do you handle exceptions in python?

with a try-except block. the code that might fail goes inside try. what should happen if it fails goes inside except.

try:
   result = 10 / 0
except ZeroDivisionError:
   result = None
   print("can't divide by zero")

always catch specific exceptions. a bare except: swallows every error, including the ones you want to know about.

8. what are *args and **kwargs?

*args lets a function accept any number of positional arguments. **kwargs does the same for keyword arguments.

def log_event(*args, **kwargs):
   print("args:", args)
   print("kwargs:", kwargs)

log_event("login", "success", user="biswa", time="10:30")
# args: ('login', 'success')
# kwargs: {'user': 'biswa', 'time': '10:30'}

9. what is a dictionary comprehension?

a one-liner that creates a dictionary from an iterable. same idea as list comprehension, but with key-value pairs.

squares = {x: x**2 for x in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

10. what does the with statement do?

it manages resources automatically. the most common use is file handling — the file closes itself when the block ends, even if an error occurs.

with open("data.csv", "r") as file:
   content = file.read()
# file is already closed here

b. intermediate python — where interviews get interesting

these questions separate someone who's used python casually from someone who's built things with it. expect follow-up questions on your answers here.

11. what are decorators?

a decorator wraps a function to add behaviour before or after it runs — without modifying the function itself. think of it as adding a layer around existing code.

def log_calls(func):
   def wrapper(*args, **kwargs):
       print(f"calling {func.__name__}")
       return func(*args, **kwargs)
   return wrapper

@log_calls
def calculate_salary(base, bonus):
   return base + bonus

common real-world use: logging, authentication checks, rate limiting, caching.

12. explain generators and the yield keyword

a generator produces values one at a time instead of creating an entire list in memory. you write it like a function, but use yield instead of return.

def count_up_to(limit):
   n = 1
   while n

why it matters: if you're processing a 10GB log file, a generator reads it line by line instead of loading everything into memory.

13. what's the difference between shallow copy and deep copy?

a shallow copy creates a new object but keeps references to the nested objects inside it. a deep copy creates new copies of everything, including nested objects.

import copy
original = [[1, 2], [3, 4]]
shallow = copy.copy(original)
deep = copy.deepcopy(original)

original[0][0] = 99
print(shallow[0][0])  # 99 — still linked
print(deep[0][0])     # 1  — independent copy

14. how does python's GIL affect multithreading?

the global interpreter lock (GIL) means only one thread executes python bytecode at a time. for CPU-heavy work, threads won't give you true parallelism — you need multiprocessing instead.

for I/O-heavy work (network requests, file reads), threading still helps because the GIL releases while waiting for I/O.

15. what are list comprehensions, and when should you avoid them?

a compact way to create lists from iterables.

even_numbers = [x for x in range(20) if x % 2 == 0]

avoid them when the logic gets nested or hard to read. a regular for-loop with comments is better than a one-liner nobody can debug.

16. explain the difference between @staticmethod and @classmethod

@staticmethod doesn't receive the class or instance — it's a regular function that lives inside a class for organisation. @classmethod receives the class itself as the first argument and can create instances or modify class-level state.

class Employee:
   raise_percentage = 1.10

   @classmethod
   def set_raise(cls, percentage):
       cls.raise_percentage = percentage

   @staticmethod
   def is_workday(day):
       return day.weekday() < 5

17. what is a virtual environment, and why do you need one?

a virtual environment isolates your project's dependencies from the system python and from other projects. without it, installing a package for one project can break another.

python -m venv myproject_env
source myproject_env/bin/activate  # linux/mac
pip install flask

18. how does python's garbage collection work beyond reference counting?

python's gc module runs a generational garbage collector. objects are grouped into three generations. new objects start in generation 0. if they survive a collection cycle, they move to generation 1, then 2. the idea is that most objects die young, so checking the youngest generation frequently is efficient.

19. what are context managers, and how do you write a custom one?

context managers handle setup and teardown. the with statement calls __enter__ at the start and __exit__ at the end.

class DatabaseConnection:
   def __enter__(self):
       self.conn = create_connection()
       return self.conn

   def __exit__(self, exc_type, exc_val, exc_tb):
       self.conn.close()

20. explain map(), filter(), and reduce()

map() applies a function to every item. filter() keeps items where the function returns True. reduce() (from functools) accumulates items into a single result.

nums = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, nums))        # [2, 4, 6, 8, 10]
evens = list(filter(lambda x: x % 2 == 0, nums))   # [2, 4]

from functools import reduce
total = reduce(lambda a, b: a + b, nums)             # 15

c. object-oriented python — testing how you structure code

OOP questions reveal whether you think about code organisation or just write scripts. even if the role isn't heavy on class hierarchies, interviewers use these to assess design thinking.

21. what are the four principles of OOP?

encapsulation — bundling data and methods together, controlling access. abstraction — hiding complex implementation behind a simple interface. inheritance — creating new classes from existing ones. polymorphism — using the same interface for different types.

22. how does inheritance work in python?

class Animal:
   def speak(self):
       return "..."

class Dog(Animal):
   def speak(self):
       return "woof"

class Cat(Animal):
   def speak(self):
       return "meow"

python supports multiple inheritance, which means a class can inherit from more than one parent. the method resolution order (MRO) decides which parent's method gets called first.

23. what is polymorphism? give a practical example

different objects responding to the same method call in their own way. the code that calls .speak() doesn't need to know whether it's dealing with a Dog or a Cat.

animals = [Dog(), Cat(), Dog()]
for animal in animals:
   print(animal.speak())  # woof, meow, woof

24. what's the difference between a class variable and an instance variable?

class variables are shared by all instances. instance variables belong to one specific object.

class Team:
   company = "weekday"       # class variable — same for all

   def __init__(self, name):
       self.name = name       # instance variable — unique per object

25. explain dunder methods (__init__, __str__, __repr__)

__init__ runs when you create an object. __str__ defines what print() shows to users. __repr__ defines what developers see in the debugger — it should ideally be unambiguous enough to recreate the object.

class Job:
   def __init__(self, title, company):
       self.title = title
       self.company = company

   def __str__(self):
       return f"{self.title} at {self.company}"

   def __repr__(self):
       return f"Job('{self.title}', '{self.company}')"

26. what is encapsulation in python?

restricting direct access to an object's data. python uses naming conventions: a single underscore _variable means "treat this as internal." a double underscore __variable triggers name mangling so it's harder to access from outside the class.

python doesn't enforce private access the way java does. it trusts developers to follow conventions.

27. how do abstract classes work?

an abstract class defines methods that subclasses must implement. you can't create an instance of the abstract class itself.

from abc import ABC, abstractmethod

class PaymentProcessor(ABC):
   @abstractmethod
   def process(self, amount):
       pass

class UPIPayment(PaymentProcessor):
   def process(self, amount):
       return f"processing ₹{amount} via UPI"

28. what is method resolution order (MRO)?

when a class inherits from multiple parents, python follows the C3 linearisation algorithm to decide which method to call. you can check it with ClassName.__mro__ or ClassName.mro().

29. what are property decorators?

they let you define methods that behave like attributes — so you can add validation or computation without changing how the caller accesses the data.

class Employee:
   def __init__(self, salary):
       self._salary = salary

   @property
   def salary(self):
       return self._salary

   @salary.setter
   def salary(self, value):
       if value < 0:
           raise ValueError("salary can't be negative")
       self._salary = value

30. when would you use composition over inheritance?

when the relationship is "has a" rather than "is a." a Car has an Engine — it doesn't inherit from Engine. composition gives you more flexibility because you can swap components without restructuring the class hierarchy.

d. python coding problems — the hands-on round

these are the questions where you actually write code. interviewers watch how you think through the problem, not just whether the answer is correct. talk through your approach before writing.

31. reverse a string without using built-in reverse functions

def reverse_string(s):
   return s[::-1]

# if the interviewer says "no slicing either":
def reverse_string_manual(s):
   result = ""
   for char in s:
       result = char + result
   return result

32. check if a string is a palindrome

def is_palindrome(s):
   cleaned = s.lower().replace(" ", "")
   return cleaned == cleaned[::-1]

print(is_palindrome("Race Car"))  # True

33. find the second largest number in a list

def second_largest(nums):
   unique = list(set(nums))
   unique.sort()
   return unique[-2] if len(unique) >= 2 else None

print(second_largest([10, 20, 4, 45, 99, 99]))  # 45

34. count the frequency of each character in a string

def char_frequency(s):
   freq = {}
   for char in s:
       freq[char] = freq.get(char, 0) + 1
   return freq

print(char_frequency("weekday"))  # {'w': 1, 'e': 2, 'k': 1, 'd': 1, 'a': 1, 'y': 1}

35. write a function to flatten a nested list

def flatten(lst):
   result = []
   for item in lst:
       if isinstance(item, list):
           result.extend(flatten(item))
       else:
           result.append(item)
   return result

print(flatten([1, [2, [3, 4]], [5, 6]]))  # [1, 2, 3, 4, 5, 6]

36. remove duplicates from a list while preserving order

def remove_duplicates(lst):
   seen = set()
   result = []
   for item in lst:
       if item not in seen:
           seen.add(item)
           result.append(item)
   return result

37. implement a basic fibonacci sequence

def fibonacci(n):
   a, b = 0, 1
   result = []
   for _ in range(n):
       result.append(a)
       a, b = b, a + b
   return result

print(fibonacci(8))  # [0, 1, 1, 2, 3, 5, 8, 13]

38. check if two strings are anagrams

def are_anagrams(s1, s2):
   return sorted(s1.lower()) == sorted(s2.lower())

print(are_anagrams("listen", "silent"))  # True

39. find common elements between two lists

def common_elements(list1, list2):
   return list(set(list1) & set(list2))

print(common_elements([1, 2, 3, 4], [3, 4, 5, 6]))  # [3, 4]

40. merge two sorted lists into one sorted list

def merge_sorted(list1, list2):
   result = []
   i = j = 0
   while i < len(list1) and j < len(list2):
       if list1[i]

e. advanced python — for senior roles and deeper conversations

these come up when the interviewer wants to test your understanding of python internals and your ability to make design decisions. not every interview reaches this level, but preparation here sets you apart.

41. what are metaclasses?

a metaclass is the class of a class. just like an object is an instance of a class, a class is an instance of a metaclass. the default metaclass is type.

you'd use a custom metaclass to enforce rules on class creation — like requiring every subclass to implement certain methods, or automatically registering classes in a plugin system.

42. explain the descriptor protocol

descriptors control what happens when you access an attribute. any object that defines __get__, __set__, or __delete__ is a descriptor. this is the mechanism behind @property, @classmethod, and @staticmethod.

43. what is monkey patching?

changing a module or class at runtime. useful for testing (mocking external calls), but dangerous in production because it makes the code unpredictable.

import some_module
some_module.expensive_api_call = lambda: {"status": "mocked"}

44. how do you optimise python code for performance?

start by profiling — cProfile or line_profiler — instead of guessing. common wins: use built-in functions (they're implemented in C), avoid unnecessary list copies, prefer generators for large datasets, use collections.defaultdict or Counter instead of manual counting loops.

45. what is the difference between concurrency and parallelism in python?

concurrency means multiple tasks make progress by switching between them (asyncio, threading). parallelism means multiple tasks run simultaneously on different CPU cores (multiprocessing).

due to the GIL, true parallelism in python requires multiprocessing or calling into C extensions.

46. explain asyncio and when to use it

asyncio handles many I/O-bound tasks efficiently with a single thread. instead of waiting for a network response, it switches to another task.

import asyncio

async def fetch_data(url):
   # simulate network call
   await asyncio.sleep(1)
   return f"data from {url}"

async def main():
   results = await asyncio.gather(
       fetch_data("api/users"),
       fetch_data("api/jobs"),
       fetch_data("api/companies")
   )
   print(results)

use it when you're making many API calls, reading from multiple sockets, or building a web server that handles thousands of connections.

47. what is type hinting and why does it matter?

type hints annotate what types a function expects and returns. python doesn't enforce them at runtime, but tools like mypy use them to catch bugs before you run the code.

def calculate_ctc(base: float, bonus: float) -> float:
   return base + bonus

in large codebases, type hints act as documentation that stays accurate because the linter checks it.

48. how would you implement a simple caching mechanism?

from functools import lru_cache

@lru_cache(maxsize=128)
def get_company_data(company_id):
   # expensive database query
   return db.query(f"SELECT * FROM companies WHERE id = {company_id}")

lru_cache stores recent results so repeated calls with the same arguments skip the computation.

49. explain the walrus operator (:=)

introduced in python 3.8. it assigns a value to a variable as part of an expression, so you can avoid computing the same thing twice.

# without walrus
data = get_data()
if data:
   process(data)

# with walrus
if (data := get_data()):
   process(data)

50. what would you check during a code review of python code?

this isn't a trick question — it tests engineering judgment. a solid answer covers: readability (clear naming, consistent style), error handling (specific exceptions, no silent failures), test coverage (edge cases, not just happy paths), performance (unnecessary loops, missing indexes), and security (user input validation, no hardcoded secrets).

what to do after practising these questions

reading answers is useful. explaining them out loud is better. pick five questions, set a timer, and answer them as if someone is listening. if you stumble, that's the question you need to revisit.

if you want a tailored set of questions based on the specific role and company you're applying for, try weekday's interview question predictor. it builds a practice round matched to real job descriptions, so you're not preparing for generic questions when the role needs something specific.

and once you feel ready — or even if you just want to see what's out there — browse python developer jobs on weekday. every listing shows who posted it and how many people have already applied, so you're not sending your resume into a black box.

good luck with the interview. you've probably done harder debugging than anything on this list.

Latest Articles

Browse Articles
Use AI to find jobs and apply

Stop manually filling job applications. Use AI to auto-apply to jobs

Browse jobs now