Table of Contents
- Python Basics
- OOP Concepts
- Python Advanced Topics
- AWS
- Scenario-Based Questions
- Coding Questions
- System Design
- Flask/Django
- REST APIs
- Databases
- Testing
- Concurrency
- Hashing
- Other Topics
Python Basics
Questions and Answers
Q: What is the main purpose of a constructor in OOP?
A:
- Primary role: Initialize object state with default/initial values
- Called automatically during object instantiation
- In Python, implemented via
__init__
method - Enables encapsulation by validating initial data
class User:
def __init__(self, name: str, id: int):
self.name = name # Initialize instance variables
self.id = id
Q: Which data types are hashable in Python?
A:
Hashable | Non-Hashable |
---|---|
int, float, bool | list, dict |
str | set |
tuple (if immutable) | bytearray |
frozenset | custom objects* |
*Objects are hashable if they implement __hash__
and __eq__
methods
Q: What is the role of __name__
in Flask applications?
A:
- Special Python variable storing module name
- Helps Flask locate:
- Template directories
- Static assets
- Root path for relative file paths
- Critical for proper app initialization:
app = Flask(__name__)
Q: How does file uploading work in Flask?
A:
- Client sends multipart/form-data request
- Access files via
request.files
dictionary - Security considerations:
- Limit file extensions (
ALLOWED_EXTENSIONS
) - Validate content type
- Store in secure location
- Limit file extensions (
@app.route('/upload', methods=['POST'])
def upload_file():
file = request.files['file']
if file and allowed_file(file.filename):
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
Q: What is Flask-JWT?
A:
- Extension for JSON Web Token authentication
- Typical workflow:
- User logs in β returns access token
- Token sent in Authorization header
- Protected routes verify token
- Key features:
- Token expiration
- Refresh tokens
- Blacklist management
from flask import Flask, jsonify, request
from flask_jwt import JWT, jwt_required, current_identity
from werkzeug.security import safe_str_cmp
# Sample user database (replace with real database in production)
users = {
"user1": {
"username": "user1",
"password": "password1" # In real app, use hashed passwords
}
}
class User(object):
def __init__(self, username):
self.username = username
# Flask app setup
app = Flask(__name__)
app.secret_key = 'super-secret-key' # Replace with actual secret key
# JWT authentication setup
def authenticate(username, password):
user = users.get(username)
if user and safe_str_cmp(user['password'], password):
return User(username)
def identity(payload):
username = payload['identity']
return users.get(username)
jwt = JWT(app, authenticate, identity)
# Protected route
@app.route('/protected')
@jwt_required()
def protected():
return jsonify({'message': f'Hello {current_identity.username}! This is a protected route'})
# Login endpoint (automatically created by Flask-JWT at /auth)
# curl -X POST -H "Content-Type: application/json" -d '{"username":"user1","password":"password1"}' http://localhost:5000/auth
# Example usage
if __name__ == '__main__':
app.run(debug=True)
OOP Concepts
Questions and Answers
Q: Explain the diamond problem in multiple inheritance
A:
- Occurs when class inherits from two classes sharing a common ancestor
- Python resolves using MRO (Method Resolution Order) with C3 linearization
- Example resolution order: Child β Parent1 β Parent2 β Grandparent
class Grandparent:
def method(self):
print("Grandparent")
class Parent1(Grandparent):
def method(self):
print("Parent1")
class Parent2(Grandparent):
def method(self):
print("Parent2")
class Child(Parent1, Parent2):
pass
# MRO: Child β Parent1 β Parent2 β Grandparent
Python Advanced Topics
Questions and Answers
Q: How can you implement a custom iterator?
A:
- Implement
__iter__
returning self - Implement
__next__
with iteration logic - Raise
StopIteration
when complete
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
num = self.current
self.current -= 1
return num
# Usage:
for num in CountDown(5):
print(num) # 5,4,3,2,1
Q: What is the Global Interpreter Lock (GIL)?
A:
- Mutex protecting Python object access
- Impacts:
- Allows only one thread execution at a time
- Limits CPU-bound multithreading performance
- Doesnβt affect I/O-bound operations
- Workarounds:
- Multiprocessing
- Asyncio for I/O tasks
- C extensions releasing GIL
AWS
Questions and Answers
Q: How would you secure S3 buckets?
A:
- Access control methods:
- IAM policies (principle of least privilege)
- Bucket policies (resource-based)
- ACLs (legacy, avoid)
- Presigned URLs for temporary access
- Encryption:
- SSE-S3, SSE-KMS, SSE-C
- Client-side encryption
- Monitoring:
- Enable S3 access logging
- Use CloudTrail for API tracking
- Set up Config rules for compliance
Q: Explain Lambda cold starts
A:
- Initialization phase when no idle instances available
- Factors affecting duration:
- Runtime (Python < Java)
- Package size
- VPC configuration
- Mitigation strategies:
- Provisioned concurrency
- Keep packages lean
- Avoid VPCs when possible
- Periodic ping (keep-warm)
Coding Questions
Add Two Numbers (LeetCode Optimized)
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def addTwoNumbers(l1: ListNode, l2: ListNode) -> ListNode:
"""
Time Complexity: O(max(m,n))
Space Complexity: O(max(m,n))
"""
dummy = ListNode() # Anchor node for result
current = dummy
carry = 0
while l1 or l2 or carry:
# Calculate sum of current digits
val1 = l1.val if l1 else 0
val2 = l2.val if l2 else 0
total = val1 + val2 + carry
# Update carry and create new node
carry, digit = divmod(total, 10)
current.next = ListNode(digit)
current = current.next
# Move to next nodes if available
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
return dummy.next
Optimized Zero Sorting
def move_zeros_and_sort(arr: list) -> list:
"""
Time Complexity: O(n log n) due to sort
Space Complexity: O(n)
"""
# Partition zeros and non-zeros in single pass
zeros_count = 0
non_zeros = []
for num in arr:
if num == 0:
zeros_count += 1
else:
non_zeros.append(num)
# In-place sort for memory efficiency
non_zeros.sort()
return [0]*zeros_count + non_zeros
System Design
Task Scheduler API Design
Key Components:
- Authentication: JWT with refresh tokens
- Authorization: RBAC (User/Admin roles)
- Endpoints:
POST /api/tasks - Create task GET /api/tasks?status=active - Filter tasks PUT /api/tasks/{id} - Update task DEL /api/tasks/{id} - Delete task POST /api/tasks/reminders - Set reminder
- Database Schema:
CREATE TABLE tasks ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), title VARCHAR(255), status ENUM('pending', 'completed'), due_date TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() );
- Scalability:
- Use Redis for rate limiting
- Celery for async reminders
- Sharding by user_id for horizontal scaling
Flask/Django
Questions and Answers
Q: Flask vs Django Middleware
A:
Feature | Flask | Django |
---|---|---|
Middleware Type | Decorator-based | Class-based |
Execution Order | Route-specific | Global |
Flexibility | High | Structured |
Common Uses | Auth, Logging | CSRF, Session |
Q: Optimize Flask Performance
A:
- Use production server (Gunicorn/uWSGI)
- Enable JIT compilation with PyPy
- Database optimizations:
- Connection pooling
- Index optimization
- Query caching
- Enable compression with Flask-Compress
- Use CDN for static assets
REST APIs
Best Practices
- Versioning:
/api/v1/resource
- Pagination:
?page=2&limit=50
- Filtering:
?status=active&sort=-created_at
- HATEOAS: Include resource links
- Rate Limiting: X-RateLimit headers
- Error Handling:
{
"error": "InvalidRequest",
"message": "Missing required field: email",
"code": 400
}
Databases
Connection Pooling Pattern
from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
engine = create_engine(
'postgresql://user:pass@host/db',
poolclass=QueuePool,
pool_size=10,
max_overflow=5,
pool_timeout=30
)
Testing
Pytest Fixture Example
import pytest
@pytest.fixture
def db_connection():
conn = create_test_connection()
yield conn # Setup/teardown
conn.close()
def test_query(db_connection):
result = db_connection.execute("SELECT 1")
assert result.fetchone() == (1,)
Concurrency
Thread Pool Pattern
from concurrent.futures import ThreadPoolExecutor
def process_data(data):
# CPU-intensive work
with ThreadPoolExecutor(max_workers=4) as executor:
futures = [executor.submit(process_data, chunk)
for chunk in data_chunks]
results = [f.result() for f in futures]
Hashing
Secure Password Handling
from werkzeug.security import generate_password_hash, check_password_hash
hashed_pw = generate_password_hash('secret', method='pbkdf2:sha512')
is_valid = check_password_hash(hashed_pw, 'secret') # Returns bool
Other Topics
CI/CD Pipeline
graph LR A[Git Commit] --> B[Run Tests] B --> C{Build Docker} C -->|Success| D[Deploy Staging] D --> E[Integration Tests] E --> F{Manual Approval} F --> G[Deploy Prod]