We have curated a list of all Python Interview Questions which are recently asked in HCL company. These HCL Python Interview Questions consist interview questions with detailed answers.
1. What are the key features of Python and where is it typically used?
Python is an interpreted, high-level, dynamically typed language with simple syntax, rich standard library, and strong ecosystem. It supports multiple paradigms (procedural, OOP, functional). Common uses: web backends, scripting/automation, data science, ML, testing, DevOps, and quick prototyping.
2. Explain the main differences between Python 2 and Python 3.
Python 3 improved Unicode support (strings are Unicode), changed print to a function, integer division (/ returns float, // floor-divides), and removed old constructs. Python 2 is end-of-life—use Python 3 for new projects.
3. What is PEP 8 and why follow it?
PEP 8 is the official Python style guide recommending naming, indentation, line length, imports ordering, etc. Following it improves code readability, maintainability, and team consistency.
4. Explain mutable vs immutable types with examples.
Mutable types (can change in place): list, dict, set, bytearray.
Immutable types (cannot change): int, float, str, tuple, frozenset.
Mutability affects aliasing and function behavior (in-place modifications vs returning new objects).
5. How does Python memory management work?
CPython uses reference counting plus a cyclic garbage collector for unreachable cycles. Objects are on a private heap; small-object allocators and memory pools reduce fragmentation. You can tune/inspect via the gc module.
6. What is the GIL (Global Interpreter Lock) and how does it affect threading?
GIL is a mutex in CPython that allows only one thread to execute Python bytecode at a time. It limits CPU-bound parallelism with threads; threads remain useful for I/O-bound tasks. Use multiprocessing or C extensions to bypass GIL for CPU-bound work.
7. Difference between `is` and `==`?
== compares value equality (calls __eq__), while is compares object identity (same object in memory). Example: two equal lists == True but is False.
8. How do you create and use virtual environments?
Create with python -m venv envname. Activate: source envname/bin/activate (Linux/macOS) or envname\Scripts\activate (Windows). Install packages inside with pip. Deactivate with deactivate. Use pip freeze > requirements.txt to capture deps.
9. What are list comprehensions? Give an example with a condition.
Concise syntax to build lists from iterables with optional filtering.
evens = [x for x in range(10) if x % 2 == 0]
10. What is a decorator? Write a simple logging decorator.
A decorator wraps a function to extend behavior without modifying it.
def log_calls(fn): def wrapper(*args, **kwargs): print(f"Calling {fn.__name__}") return fn(*args, **kwargs) return wrapper @log_calls def greet(name): return f"Hello, {name}"
11. Explain `*args` and `**kwargs`.
*args collects extra positional args as a tuple; **kwargs collects extra keyword args as a dict. Useful for flexible APIs and forwarding arguments.
12. How does exception handling work (`try/except/else/finally`)?
try runs risky code; except handles exceptions; else runs if no exception; finally runs always (cleanup). Example flow: try → except (if error) → else (if no error) → finally (always).
13. What is a generator? How does `yield` help?
A generator is a function that yields values one at a time and maintains internal state, enabling lazy, memory-efficient iteration. Use yield to emit values instead of returning a list.
14. Differences: `@staticmethod`, `@classmethod`, instance method?
Instance methods get self; operate on instance.
@classmethod gets cls; operate on class/state.
@staticmethod receives no implicit first arg; utility function inside class namespace.
15. How do `map`, `filter`, and `reduce` differ?
map(fn, seq) applies fn to each item.
filter(fn, seq) keeps items where fn(item) True.
functools.reduce(fn, seq) reduces sequence to a single value by cumulative application.
16. How to handle files safely? Use context managers.
Use with open(…) as f: to ensure files close automatically, even on errors.
with open('data.txt') as f: for line in f: process(line)
17. Difference between `__str__` and `__repr__`?
__repr__ should be unambiguous (developer-facing) and ideally evaluable; __str__ is user-friendly. If only __repr__ exists, it’s used as fallback.
18. Shallow copy vs deep copy — when to use `copy.deepcopy()`?
Shallow copy copies top-level container but shares nested objects. Deep copy recursively copies nested objects. Use deepcopy when you need fully independent nested structures.
19. Remove duplicates from a list while preserving order.
Use seen set:
def dedupe(seq): seen = set() out = [] for x in seq: if x not in seen: seen.add(x) out.append(x) return out
Or list(dict.fromkeys(seq)) (maintains insertion order).
20. How to sort a dictionary by value?
Use sorted with a key:
sorted_items = sorted(d.items(), key=lambda kv: kv[1]) sorted_dict = {k: v for k, v in sorted_items}
21. What are modules and packages? How does importing work?
A module is a .py file. A package is a directory (often with __init__.py). import module loads and executes the module, caching it in sys.modules. Use absolute or relative imports within packages.
22. What is monkey patching? Test use-case and dangers.
Monkey patching modifies code at runtime (e.g., replacing a function in a library during tests). Useful for mocking, but risky in production—can create hidden side effects and maintenance issues.
23. How do you debug Python applications? Tools/techniques.
Use pdb or ipdb, IDE debuggers, logging (logging module), print debugging when quick. For complex issues, use stack traces, unit tests, and profilers.
24. How to profile Python code? Name tools.
Use cProfile, profile, pyinstrument, line_profiler (for line-level), and visualization tools like snakeviz. Identify hotspots and optimize algorithms or use C-accelerated libraries.
25. Palindrome check (ignore punctuation and case) — example.
import re def is_palindrome(s): cleaned = re.sub(r'[^A-Za-z0-9]', '', s).lower() return cleaned == cleaned[::-1]
26. Difference between `list.sort()` and `sorted()`?
list.sort() sorts in-place and returns None. sorted() returns a new list and leaves original intact. Both accept key and reverse.
27. Merge two sorted lists without using built-ins (merge step).
def merge(a, b): i = j = 0 out = [] while i < len(a) and j < len(b): if a[i] <= b[j]: out.append(a[i]); i += 1 else: out.append(b[j]); j += 1 out.extend(a[i:]) out.extend(b[j:]) return out
28. Explain multiple inheritance and MRO (method resolution order).
Python uses C3 linearization to compute MRO, ensuring consistent order without duplicates. Inspect with Class.mro() or Class.__mro__. MRO determines which method is used in diamond patterns.
29. What is `__slots__` and when would you use it?
__slots__ declares fixed attributes for instances to avoid per-instance __dict__, saving memory and slightly speeding attribute access. Use for many small objects; complicates dynamic attribute addition and some inheritance.
30. Implement a thread-safe singleton (sketch).
Use a metaclass with a lock:
import threading class SingletonMeta(type): _instances = {} _lock = threading.Lock() def __call__(cls, *args, **kwargs): with cls._lock: if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls]
31. Useful `collections` types: `namedtuple`, `deque`, `defaultdict`, `Counter` — examples.
namedtuple: lightweight records.
deque: fast append/pop both ends.
defaultdict: auto default values for missing keys.
Counter: frequency counting with most_common().
32. What is `functools.lru_cache`?
A decorator that caches function results by arguments (LRU eviction). Great for expensive pure functions (e.g., recursive Fibonacci) to avoid recomputation.
33. Explain `async` / `await` and when to use `asyncio`.
async def defines coroutines; await suspends until awaitable completes. Use asyncio for high-concurrency I/O-bound applications (many open connections) with cooperative scheduling; use threads/processes for CPU-bound tasks.
34. `multiprocessing` vs `threading` — when to use each?
threading shares memory, good for I/O-bound tasks. multiprocessing spawns processes (separate memory) to bypass GIL—use for CPU-bound parallelism.
35. Simple LRU cache implementation approach.
Use collections.OrderedDict / dict (3.7+) and move_to_end() to track recency. On get, move key to end; on put, evict popitem(last=False) when over capacity.
36. How to serialize `datetime` or custom classes to JSON?
Provide a custom encoder or convert fields before json.dumps():
import json, datetime class DateEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return obj.isoformat() return super().default(obj)
37. Why is unpickling untrusted data dangerous and how to mitigate?
Unpickling can execute arbitrary code from crafted byte streams. Never unpickle untrusted input. Prefer JSON or use restricted/untrusted-safe serializers or validate inputs strictly.
38. Count top-k frequent error codes from a huge log file (streaming approach).
Read file line-by-line, parse code, update collections.Counter(); use most_common(k) at end. For extreme scale, use external map-reduce, partitioning, or approximate sketches (Count-Min Sketch).
39. Find two numbers closest to a target — approach.
Sort and use two pointers (left, right). Move pointers depending on sum relative to target. O(n log n) due to sort, O(n) two-pointer pass.
40. What is a closure? Practical use-case.
Closure: inner function captures variables from enclosing scope even after outer returns. Useful for factories and callbacks.
def make_multiplier(n): def mul(x): return x * n return mul times3 = make_multiplier(3)
41. What are descriptors and how do they relate to `property`?
Descriptors implement __get__, __set__, __delete__ to control attribute access. property is a descriptor that wraps getter/setter methods for managed attributes (validation, computed properties).
42. Implement retry with exponential backoff — short sketch.
Use a decorator that catches exceptions and sleeps base * 2**attempt (with jitter) between retries, up to max_attempts. Example pattern used for network calls.
43. Running median of a stream — efficient technique?
Maintain two heaps: a max-heap for lower half and min-heap for upper half; balance sizes. Insertion O(log n), median retrieval O(1).
44. How to dynamically import a module/class by string name?
Use importlib:
import importlib m = importlib.import_module('mypkg.mymodule') Cls = getattr(m, 'MyClass') inst = Cls()
45. `bytes`, `bytearray`, `memoryview` — differences and zero-copy use-case.
bytes immutable, bytearray mutable. memoryview views underlying buffer without copying—useful for slicing large binary buffers efficiently (zero-copy).
46. Connect Python to a relational DB — patterns (pooling, ORM vs raw SQL).
Use a DB driver (psycopg2 for Postgres), connection pooling (e.g., sqlalchemy.pool), and ORM (SQLAlchemy) or parameterized raw SQL. Use transactions, parameterized queries to prevent SQL injection.
47. How to write unit tests — example with `unittest` or `pytest`.
Example unittest:
import unittest from mymodule import add class TestAdd(unittest.TestCase): def test_add(self): self.assertEqual(add(2, 3), 5) if __name__ == '__main__': unittest.main()
48. Behavioral: How would you describe optimizing Python code you worked on?
Structure answer with: context (what was slow), measurement (profiling tool and hotspot), action (algorithm change, caching, native libs), and result (performance improvement with numbers).
49. Design a simple REST endpoint in Flask/FastAPI that accepts JSON and validates it.
Sketch (FastAPI recommended for built-in validation with Pydantic):
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class Item(BaseModel): name: str price: float @app.post("/items") def create_item(item: Item): return {"status": "ok", "item": item}
Production: add auth, rate-limit, input size checks, logging, and schema versioning.
50. How do you secure a Python web app?
Use HTTPS/TLS, validate & sanitize inputs, use parameterized DB queries to prevent SQL injection, implement proper auth/authorization (JWT/OAuth), manage secrets securely, enable rate-limiting, set secure headers, and use vulnerability scanning/patching.
HCL Python coding questions
1. Reverse a String Without Using Built-in Functions
Logic: Use slicing or loop.
def reverse_string(s):
rev = ''
for ch in s:
rev = ch + rev
return rev
print(reverse_string("HCLPython")) # Output: nohtyPLCH
2. Check if a String is a Palindrome
Logic: Compare string with its reverse.
def is_palindrome(s):
s = s.lower().replace(" ", "")
return s == s[::-1]
print(is_palindrome("Level")) # True
3. Find Factorial of a Number (Iterative and Recursive)
# Iterative
def factorial(n):
res = 1
for i in range(1, n+1):
res *= i return res
# Recursive
def fact_recursive(n):
return 1 if n == 0 else n * fact_recursive(n-1)
4. Count Frequency of Each Character in a String
from collections import Counter
s = "hello world"
freq = Counter(s)
print(freq) # {'h':1, 'e':1, 'l':3, 'o':2, ...}
5. Find Missing Number in an Array (1 to N)
Logic: Use sum formula.
def missing_number(arr):
n = len(arr) + 1
total = n * (n + 1) // 2
return total - sum(arr)
print(missing_number([1, 2, 4, 5])) # 3
6. Find Second Largest Element in a List
def second_largest(nums):
unique = list(set(nums))
unique.sort()
return unique[-2]
print(second_largest([10, 20, 4, 45, 99])) # 45
7. Print Fibonacci Series up to N
def fibonacci(n):
a, b = 0, 1
while a <= n:
print(a, end=" ")
a, b = b, a + b fibonacci(20)
8. Check if a Number is Prime
def is_prime(num): if num <= 1: return False for i in range(2, int(num ** 0.5) + 1): if num % i == 0: return False return True print(is_prime(29)) # True
9. Find All Duplicates in a List
def find_duplicates(lst): seen, dup = set(), set() for x in lst: if x in seen: dup.add(x) else: seen.add(x) return list(dup) print(find_duplicates([1,2,3,2,4,1])) # [1, 2]
10. Check for Anagrams
def are_anagrams(a, b): return sorted(a) == sorted(b) print(are_anagrams("listen", "silent")) # True
11. Find Pairs with Given Sum
def pair_sum(arr, target): seen = set() for num in arr: if target - num in seen: print(num, target - num) seen.add(num) pair_sum([1,4,7,3,9,2], 10)
12. Count Vowels and Consonants
def count_vowels_consonants(s): vowels = set("aeiouAEIOU") v = c = 0 for ch in s: if ch.isalpha(): if ch in vowels: v += 1 else: c += 1 return v, c print(count_vowels_consonants("HCL Python")) # (2, 6)
13. Sort a List of Tuples by Second Element
data = [(1, 3), (2, 1), (5, 2)] data.sort(key=lambda x: x[1]) print(data) # [(2,1), (5,2), (1,3)]
14. Find Intersection and Union of Two Lists
a = [1,2,3,4,5] b = [4,5,6,7] print("Intersection:", list(set(a) & set(b))) print("Union:", list(set(a) | set(b)))
15. Find the Longest Word in a Sentence
def longest_word(sentence): words = sentence.split() return max(words, key=len) print(longest_word("Python interview questions for HCL")) # 'interview'
Bonus Patterns HCL Commonly Asks:
Print pattern triangles (right, inverted, pyramid)
Reverse each word in a sentence
Find duplicates in string without using sets
Find common elements between two lists using loops
Write custom sorting using lambda (like sort names by length)