
1. Basic Python Concepts
Q1. What is Python and why is it popular?ย Python is a high-level, interpreted, general-purpose programming language known for its clean, readable syntax and vast standard library. It is popular because it reduces development time significantly, supports multiple programming paradigms (procedural, OOP, functional), and has one of the largest ecosystems of third-party libraries – making it the go-to language for web development, data science, automation, AI/ML, and scripting.
Q2. What is the difference between interpreted and compiled languages? Where does Python fit? A compiled language (like C or C++) converts the entire source code to machine code before execution. An interpreted language executes code line by line at runtime. Python is interpreted – the Python interpreter reads and executes code directly without a separate compilation step, which makes development faster but generally slower at runtime than compiled languages.
Q3. What are Python’s key features?
- Dynamically typed – variable types are determined at runtime
- Strongly typed – implicit type conversion is not allowed between incompatible types
- Interpreted – executed line by line
- Object-oriented – supports classes and inheritance
- Multi-paradigm – supports OOP, functional, and procedural styles
- Garbage collected – automatic memory management
- Cross-platform – runs on Windows, Linux, macOS without modification
Q4. What is PEP 8? PEP 8 is Python’s official style guide – a set of conventions for writing readable Python code. Key rules include 4-space indentation (not tabs), maximum line length of 79 characters, two blank lines before and after class/function definitions, lowercase with underscores for variable and function names (snake_case), and CamelCase for class names. Following PEP 8 is expected in professional Python codebases.
Q5. What is the difference between is and == in Python? == checks value equality – whether two objects have the same value. is checks identity – whether two variables point to the exact same object in memory.
python
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True - same values
print(a is b) # False - different objects in memory
c = a
print(a is c) # True - same object
Use is only for comparing to None (if x is None), not for general value comparison.
2. Data Types and Data Structures
Q6. What are Python’s built-in data types?
| Category | Types |
|---|---|
| Numeric | int, float, complex |
| Text | str |
| Sequence | list, tuple, range |
| Mapping | dict |
| Set | set, frozenset |
| Boolean | bool |
| Binary | bytes, bytearray |
| None | NoneType |
Q7. What is the difference between a list, tuple, and set?
| Feature | List | Tuple | Set |
|---|---|---|---|
| Mutable | Yes | No | Yes |
| Ordered | Yes | Yes | No |
| Duplicates | Yes | Yes | No |
| Syntax | [1,2,3] | (1,2,3) | {1,2,3} |
Use lists when you need a mutable ordered collection. Use tuples for fixed data that should not change (coordinates, RGB values). Use sets when you need uniqueness or fast membership testing.
Q8. What is a dictionary and when would you use it? A dictionary is an unordered (Python 3.7+ maintains insertion order) collection of key-value pairs. Keys must be unique and hashable. Dictionaries offer O(1) average-time lookup by key – making them ideal for any situation where you need to map one piece of data to another (e.g., a user profile, configuration settings, frequency counting).
python
student = {"name": "Ravi", "age": 22, "score": 91.5}
print(student["name"]) # Ravi
student["city"] = "Hyderabad" # Add new key
Q9. What is the difference between deepcopy and shallow copy? A shallow copy creates a new object but copies references to the objects inside it – so nested mutable objects are shared between the original and the copy. A deep copycreates a completely independent copy – all nested objects are also copied recursively.
python
import copy
original = [[1, 2], [3, 4]]
shallow = copy.copy(original)
deep = copy.deepcopy(original)
original[0][0] = 99
print(shallow[0][0]) # 99 - affected by change
print(deep[0][0]) # 1 - completely independent
Q10. How do you remove duplicates from a list while preserving order?
python
# Method 1 - Using dict.fromkeys (Python 3.7+, preserves order)
lst = [3, 1, 2, 1, 3, 4]
result = list(dict.fromkeys(lst))
print(result) # [3, 1, 2, 4]
# Method 2 - Manual loop
seen = set()
result = []
for item in lst:
if item not in seen:
result.append(item)
seen.add(item)
3. Functions
**Q11. What are *args and kwargs? *args allows a function to accept any number of positional arguments as a tuple. **kwargs allows a function to accept any number of keyword arguments as a dictionary.
python
def show(*args, **kwargs):
print(args) # ('a', 'b', 'c')
print(kwargs) # {'x': 1, 'y': 2}
show('a', 'b', 'c', x=1, y=2)
Q12. What is a lambda function? A lambda is an anonymous, single-expression function defined inline. It is useful for short throwaway functions, especially as arguments to map(), filter(), or sorted().
python
square = lambda x: x ** 2
print(square(5)) # 25
numbers = [3, 1, 4, 1, 5, 9]
print(sorted(numbers, reverse=True)) # [9, 5, 4, 3, 1, 1]
# Lambda with sorted key
people = [("Ravi", 25), ("Priya", 22), ("Arun", 28)]
sorted_people = sorted(people, key=lambda x: x[1])
Q13. What is the difference between map(), filter(), and reduce()?
map(func, iterable)– appliesfuncto every element and returns a map objectfilter(func, iterable)– returns elements for whichfuncreturns Truereduce(func, iterable)– cumulatively appliesfuncto reduce the iterable to a single value (requiresfrom functools import reduce)
python
nums = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, nums)) # [1, 4, 9, 16, 25]
evens = list(filter(lambda x: x%2==0, nums)) # [2, 4]
from functools import reduce
total = reduce(lambda x, y: x+y, nums) # 15
Q14. What is a decorator in Python? A decorator is a function that takes another function as input, adds behaviour to it, and returns the modified function – without changing the original function’s code. Decorators use the @ syntax and are widely used for logging, authentication, timing, and caching.
python
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"Done {func.__name__}")
return result
return wrapper
@log_call
def greet(name):
print(f"Hello, {name}!")
greet("Ravi")
# Calling greet
# Hello, Ravi!
# Done greet
Q15. What is a generator and how is it different from a regular function? A generator is a function that uses yieldinstead of return. It does not compute all values at once – it produces values one at a time, only when requested (lazy evaluation). This makes generators memory-efficient for large sequences.
python
def count_up(n):
for i in range(n):
yield i
gen = count_up(1000000)
print(next(gen)) # 0 - only one value computed at a time
print(next(gen)) # 1
A regular function with return computes the full result and stores it in memory. A generator produces values on demand.
4. Object-Oriented Programming
Q16. What are the four pillars of OOP in Python?
- Encapsulation – bundling data and methods together inside a class, and restricting direct access to internal state using private/protected attributes
- Inheritance – a child class inherits attributes and methods from a parent class, enabling code reuse
- Polymorphism – the same method name behaves differently depending on the object it is called on
- Abstraction – hiding internal implementation details and exposing only what is necessary
Q17. What is the difference between __init__ and __new__? __new__ creates the instance (allocates memory). __init__initialises it (sets attributes). In virtually all standard Python code, you only override __init__. __new__ is rarely overridden except when subclassing immutable types like int or str, or implementing singleton patterns.
python
class Dog:
def __init__(self, name, breed):
self.name = name
self.breed = breed
def bark(self):
return f"{self.name} says: Woof!"
dog = Dog("Tommy", "Labrador")
print(dog.bark()) # Tommy says: Woof!
Q18. What are @classmethod and @staticmethod?
python
class Counter:
count = 0
def __init__(self):
Counter.count += 1
@classmethod
def get_count(cls):
# Receives the class as first argument (cls)
# Can access and modify class state
return cls.count
@staticmethod
def description():
# Receives no implicit first argument
# Cannot access class or instance state
return "This class counts instances"
Counter()
Counter()
print(Counter.get_count()) # 2
print(Counter.description()) # This class counts instances
Use @classmethod when the method needs to access or modify class-level state. Use @staticmethod for utility functions that logically belong to the class but do not depend on class or instance data.
Q19. What is method resolution order (MRO) in Python? MRO determines the order in which Python searches for methods in a class hierarchy – especially relevant in multiple inheritance. Python uses the C3 linearisation algorithm. You can view it with ClassName.__mro__ or ClassName.mro().
python
class A:
def method(self): print("A")
class B(A):
def method(self): print("B")
class C(A):
def method(self): print("C")
class D(B, C):
pass
D().method() # B - follows MRO: D โ B โ C โ A
print(D.__mro__) # (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
5. Error Handling and File I/O
Q20. How does Python handle exceptions?
python
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
except (ValueError, TypeError) as e:
print(f"Value/Type error: {e}")
else:
# Runs only if no exception was raised
print(f"Result: {result}")
finally:
# Always runs - for cleanup
print("Execution complete")
Always catch specific exceptions rather than using a bare except: – catching all exceptions silently hides bugs.
Q21. What is the difference between raise and raise from? raise re-raises an exception or raises a new one. raise ... from ...chains exceptions – it explicitly links a new exception to the original one, preserving the full error context in the traceback.
python
try:
int("abc")
except ValueError as e:
raise RuntimeError("Conversion failed") from e
Q22. How do you read and write files in Python?
python
# Writing a file
with open("data.txt", "w") as f:
f.write("Hello, Python!\n")
f.write("Line 2")
# Reading entire file
with open("data.txt", "r") as f:
content = f.read()
# Reading line by line (memory efficient)
with open("data.txt", "r") as f:
for line in f:
print(line.strip())
Always use the with statement for file operations – it ensures the file is properly closed even if an exception occurs.
6. Python Internals
Q23. What is a mutable vs immutable type in Python? Immutable types cannot be changed after creation – int, float, str, tuple, frozenset. Mutable types can be modified in place – list, dict, set. This distinction matters when passing objects to functions – mutable objects are passed by reference and modifications inside the function affect the original.
python
# Immutable - original unchanged
def add_one(n):
n += 1
x = 5
add_one(x)
print(x) # Still 5
# Mutable - original changed
def append_item(lst):
lst.append(99)
nums = [1, 2, 3]
append_item(nums)
print(nums) # [1, 2, 3, 99]
Q24. What are list comprehensions and when should you use them? List comprehensions provide a concise, readable way to create lists from existing iterables – often replacing 3-4 lines of loop code with a single expressive line. They are generally faster than equivalent for-loops because they are optimised at the C level.
python
# Traditional
squares = []
for x in range(10):
if x % 2 == 0:
squares.append(x**2)
# List comprehension - same result, one line
squares = [x**2 for x in range(10) if x % 2 == 0]
# [0, 4, 16, 36, 64]
# Dict comprehension
word_lengths = {word: len(word) for word in ["Python", "Java", "Go"]}
# {'Python': 6, 'Java': 4, 'Go': 2}
Q25. What is the Global Interpreter Lock (GIL)? The GIL is a mutex in CPython (the standard Python interpreter) that allows only one thread to execute Python bytecode at a time – even on multi-core systems. This means Python threads do not achieve true parallel execution for CPU-bound tasks. For CPU-bound work, use multiprocessing (separate processes bypass the GIL). For I/O-bound work (network calls, file reads), multithreading works fine because threads release the GIL while waiting for I/O.
7. Common Coding Questions
Q26. How do you reverse a string in Python?
python
s = "Python"
print(s[::-1]) # nohtyP - slicing (fastest, most Pythonic)
print("".join(reversed(s))) # nohtyP - using reversed()
Q27. How do you check if a string is a palindrome?
python
def is_palindrome(s):
s = s.lower().replace(" ", "")
return s == s[::-1]
print(is_palindrome("racecar")) # True
print(is_palindrome("A man a plan a canal Panama")) # True
print(is_palindrome("python")) # False
Q28. How do you find the most frequent element in a list?
python
from collections import Counter
nums = [1, 3, 2, 1, 4, 1, 3, 2, 1]
c = Counter(nums)
print(c.most_common(1)[0][0]) # 1
# Manual approach
print(max(nums, key=nums.count)) # 1
Q29. How do you merge two dictionaries in Python 3.9+?
python
a = {"x": 1, "y": 2}
b = {"y": 99, "z": 3}
# Python 3.9+ - merge operator
merged = a | b
print(merged) # {'x': 1, 'y': 99, 'z': 3}
# Python 3.5+ - unpacking
merged = {**a, **b}
# In-place update
a.update(b)
When keys overlap, the right-hand dictionary’s value wins.
Q30. What is the time complexity of common Python operations?
| Operation | List | Dict | Set |
|---|---|---|---|
| Access by index | O(1) | – | – |
| Search | O(n) | O(1) avg | O(1) avg |
| Insert at end | O(1) amortized | O(1) avg | O(1) avg |
| Insert at start | O(n) | – | – |
| Delete | O(n) | O(1) avg | O(1) avg |
| Membership test | O(n) | O(1) avg | O(1) avg |
Are you looking for Job Opportunities
๐ Check latest IT Jobs