Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools
Python

Top 50 Python Interview Questions

Curated questions covering OOP, decorators, generators, list comprehensions, data structures, Django, Flask, and Python 3 features.

01

What is Python and what are its key features?

Python is a high-level, interpreted, dynamically-typed language. Key features: simple syntax, extensive standard library, dynamic typing, automatic memory management (garbage collection), supports multiple paradigms (OOP, functional, procedural), and a vast ecosystem (Django, Flask, NumPy, pandas).

02

What is the difference between Python 2 and Python 3?

  • print - Python 2: print "hello". Python 3: print("hello") (function).
  • Division - Python 2: 5/2 = 2 (integer). Python 3: 5/2 = 2.5 (float). Use // for integer division.
  • Unicode - Python 3 strings are Unicode by default.
  • Python 2 reached end-of-life in 2020. Always use Python 3.
03

What is the difference between list, tuple, and set?

  • list - mutable, ordered, allows duplicates. Syntax: [1, 2, 3].
  • tuple - immutable, ordered, allows duplicates. Syntax: (1, 2, 3). Faster than list.
  • set - mutable, unordered, no duplicates. Syntax: {1, 2, 3}. O(1) membership test.
Example
lst = [1, 2, 2, 3]\ntpl = (1, 2, 2, 3)\nst = {1, 2, 2, 3}  # {1, 2, 3} - duplicates removed
04

What is the difference between list and dict?

  • list - ordered collection indexed by integers. O(n) lookup by value.
  • dict - unordered (Python 3.7+ maintains insertion order) key-value pairs. O(1) lookup by key.
Example
lst = ["a", "b", "c"]\nprint(lst[0])  # "a"\n\ndct = {"name": "Alice", "age": 30}\nprint(dct["name"])  # "Alice"
05

What is a Python decorator?

A decorator wraps a function to extend its behavior without modifying it. Used for logging, authentication, caching, and timing.

Example
def log(func):\n  def wrapper(*args, **kwargs):\n    print(f"Calling {func.__name__}")\n    return func(*args, **kwargs)\n  return wrapper\n\n@log\ndef greet(name):\n  return f"Hello, {name}"\n\ngreet("Alice")  # prints "Calling greet", returns "Hello, Alice"
06

What is the difference between *args and **kwargs?

  • *args - captures positional arguments as a tuple.
  • **kwargs - captures keyword arguments as a dict.
  • Both allow functions to accept a variable number of arguments.
Example
def func(*args, **kwargs):\n  print(args)    # (1, 2, 3)\n  print(kwargs)  # {"a": 4, "b": 5}\n\nfunc(1, 2, 3, a=4, b=5)
07

What is a Python generator?

A generator yields values one at a time using yield, enabling memory-efficient iteration over large datasets. Generators are lazy - they produce values on demand.

Example
def fibonacci(n):\n  a, b = 0, 1\n  for _ in range(n):\n    yield a\n    a, b = b, a + b\n\nfor num in fibonacci(10):\n  print(num)
08

What is the difference between yield and return?

  • return - exits the function and returns a value. Function state is lost.
  • yield - pauses the function and returns a value. Function state is preserved. Next call resumes from where it left off.
  • yield creates a generator; return creates a regular function.
09

What is list comprehension in Python?

List comprehension provides a concise way to create lists. It is more readable and often faster than equivalent for loops.

Example
# Traditional\nsquares = []\nfor x in range(10):\n  squares.append(x**2)\n\n# List comprehension\nsquares = [x**2 for x in range(10)]\n\n# With condition\nevens = [x for x in range(10) if x % 2 == 0]
10

What is the difference between list comprehension and generator expression?

  • List comprehension [x for x in ...] - creates the entire list in memory immediately.
  • Generator expression (x for x in ...) - creates a generator that yields values lazily. Memory-efficient for large datasets.
Example
lst = [x**2 for x in range(1000000)]  # entire list in memory\ngen = (x**2 for x in range(1000000))  # lazy, one at a time
11

What is the difference between == and is in Python?

  • == - compares values (calls __eq__ method).
  • is - compares object identity (memory address). Checks if two variables point to the same object.
Example
a = [1, 2, 3]\nb = [1, 2, 3]\nc = a\nprint(a == b)  # True (same values)\nprint(a is b)  # False (different objects)\nprint(a is c)  # True (same object)
12

What is the difference between shallow copy and deep copy?

  • Shallow copy - copies the object but not nested objects. Nested objects are still referenced.
  • Deep copy - recursively copies the object and all nested objects. Completely independent.
Example
import copy\noriginal = [[1, 2], [3, 4]]\nshallow = copy.copy(original)\ndeep = copy.deepcopy(original)\n\nshallow[0][0] = 99  # affects original\ndeep[0][0] = 88     # does not affect original
13

What is the difference between @staticmethod and @classmethod?

  • @staticmethod - does not receive implicit first argument. Cannot access class or instance state. Just a function grouped in a class namespace.
  • @classmethod - receives the class (cls) as the first argument. Can access class variables and create instances.
Example
class MyClass:\n  count = 0\n  @staticmethod\n  def add(a, b): return a + b\n  @classmethod\n  def increment(cls): cls.count += 1
14

What is the difference between __str__ and __repr__?

  • __str__ - human-readable string representation. Called by str() and print().
  • __repr__ - unambiguous string representation for developers. Called by repr() and in the REPL. Should ideally be valid Python code to recreate the object.
  • If only one is defined, define __repr__.
Example
class Point:\n  def __init__(self, x, y): self.x, self.y = x, y\n  def __repr__(self): return f"Point({self.x}, {self.y})"\n  def __str__(self): return f"({self.x}, {self.y})"
15

What is the difference between append() and extend() for lists?

  • append(item) - adds a single item to the end of the list. If item is a list, the entire list is added as one element.
  • extend(iterable) - adds all elements from the iterable to the end of the list.
Example
a = [1, 2]\na.append([3, 4])  # [1, 2, [3, 4]]\n\nb = [1, 2]\nb.extend([3, 4])  # [1, 2, 3, 4]
16

What is the difference between remove(), pop(), and del for lists?

  • remove(value) - removes the first occurrence of a value. Raises ValueError if not found.
  • pop(index) - removes and returns the element at index (default: last). Raises IndexError if empty.
  • del list[index] - deletes the element at index or a slice. Can also delete the entire list.
Example
lst = [1, 2, 3, 2]\nlst.remove(2)  # [1, 3, 2]\nlst.pop()      # returns 2, lst is [1, 3]\ndel lst[0]     # [3]
17

What is the difference between range() and xrange()?

xrange() existed in Python 2 and returned a generator. range() in Python 2 returned a list. In Python 3, range() behaves like Python 2 xrange() (returns a lazy range object), and xrange() was removed.

18

What is the Global Interpreter Lock (GIL)?

The GIL is a mutex that allows only one thread to execute Python bytecode at a time, even on multi-core systems. This simplifies memory management but limits CPU-bound parallelism. Use multiprocessing for CPU-bound tasks; threading still works for I/O-bound tasks.

19

What is the difference between threading and multiprocessing in Python?

  • threading - multiple threads in one process. Shares memory. Limited by GIL for CPU-bound tasks. Good for I/O-bound tasks.
  • multiprocessing - multiple processes, each with its own Python interpreter and memory. No GIL limitation. Good for CPU-bound tasks.
Example
from multiprocessing import Pool\n\ndef square(x): return x * x\n\nwith Pool(4) as pool:\n  results = pool.map(square, range(10))
20

What is the difference between lambda and def?

  • lambda - anonymous function, single expression only, returns the expression result implicitly.
  • def - named function, multiple statements, explicit return.
  • Use lambda for short, throwaway functions; def for everything else.
Example
# lambda\nsquare = lambda x: x**2\n\n# def\ndef square(x):\n  return x**2\n\n# lambda in sorted()\nstudents.sort(key=lambda s: s.age)
21

What is the difference between map(), filter(), and reduce()?

  • map(func, iterable) - applies func to each element, returns an iterator.
  • filter(func, iterable) - returns elements where func returns True.
  • reduce(func, iterable) - accumulates values into a single result. Requires from functools import reduce.
Example
nums = [1, 2, 3, 4, 5]\nlist(map(lambda x: x*2, nums))      # [2,4,6,8,10]\nlist(filter(lambda x: x%2==0, nums)) # [2,4]\nfrom functools import reduce\nreduce(lambda a,b: a+b, nums)    # 15
22

What is the difference between __init__ and __new__?

  • __new__(cls) - creates and returns a new instance. Called before __init__. Rarely overridden.
  • __init__(self) - initializes the instance after it is created. Most common place for setup logic.
Example
class Singleton:\n  _instance = None\n  def __new__(cls):\n    if cls._instance is None:\n      cls._instance = super().__new__(cls)\n    return cls._instance
23

What is the difference between instance variables, class variables, and local variables?

  • Instance variables (self.x) - unique to each instance. Defined in __init__.
  • Class variables - shared across all instances. Defined at class level.
  • Local variables - exist only within a function scope.
Example
class MyClass:\n  class_var = 0  # class variable\n  def __init__(self, x):\n    self.x = x   # instance variable
24

What is the difference between @property and getters/setters?

@property allows you to define methods that are accessed like attributes, providing controlled access to private variables without explicit getter/setter calls.

Example
class User:\n  def __init__(self, name):\n    self._name = name\n  @property\n  def name(self): return self._name\n  @name.setter\n  def name(self, value):\n    if not value: raise ValueError("Name required")\n    self._name = value\n\nuser.name = "Alice"  # calls setter
25

What is the difference between is None and == None?

is None checks object identity (recommended). == None checks equality (calls __eq__). Always use is None because None is a singleton - there is only one None object in Python.

Example
if value is None:  # correct\n  pass\nif value == None:  # works but not idiomatic\n  pass
26

What is the difference between mutable and immutable types in Python?

  • Immutable - cannot be changed after creation: int, float, str, tuple, frozenset.
  • Mutable - can be modified in place: list, dict, set.
  • Immutable objects are hashable and can be dict keys; mutable objects cannot.
27

What is the difference between pass, continue, and break?

  • pass - does nothing. Placeholder for empty code blocks.
  • continue - skips the rest of the current loop iteration and moves to the next.
  • break - exits the loop entirely.
28

What is the difference between try/except/else/finally?

  • try - code that might raise an exception.
  • except - handles the exception.
  • else - runs if no exception was raised.
  • finally - always runs, whether or not an exception occurred. Used for cleanup.
Example
try:\n  result = risky_operation()\nexcept ValueError as e:\n  handle_error(e)\nelse:\n  process_result(result)\nfinally:\n  cleanup()
29

What is the difference between raise and assert?

  • raise - explicitly raises an exception. Used for error handling.
  • assert condition, message - raises AssertionError if condition is False. Used for debugging and testing. Can be disabled with python -O.
Example
if age < 0:\n  raise ValueError("Age cannot be negative")\n\nassert age >= 0, "Age must be non-negative"
30

What is the with statement and context managers?

The with statement ensures proper resource cleanup using context managers (__enter__ and __exit__ methods). Commonly used for file handling, database connections, and locks.

Example
with open("file.txt", "r") as f:\n  data = f.read()\n# file is automatically closed\n\n# Custom context manager\nfrom contextlib import contextmanager\n@contextmanager\ndef timer():\n  start = time.time()\n  yield\n  print(f"Elapsed: {time.time() - start}s")
31

What is the difference between __getattr__ and __getattribute__?

  • __getattribute__(self, name) - called for every attribute access. Can cause infinite recursion if not careful.
  • __getattr__(self, name) - called only when the attribute is not found via normal lookup. Safer fallback mechanism.
32

What is the difference between pickle and JSON?

  • pickle - Python-specific binary serialization. Can serialize almost any Python object including functions. Not secure - do not unpickle untrusted data.
  • JSON - text-based, language-agnostic. Only supports basic types (dict, list, str, int, float, bool, None). Secure and portable.
Example
import pickle, json\ndata = {"name": "Alice", "age": 30}\npickle.dumps(data)  # binary\njson.dumps(data)    # text
33

What is the difference between enumerate() and range()?

  • range(n) - generates a sequence of numbers from 0 to n-1.
  • enumerate(iterable, start=0) - returns (index, value) pairs from an iterable.
Example
for i in range(len(items)):\n  print(i, items[i])\n\n# Better with enumerate\nfor i, item in enumerate(items):\n  print(i, item)
34

What is the difference between zip() and itertools.zip_longest()?

  • zip(*iterables) - stops when the shortest iterable is exhausted.
  • itertools.zip_longest(*iterables, fillvalue=None) - continues until the longest iterable is exhausted, filling missing values.
Example
a = [1, 2, 3]\nb = ["a", "b"]\nlist(zip(a, b))  # [(1,"a"), (2,"b")]\n\nfrom itertools import zip_longest\nlist(zip_longest(a, b, fillvalue="-"))  # [(1,"a"), (2,"b"), (3,"-")]
35

What is the difference between any() and all()?

  • any(iterable) - returns True if at least one element is truthy.
  • all(iterable) - returns True only if all elements are truthy.
Example
print(any([False, 0, 1]))  # True\nprint(all([True, 1, "a"]))  # True\nprint(all([True, 0, "a"]))  # False
36

What is the difference between sort() and sorted()?

  • list.sort() - sorts the list in place. Returns None. Modifies the original list.
  • sorted(iterable) - returns a new sorted list. Does not modify the original.
Example
a = [3, 1, 2]\na.sort()       # a is now [1, 2, 3]\n\nb = [3, 1, 2]\nc = sorted(b)  # b unchanged, c is [1, 2, 3]
37

What is the difference between join() and split()?

  • str.split(sep) - splits a string into a list of substrings.
  • sep.join(iterable) - joins elements of an iterable into a single string with sep as separator.
Example
s = "a,b,c"\nparts = s.split(",")  # ["a", "b", "c"]\njoined = ",".join(parts)  # "a,b,c"
38

What is the difference between __call__ and regular methods?

__call__ makes an instance callable like a function. Regular methods are called with dot notation.

Example
class Multiplier:\n  def __init__(self, factor): self.factor = factor\n  def __call__(self, x): return x * self.factor\n\ndouble = Multiplier(2)\nprint(double(5))  # 10 - instance called like a function
39

What is the difference between staticmethod, classmethod, and instance method?

  • Instance method - receives self. Can access instance and class variables.
  • @classmethod - receives cls. Can access class variables, cannot access instance variables. Used for factory methods.
  • @staticmethod - receives neither self nor cls. Cannot access instance or class variables. Just a utility function.
40

What is the difference between __init__.py and regular Python files?

__init__.py marks a directory as a Python package, allowing imports from it. It can be empty or contain package initialization code. Python 3.3+ supports namespace packages without __init__.py, but it is still recommended for explicit package definition.

41

What is the difference between import module and from module import name?

  • import module - imports the entire module. Access members with module.name.
  • from module import name - imports specific names directly into the current namespace.
  • from module import * - imports all public names (avoid - pollutes namespace).
Example
import math\nmath.sqrt(16)\n\nfrom math import sqrt\nsqrt(16)
42

What is the difference between __name__ == "__main__" and module-level code?

Code under if __name__ == "__main__": only runs when the script is executed directly, not when imported as a module. Module-level code (outside the if) runs on both direct execution and import.

Example
def main():\n  print("Running main")\n\nif __name__ == "__main__":\n  main()  # only runs when script is executed directly
43

What is the difference between *args unpacking and **kwargs unpacking?

  • *iterable - unpacks an iterable into positional arguments.
  • **dict - unpacks a dict into keyword arguments.
Example
def func(a, b, c): print(a, b, c)\n\nargs = [1, 2, 3]\nfunc(*args)  # unpacks to func(1, 2, 3)\n\nkwargs = {"a": 1, "b": 2, "c": 3}\nfunc(**kwargs)  # unpacks to func(a=1, b=2, c=3)
44

What is the difference between type() and isinstance()?

  • type(obj) - returns the exact type of obj. Does not consider inheritance.
  • isinstance(obj, class) - checks if obj is an instance of class or any subclass. Respects inheritance.
  • Always prefer isinstance() for type checking.
Example
class Animal: pass\nclass Dog(Animal): pass\nd = Dog()\nprint(type(d) == Dog)        # True\nprint(type(d) == Animal)     # False\nprint(isinstance(d, Animal)) # True
45

What is the difference between dict.get() and dict[key]?

  • dict[key] - raises KeyError if key does not exist.
  • dict.get(key, default) - returns default (None if not specified) if key does not exist. Safer.
Example
d = {"name": "Alice"}\nprint(d["age"])       # KeyError\nprint(d.get("age"))   # None\nprint(d.get("age", 0)) # 0
46

What is the difference between itertools.chain() and list concatenation?

itertools.chain(*iterables) creates a lazy iterator that chains multiple iterables without creating a new list in memory. list1 + list2 creates a new list immediately. Use chain() for memory efficiency with large iterables.

Example
from itertools import chain\nfor item in chain([1,2], [3,4], [5,6]):\n  print(item)  # 1,2,3,4,5,6 - no intermediate list created
47

What is the difference between collections.defaultdict and regular dict?

defaultdict automatically creates a default value for missing keys using a factory function. Regular dict raises KeyError for missing keys.

Example
from collections import defaultdict\n\n# Regular dict\nd = {}\nd["key"] += 1  # KeyError\n\n# defaultdict\nd = defaultdict(int)  # int() returns 0\nd["key"] += 1  # works, d["key"] is now 1
48

What is the difference between collections.Counter and dict?

Counter is a dict subclass for counting hashable objects. It provides convenient methods like most_common(), elements(), and arithmetic operations on counts.

Example
from collections import Counter\nc = Counter(["a", "b", "a", "c", "a"])\nprint(c)  # Counter({"a": 3, "b": 1, "c": 1})\nprint(c.most_common(2))  # [("a", 3), ("b", 1)]
49

What is the difference between collections.namedtuple and dataclasses?

  • namedtuple - immutable, lightweight, tuple-like. Access fields by name or index.
  • dataclass (Python 3.7+) - mutable by default, more features (default values, type hints, methods). Generates __init__, __repr__, __eq__ automatically.
Example
from collections import namedtuple\nPoint = namedtuple("Point", ["x", "y"])\np = Point(1, 2)\n\nfrom dataclasses import dataclass\n@dataclass\nclass Point:\n  x: int\n  y: int = 0  # default value
50

What is the difference between f-strings, format(), and % formatting?

  • % formatting - oldest, C-style. "Hello %s" % name.
  • str.format() - more powerful. "Hello {}".format(name).
  • f-strings (Python 3.6+) - fastest, most readable. f"Hello {name}". Supports expressions.
Example
name = "Alice"\nage = 30\nprint(f"{name} is {age} years old")  # f-string (preferred)\nprint("{} is {} years old".format(name, age))\nprint("%s is %d years old" % (name, age))

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.