Python


Core Python

1. What are decorators?

Answer: Decorators are functions that modify the behavior of another function or class without changing its source code. Commonly used for logging, authentication, timing, and caching.


2. @staticmethod vs @classmethod vs instance method

Instance method — takes self. Can access instance variables.

Class method — takes cls. Can access class variables. Use for alternative constructors.

Static method — takes neither. Utility function belonging to the class.


3. What is a generator?

Answer: A generator uses yield to return values one at a time instead of storing them all in memory, making it memory-efficient for large datasets.


4. Generator vs Iterator

Generator — created using yield, automatically implements iterator protocol.

Iterator — any object implementing __iter__() and __next__(). Can be manually implemented.


5. What is the GIL?

Answer: The Global Interpreter Lock allows only one thread to execute Python bytecode at a time in CPython. Makes CPU-bound multithreading ineffective, but I/O-bound multithreading still works fine.


6. How does Python memory management work?

Answer: Python uses reference counting and a cyclic garbage collector. Objects are freed when their reference count drops to zero. The GC handles circular references.


7. __new__() vs __init__()

__new__() creates the object. __init__() initializes it after creation.


8. What is __del__()?

Destructor called before garbage collection. Generally not recommended — use context managers instead.


9. Mutable vs Immutable

Mutable: list, dict, set

Immutable: int, float, tuple, str

Mutable objects can change after creation; immutable objects cannot.


10. Why are tuples hashable?

Tuples are immutable, so their hash value never changes, making them valid dictionary keys.


11. What are context managers?

Objects that manage resources automatically using with, ensuring cleanup even if exceptions occur. Implement __enter__() and __exit__().


12. List vs Tuple

ListTuple
MutabilityMutableImmutable
SpeedSlowerFaster
MemoryMoreLess
Use caseDynamic dataFixed data, dictionary keys

13. List comprehension vs Generator expression

List comprehension creates the full list in memory: [x*2 for x in range(100)]

Generator expression produces values lazily: (x*2 for x in range(100))


14. Deep Copy vs Shallow Copy

Shallow copy — copies references to nested objects. Modifying nested objects in the copy also modifies the original.

Deep copy — recursively copies all nested objects. Fully independent.


15. == vs is

== compares values. is compares object identity (memory address).

Use is for None checks: if result is None: (PEP 8).


16. Lambda functions

Anonymous one-line functions, mainly used with map, filter, and sorted.

sorted(users, key=lambda u: u["age"])

17. map(), filter(), reduce()

map() — applies a function to every element → same-length result.

filter() — keeps elements satisfying a condition → shorter result.

reduce() — aggregates all elements into one value (from functools).


18. *args and **kwargs

*args — variable positional arguments (tuple).

**kwargs — variable keyword arguments (dict).


19. Modules vs Packages

Module — single Python file (.py). Package — directory with __init__.py containing multiple modules.


OOP

20. Encapsulation

Bundling data and methods together while restricting direct access using private/protected members.


21. Inheritance (types)

Allows a class to reuse properties and methods from another class.

Single — one parent. Multiple — two or more parents. Multilevel — chain of inheritance. Hierarchical — multiple children from one parent.


22. Polymorphism

Same interface with different implementations. Different classes implement the same method differently.


23. Abstraction

Hides implementation details while exposing only required functionality. Implemented using Abstract Base Classes (ABC).

from abc import ABC, abstractmethod
 
class PaymentProcessor(ABC):
    @abstractmethod
    def process_payment(self, amount): pass
 
class StripePayment(PaymentProcessor):
    def process_payment(self, amount):
        print(f"Stripe: ${amount}")

Cannot instantiate PaymentProcessor directly — must implement all abstract methods.


24. Composition vs Inheritance

Inheritance — “is-a” relationship. Rigid hierarchy.

Composition — “has-a” relationship. Preferred for loose coupling.


25. Method Overloading vs Overriding

Python doesn’t support true method overloading (use default args instead).

Method overriding allows child classes to redefine parent methods.


26. MRO (Method Resolution Order)

Determines the order Python searches parent classes in multiple inheritance. Use ClassName.mro() to inspect.


27. Duck Typing

“If it behaves like a duck, it’s a duck.” Python focuses on object behavior rather than type. If an object has the required method, Python will call it — no inheritance required.


Advanced Python

28. __slots__

Restricts instance attributes to a fixed set, reducing memory usage per instance.

class Point:
    __slots__ = ['x', 'y']

29. What is a weakref?

A reference to an object that does not increment the reference count. The object can still be garbage collected. Used for caches and observer patterns to avoid memory leaks.


Concurrency

30. Thread vs Process

ThreadProcess
MemorySharedSeparate
WeightLightweightHeavyweight
Best forI/O-boundCPU-bound
GIL affectedYesNo

31. Multithreading vs Multiprocessing

Multithreading — best for I/O-bound work (API calls, DB queries, file I/O). Threads share memory and wait together.

Multiprocessing — best for CPU-bound work (image processing, data crunching). Each process bypasses the GIL.


32. Why doesn’t multithreading speed up CPU tasks?

Because of the GIL — only one thread executes Python bytecode at a time, regardless of core count.


33. What is asyncio?

Python framework for asynchronous programming using a single thread and an event loop. Tasks cooperatively yield control using await instead of blocking.


34. async vs await

async def — defines a coroutine (asynchronous function).

await — pauses the coroutine and yields control to the event loop without blocking.


35. Event Loop

Core component of asyncio. Continuously checks for ready tasks and runs them. Manages coroutines, futures, and I/O events.


36. Future vs Coroutine

Coroutine — function defined with async def. Contains the logic.

Future — a low-level placeholder representing a result that isn’t available yet. Modern code uses asyncio.create_task() which wraps coroutines into Tasks (a subclass of Future) automatically.


37. Thread-safe code

Code that avoids race conditions when multiple threads access shared resources concurrently. Achieved using synchronization mechanisms like threading.Lock() to ensure only one thread modifies the resource at a time, or by avoiding shared state altogether.


FastAPI & REST APIs

38. Why FastAPI over Flask?

FastAPI provides async support, automatic OpenAPI docs, Pydantic type validation, and better performance (ASGI vs WSGI).


39. What is Pydantic?

Library used by FastAPI for request validation and serialization using Python type hints. Invalid input raises a 422 automatically.

class UserCreate(BaseModel):
    name: str
    age: int
    email: EmailStr

40. Dependency Injection (Depends())

FastAPI’s Depends() allows reusable authentication, database sessions, and shared logic injected at the route level.

async def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
 
@app.get("/users")
async def list_users(db: Session = Depends(get_db)):
    ...

41. Middleware

Executes before and after every request. Common uses: logging, CORS, authentication, request timing.

@app.middleware("http")
async def log_requests(request: Request, call_next):
    response = await call_next(request)
    return response

42. Background Tasks

Runs long work after the response is sent to the client.

@app.post("/send-email")
async def send(background_tasks: BackgroundTasks):
    background_tasks.add_task(send_email, recipient)
    return {"status": "queued"}

43. How do you secure FastAPI APIs?

  • JWT authentication via OAuth2PasswordBearer
  • OAuth2 with password flow
  • HTTPS
  • Role-based authorization via Depends()
  • Input validation via Pydantic
  • CORS middleware to whitelist allowed origins

44. What is REST?

Architectural style using HTTP methods for CRUD operations on resources. Stateless, resource-based URLs.


45. GET vs POST vs PUT vs PATCH vs DELETE

MethodOperationIdempotent?
GETReadYes
POSTCreateNo
PUTFull replaceYes
PATCHPartial updateYes
DELETERemoveYes

46. Common HTTP status codes

200 OK · 201 Created · 204 No Content · 400 Bad Request · 401 Unauthorized · 403 Forbidden · 404 Not Found · 422 Unprocessable Entity · 500 Internal Server Error


47. JWT vs OAuth

JWT — a token format for authentication. Self-contained, signed.

OAuth — an authorization framework allowing third-party access delegation. JWTs are often used inside OAuth flows.


48. API Pagination

Splits large datasets using limit/offset (simple, but slow on deep pages) or cursor-based pagination (efficient, scalable).


49. API Versioning

Common approaches: /v1/users (URL path) · Accept: application/vnd.api.v1+json (header) · ?version=1 (query param).


50. How do you design a scalable REST API?

  • Stateless architecture
  • Proper resource naming (nouns, not verbs)
  • Pagination and filtering
  • Caching (Redis for repeated reads)
  • Authentication and rate limiting
  • Versioning
  • Structured logging and monitoring

51. Explain the Flask/FastAPI APIs you built and how you ensured scalability.

Experience-based question. Prepare to discuss:

  • Why you chose the framework
  • How you handled concurrent requests (async/await, ASGI)
  • Database connection pooling or caching strategies used
  • How the API was deployed (Docker, ECS, load balancing)

Testing

52. unittest vs pytest

unittest — Python’s built-in framework. Verbose, class-based.

pytest — more concise, supports fixtures, parametrization, richer plugins. Industry standard.


53. What is mocking?

Replacing real dependencies (databases, APIs) with simulated objects to isolate the code under test.

from unittest.mock import patch
 
@patch("mymodule.requests.get")
def test_fetch(mock_get):
    mock_get.return_value.json.return_value = {"id": 1}
    result = fetch_user(1)
    assert result["id"] == 1

54. What are fixtures?

Reusable setup/teardown logic in pytest. Used for test data, database connections, API clients.

@pytest.fixture
def db():
    conn = create_test_db()
    yield conn
    conn.close()

55. Unit Test vs Integration Test

Unit Test — tests a single function/class in isolation. Fast, no external dependencies.

Integration Test — verifies multiple components working together (e.g., API + DB).


56. What is code coverage?

Measures the percentage of code executed during tests. High coverage improves confidence but doesn’t guarantee bug-free code. Target 80%+ for critical paths.


57. How would you test a FastAPI REST API?

Use pytest with TestClient. Verify status codes, response payloads, auth, validation, and error scenarios.

from fastapi.testclient import TestClient
client = TestClient(app)
 
def test_create_user():
    response = client.post("/users", json={"name": "Alice"})
    assert response.status_code == 201