In short
Python is a high-level, dynamically typed, interpreted language in which everything is an object and names are only references to objects. Its small syntax, huge standard library and the NumPy/Pandas/Django/Flask ecosystem make it the default language for data, automation, testing, scripting and backend work in Indian IT services and product companies. It appears in first-year AICTE/CBCS "Programming for Problem Solving" and "Python Programming" papers, in the GATE Data Science and AI (DA) paper, and in almost every campus coding round (TCS NQT, Infosys, Wipro, Cognizant, Zoho, Accenture) where candidates may answer in Python. Interviewers test the object model - mutability, references, copying, scoping - far more than syntax.
Explained
Language model, execution and typing
- Interpreted and compiled: CPython compiles source to bytecode (cached in
__pycache__/*.pyc) and runs it on a stack-based virtual machine; there is no separate link step and no machine-code binary. - Implementations: CPython (reference), PyPy (JIT, faster loops), Jython, IronPython, MicroPython (microcontrollers). "Python" in exams means CPython 3.
- Dynamic typing: a *name* has no type; the *object* it points to does.
x = 5; x = "five"is legal. Types are checked at run time → flexibility, but errors surface late. - Strongly typed: no silent coercion between unrelated types -
"5" + 3raisesTypeError(unlike JavaScript). - Duck typing: usability depends on behaviour, not class - any object with
__iter__can be looped over. - Type hints (PEP 484):
def area(r: float) -> float:are *annotations only*; the interpreter does not enforce them at run time. Tools such as mypy check them statically. - Everything is an object: ints, functions, classes and modules all have identity (
id()), type (type()) and value. - Indentation is syntax (4 spaces by PEP 8); no braces, no semicolons needed. Mixing tabs and spaces raises
TabError. - Version notes: Python 2 reached end of life in 2020. Python 3 changed
printto a function,/to true division, made strings Unicode by default, and maderange/zip/maplazy. Newer features: f-strings (3.6),:=walrus (3.8), dict merge|(3.9),match/casestructural pattern matching (3.10). Exact version availability should be checked against the interpreter in use.
Built-in data types and mutability
- Numeric:
int(arbitrary precision - no overflow),float(IEEE-754 double, ~15-17 significant digits),complex,bool(a subclass ofint:True == 1), plusDecimal/Fraction(fromdecimal/fractions) for exact money/ratio work. - Sequences:
str(immutable Unicode),list(mutable, dynamic array),tuple(immutable, hashable if its items are),range,bytes/bytearray. - Sets:
set(mutable, unordered, unique, hashable members),frozenset(immutable, usable as a dict key). - Mapping:
dict- hash table; since Python 3.7 insertion order is guaranteed. Keys must be hashable, so a list cannot be a key but a tuple can. - Mutable vs immutable: mutable =
list,dict,set,bytearray, most user classes; immutable =int,float,str,tuple,frozenset,bytes. Immutables can be cached and shared safely; this is why small ints (−5 to 256) and short identifier-like strings are interned. - References, not copies: assignment binds a name to the same object.
b = aon a list meansb is a; mutating through either is visible through both (aliasing). - Copying:
b = a[:]orlist(a)orcopy.copy(a)= shallow (outer container new, inner objects shared);copy.deepcopy(a)= recursive copy. - Argument passing is "pass by object reference": rebinding a parameter inside a function does not affect the caller; mutating the object does.
- **
isvs==:**iscompares identity (same object),==compares value via__eq__. Useisonly withNone,True,False. - Truthiness:
0,0.0,"",[],{},(),set(),Noneare falsy; everything else is truthy.
Operators, strings and control flow
- Arithmetic:
/true division (always float),//floor division,%modulo,**power. Floor division rounds towards −∞, and%takes the sign of the divisor. - Chained comparison:
0 <= x < 10is valid and evaluatesxonce.and/orare short-circuiting and return an *operand*, not a bool. - Unpacking:
a, b = b, aswaps;first, *rest = lst;*argscollects positional arguments into a tuple,**kwargskeyword arguments into a dict. - Strings are immutable: every "modification" creates a new object. Key methods:
split,join,strip,replace,find,upper/lower,startswith,format,encode. Prefer f-strings:f"{name} scored {m:.2f}%". - Slicing
s[start:stop:step]-stopis exclusive, negative indices count from the end, out-of-range slices clip silently (noIndexError),s[::-1]reverses. - Control flow:
if/elif/else;while;for x in iterable(there is no C-style countedfor);break,continue,pass;for...else/while...elsewhere theelseblock runs only if the loop was not broken. - Comprehensions:
[f(x) for x in it if cond], plus set{...}, dict{k: v ...}and generator(...)forms - the idiomatic replacement for build-a-list loops; faster because a dedicated append opcode replaces the repeatedlst.appendattribute lookup and call. - Useful built-ins:
len, range, enumerate, zip, sorted, reversed, sum, min, max, any, all, abs, round, map, filter, isinstance, id, type, input, print. - **
sorted()is stable and returns a new list;**list.sort()sorts in place and returnsNone. Both takekey=andreverse=.
Functions, scope and iteration machinery
- Definition:
def f(a, b=2, *args, key=None, **kwargs):- order is positional, default, varargs, keyword-only, varkwargs. Defaults are evaluated once at definition time (the mutable-default trap). - First-class functions: functions are objects - assignable, passable, returnable.
lambda x: x*xis a single-expression anonymous function. - LEGB scope resolution: Local → Enclosing → Global → Built-in. Assigning to a name makes it local for the whole function unless declared
globalornonlocal. - Closures: a nested function remembers its enclosing variables; the basis of decorators -
@timeris simplyf = timer(f). - Iterator protocol: an *iterable* has
__iter__; an *iterator* has__next__and raisesStopIterationwhen exhausted.forloops call these internally. - Generators: functions containing
yieldreturn a lazy iterator; state is suspended and resumed, so memory is O(1) regardless of the sequence length. Generator expressions do the same inline. - Context managers:
with open(...) as f:guarantees cleanup via__enter__/__exit__, even on an exception - the standard way to handle files and locks. - Docstrings (first string in a module/function/class) are available as
__doc__and drivehelp(). - Mangling and conventions:
_xmeans "internal by convention",__xinside a class is name-mangled to_Class__x,__x__are dunder (special) methods. - Classes are declared with
class C:andselfas the explicit first parameter; the OO concepts themselves are covered in the object-oriented note, andtry/exceptin the exception-handling note.
Memory management, performance and concurrency
- Reference counting frees an object the moment its count hits zero; a generational garbage collector (
gcmodule) additionally breaks reference *cycles*. - Private heap: all objects live in a heap managed by the interpreter's allocator (pymalloc for small blocks); there is no manual
free. - **
del name** removes the binding, not necessarily the object. - GIL (Global Interpreter Lock): in CPython only one thread executes bytecode at a time. So
threadinghelps I/O-bound work (files, network, DB) but not CPU-bound work; usemultiprocessing, NumPy vectorisation or C extensions for CPU-bound work. (Experimental free-threaded builds exist from 3.13; treat as not yet the default.) - **
asyncio** gives single-threaded cooperative concurrency withasync def/awaitfor high-concurrency I/O. - Costs to know: attribute lookup, dynamic dispatch and object boxing make pure-Python loops roughly 10-100× slower than C; the fix is to push loops into NumPy/Pandas/C libraries, not to micro-tune Python.
- Complexity of built-ins (CPython):
| Operation | list | dict / set | str |
|---|---|---|---|
| index / key lookup | O(1) | O(1) average, O(n) worst | O(1) |
| append / add | O(1) amortised | O(1) average | immutable |
| insert / delete at front | O(n) | - | - |
membership in | O(n) | O(1) average | O(n·m) substring |
| sort | O(n log n) (Timsort) | - | - |
Modules, packages, files and the ecosystem
- Module = one
.pyfile; package = a directory importable as a module.import m,from m import x,import m as alias.sys.pathdecides where imports are searched. - **
if __name__ == "__main__":** runs a block only when the file is executed directly, not when imported - the standard script entry point. - Virtual environments:
python -m venv .venvisolates dependencies;pip install -r requirements.txtinstalls them; PyPI is the package index. Conda is common in data work. - File I/O:
with open("f.csv", "r", encoding="utf-8") as fh:thenfh.read(),.readline(), iteration overfh, or.write(). Modesr/w/a/xplusbfor binary. Always setencodingexplicitly - Windows defaults differ from Linux and break Indian-language text. - Standard library highlights:
os,pathlib,sys,math,random,datetime,json,csv,re,collections(Counter,defaultdict,deque,namedtuple),itertools,functools(lru_cache,reduce),dataclasses,sqlite3,unittest,logging,pickle,subprocess,argparse. - Third-party stack: NumPy, Pandas, Matplotlib, scikit-learn, requests, BeautifulSoup, Selenium, pytest, Django, Flask, FastAPI, PySpark, Streamlit.
- Style and quality: PEP 8 (layout and naming:
snake_casefunctions,CapWordsclasses,UPPER_CASEconstants), PEP 20 (Zen of Python), formattersblack/ruff, lintersflake8/pylint. Campus and on-the-job reviews in Indian service companies routinely check PEP 8 compliance.
Key points
- Everything is an object - names are references; assignment never copies the object.
- Mutable vs immutable - the single most examined distinction; drives aliasing, dict keys and default arguments.
- **
isvs==** - identity vs value;x is ycan be True for small ints purely due to interning. - Slicing -
stopis exclusive, negatives count from the end, slices clip instead of raisingIndexError. - List vs tuple - mutable, heavier, not hashable vs immutable, lighter, hashable.
- Dict and set - hash tables, O(1) average lookup; dicts preserve insertion order from 3.7.
- Shallow vs deep copy -
a[:]copies the outer container only;copy.deepcopycopies nested objects. - **
//floors towards −∞** and%takes the divisor's sign, unlike C's truncating integer division. - Floats are binary -
0.1 + 0.2 != 0.3; compare with a tolerance or useDecimalfor money. - LEGB - scope search order; assignment inside a function creates a local unless
global/nonlocal. - Default arguments are evaluated once - a mutable default persists across calls.
- Generators are lazy - constant memory, single-pass, cannot be indexed or reused.
- Comprehensions replace accumulate-in-a-loop code and are faster.
- **
with** guarantees resource cleanup through the context-manager protocol. - GIL - threads do not speed up CPU-bound Python; use processes or vectorised libraries.
- Reference counting plus cyclic GC manages memory; there is no explicit free.
- **
sorted()returns a list;.sort()returnsNone** - assigning the result of.sort()is a classic bug. - Type hints are not enforced at run time.
Formulas and examples
Example 1 - slicing arithmetic. s = "ABCDEFGHIJ" (indices 0-9).
s[2:8:3]→ indices 2, 5 (8 excluded) → "CF"; by formula ⌈(8−2)/3⌉ = ⌈2.0⌉ = 2 characters. ✓s[-4:-1]→ indices 6, 7, 8 → "GHI" (length 3).s[::-1]→ "JIHGFEDCBA";s[20:30]→ "" (clips, no error).len(range(3, 20, 4))= ⌈17/4⌉ = ⌈4.25⌉ = 5 → values 3, 7, 11, 15, 19. ✓
Example 2 - integer and float arithmetic traps.
7 / 2= 3.5;7 // 2= 3;-7 // 2= −4 (floored, not −3) and-7 % 2= 1, since −7 = 2×(−4) + 1. ✓7 % -2= −1 (sign of divisor), with7 // -2= −4: 7 = (−2)(−4) + (−1). ✓0.1 + 0.2= 0.30000000000000004, so0.1 + 0.2 == 0.3is False; usemath.isclose(0.1+0.2, 0.3)→ True.round(2.5)= 2,round(3.5)= 4 (banker's rounding, ties to even);round(2.675, 2)= 2.67 because 2.675 is stored slightly below.2**100works exactly (arbitrary-precision int) = 1267650600228229401496703205376.
Example 3 - cost of string concatenation. Build a 100,000-character string one character at a time.
- Naive
s += cin a loop: copies ≈ n²/2 = (10⁵)²/2 = 5 × 10⁹ characters. "".join(chars): one pass, 1 × 10⁵ characters copied → about 50,000× less work.
parts = [chr(65 + i % 26) for i in range(100_000)]
s = "".join(parts) # O(n)
Example 4 - aliasing, shallow copy and the mutable default.
grid = [[0] * 3] * 3 # 3 references to ONE row
grid[0][0] = 1
print(grid) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]
good = [[0] * 3 for _ in range(3)] # 3 independent rows
def add(x, bag=[]): # default created ONCE
bag.append(x); return bag
print(add(1), add(2)) # [1, 2] [1, 2] - shared list
def ok(x, bag=None):
bag = [] if bag is None else bag
bag.append(x); return bag
print(ok(1), ok(2)) # [1] [2]
grid[0] is grid[1] → True in the first case, False in good.
Example 5 - counting and sorting (typical placement question). Sentence: "data is the new oil and data is everywhere" → 9 words, 7 unique.
from collections import Counter
text = "data is the new oil and data is everywhere"
c = Counter(text.split())
top = sorted(c.items(), key=lambda kv: (-kv[1], kv[0]))
- Counts: data 2, is 2, and 1, everywhere 1, new 1, oil 1, the 1 (total 2+2+1+1+1+1+1 = 9). ✓
top[:3]→[('data', 2), ('is', 2), ('and', 1)]- the key sorts by descending count, then alphabetically.- Memory:
list(range(10**7))holds 10 million 28-byte int objects plus 8-byte pointers ≈ 360 MB on 64-bit CPython, while(x for x in range(10**7))stays at a few hundred bytes - figures are approximate and build-dependent.
| Type | Mutable | Ordered | Hashable | Typical use |
|---|---|---|---|---|
| list | Yes | Yes | No | ordered collection you modify |
| tuple | No | Yes | Yes (if items are) | fixed record, dict key, multiple return |
| set | Yes | No | No | membership tests, de-duplication |
| frozenset | No | No | Yes | set used as a dict key |
| dict | Yes | Insertion order (3.7+) | No | key → value mapping, JSON |
| str | No | Yes | Yes | text |
Where it is used
- IT services and automation: TCS, Infosys, Wipro, HCLTech, Cognizant and Capgemini use Python for ETL, report automation, log parsing, RPA glue and test automation (pytest, Selenium, Robot Framework).
- Data and AI roles: data analyst / data scientist / ML engineer work in Pandas, NumPy, scikit-learn and PyTorch at Flipkart, Swiggy, Zomato, PhonePe, Jio, banks and analytics firms; also the GATE DA syllabus.
- Backend and web: Django/Flask/FastAPI APIs for fintech and SaaS products; Razorpay/UPI integrations, Celery job queues, SQLAlchemy and
sqlite3/Postgres access. - DevOps, QA and security:
requests,paramiko,boto3, Ansible modules, CI scripts, scanning and log-analysis tooling. - Research and government: ISRO/DRDO/IMD simulation and data pipelines, NIC dashboards, NPTEL and SWAYAM courses, CBSE Class 11-12 Computer Science (Python is the prescribed language), and university first-year programming labs.
- Embedded and IoT: MicroPython/CircuitPython on ESP32 and Raspberry Pi projects in final-year B.Tech work.
Interview questions
- Q: Is Python pass by value or pass by reference? A: Neither exactly - it passes a reference to the object by value. Rebinding the parameter does not affect the caller; mutating a mutable object does.
- Q: Difference between a list and a tuple? A: A list is mutable and takes more memory; a tuple is immutable, slightly faster, and hashable so it can be a dict key or set member.
- Q:
isversus==? A:istests whether two names point to the same object;==tests equality of value. Small integers and interned strings may be identical by accident, so never useisfor value comparison. - Q: Why does a mutable default argument misbehave? A: Defaults are evaluated once when the function is defined, so the same list or dict is reused across calls; use
Noneas the default and create the object inside. - Q: Shallow copy versus deep copy? A: A shallow copy duplicates only the outer container and shares the nested objects;
copy.deepcopyrecursively duplicates everything. - Q: What is the GIL and when does it hurt? A: A lock that lets only one thread run Python bytecode at a time in CPython; it limits CPU-bound multithreading but not I/O-bound threads, where the lock is released during waits.
- Q: How does Python manage memory? A: Objects live in a private heap with reference counting for immediate reclamation, plus a generational garbage collector to break reference cycles.
- Q: Difference between a list and a generator? A: A list stores all elements in memory and can be indexed and reused; a generator produces values lazily on demand, uses constant memory and can be consumed only once.
- Q: Why is
0.1 + 0.2 == 0.3False? A: Floats are binary IEEE-754 approximations, so 0.1 and 0.2 cannot be represented exactly; compare withmath.iscloseor useDecimal. - Q: What do
*argsand**kwargsdo? A: They collect extra positional arguments into a tuple and extra keyword arguments into a dict, letting a function accept a variable signature. - Q: What does
if __name__ == "__main__":achieve? A: The block runs only when the file is executed as a script, so the module can be imported without side effects. - Q: How do you reverse a list and a string? A:
lst[::-1]orreversed(lst)(iterator) orlst.reverse()in place; for a string only slicing or"".join(reversed(s)), because strings are immutable.
Common mistakes
- Assuming
b = acopies a list, then being surprised that mutatingbchangesa. - Writing
lst = lst.sort()and gettingNone, or expectingsorted()to sort in place. - Using a mutable default argument, or
[[0]*n]*mfor a 2-D grid where all rows alias one list. - Modifying a list or dict while iterating over it, causing skipped items or
RuntimeError; iterate over a copy or build a new object. - Confusing
/with//, or expecting C-style truncation from-7 // 2and-7 % 2. - Comparing floats with
==, or usingisto compare numbers and strings. - Mixing tabs and spaces, mis-indenting a block, or forgetting the colon after
if,for,def- the commonest lab and exam syntax errors. - Opening files without
with(or withoutencoding="utf-8"), leaving handles open and mangling non-ASCII text.
Related topics
Object-oriented programming concepts · Exception handling and debugging · Functional programming basics · JavaScript essentials · Data structures with Python · Databases and SQL basics