python asyncio async await coroutines event loop 2024 Interview Q&A
Prepare for senior technical positions. Click on any question to expand and review details.
Here is advanced Interview Prep Q&A module based on the provided tutorials, quizzes. Coding challenges for Python Async/Await and API integration.
Advanced Python Async/Await & API Integrations: Interview Q&
Question: What happens under a hood when you define function with the async def syntax, and how does a await keyword function when applied to an I/O operation like asyncio.sleep()?
Answer:
When you define a function using async def, Python doesn't really execute the function immediately; instead, it creates a coroutine object behind a scenes.
The await keyword is then used to pause the execution of that coroutine. When operation like asyncio.sleep() is awaited, it yields control back to the event loop, while this allows an event loop to execute other pending tasks instead of freezing the entire program. A helpful analogy from a tutorial is a chess grandmaster playing multiple opponents: instead of waiting for one opponent for think (blocking), she moves for the next table and makes the move there, constantly yielding her waiting time to do other useful work.
Question: You're building asynchronous Python application but need to use the requests library to fetch data from the API. Since requests.get() is a synchronous, blocking function how would you integrate it without freezing the asyncio event loop?
Answer:
Because requests is fundamentally built to block the program until the server replies, running it directly inside a coroutine will probably freeze an entire event loop; to fix this you should use asyncio.to_thread().
This function allows you to take any standard, blocking function and asynchronously run it in an entirely separate system thread. Any arguments you supply (*args or **kwargs) are directly passed to target function, keeping main async program lightning-fast and unblocked.
import asyncio
import requests
def fetch_sync(url):
# This is a blocking call
return requests.get(url).json()
async def fetch_async(url):
# Offload the blocking call to a separate thread
data = await asyncio.to_thread(fetch_sync, url)
return data
Question: According to Python's event loop documentation, how should standard application developers manage event loop execution. What happens if you try to retrieve the running loop when none is active?
Answer:
Application developers should primarily manage execution using high-level asyncio functions, such as asyncio.run(). Directly referencing loop object or calling its lower-level methods is mostly intended for authors of lower-level code libraries. Frameworks who require finer control over the event loop's behavior.
If you attempt to retrieve the running event loop in the current OS thread (using the appropriate internal function) and there's no event loop currently running, Python will raise a RuntimeError. Plus fetching the running loop is strictly restricted to being called from within coroutine or a callback.
Question: You're pretty much tasked of aggregating live user statistics than a highly unreliable third-party API. The server lot of times times out. When it crashes it returns flat HTML error pages instead of JSON, and how do you implement safe deserialization to ensure your system never crashes?
Answer:
In the professional environment blindly calling .json() on a response is dangerous because encountering an HTML page instead of JSON will trigger JSONDecodeError (or ValueError) and crash the application.
For implement safe deserialization, you really have to:
1. Enforce a timeout upon a request for prevent a program from waiting forever.
2. Call response.raise_for_status() to verify the server actually responded with a successful HTTP status code before attempting to parse a payload.
3. Wrap the logic in a try-except block specifically catching requests.exceptions.RequestException for network or timeout issues and JSON decoding errors for bad payloads.
import requests
def get_reliable_data(url):
try:
response = requests.get(url, timeout=5.0)
# Verify success code before parsing
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Network/Timeout Error: {e}")
return None
except requests.exceptions.JSONDecodeError:
print("Server returned invalid JSON (e.g., HTML error page).")
return None
Question: The third-party analytics API you're pretty much querying strictly blocks default Python scripts to prevent spam bots. How can you bypass this restriction and securely authenticate your request?
Answer:
APIs identify clients and enforce rules based on metadata passed in the HTTP Headers. By default, requests library announces itself as a Python script which triggers bot blockers, and
to bypass this, you need for pass a custom User-Agent string (e.g., "AnalyticsDashboard/1.0") inside headers to politely identify your application. Additionally, you can pass secret API tokens to authenticate your request, a lot with times placed in an "Authorization" header.
import requests
url = "https://api.startup.com/stats"
headers = {
"User-Agent": "AnalyticsDashboard/1.0",
"Authorization": "Bearer YOUR_SECRET_TOKEN"
}
response = requests.get(url, headers=headers, timeout=5.0)