Tornado中initialize()与prepare()方法的区别及适用场景解析
Great question! I remember scratching my head over this exact distinction when I first started building apps with Tornado—they do seem interchangeable at first glance, but they have clear use cases once you dig into the details. Let’s break it down:
Core Differences & Use Cases
initialize(): Instance Setup for Static Configuration
initialize() is called once per RequestHandler instance (and since Tornado creates a new instance for every HTTP request, this means it runs once per request—but its purpose is distinct from prepare()).
The key feature of initialize() is that it can accept arguments passed directly from your route definitions. This makes it perfect for injecting static dependencies or configuration that the handler needs to function across all requests it handles.
Example Use Case: Injecting Dependencies
Suppose you have a database connection multiple handlers need access to. You can pass it via the route and capture it in initialize():
import tornado.web class UserHandler(tornado.web.RequestHandler): def initialize(self, db_connection): # Save the injected database connection as an instance variable self.db = db_connection def get(self, user_id): # Use the pre-configured DB connection in your request handler user = self.db.fetch_user(user_id) self.write({"user": user}) # Route definition: pass the DB connection as an argument app = tornado.web.Application([ (r"/users/(\d+)", UserHandler, {"db_connection": my_db_instance}), ])
Other solid uses for initialize():
- Setting up handler-specific template paths or static file roots
- Capturing route-specific flags (like a
require_admintoggle for permission checks)
prepare(): Per-Request Preprocessing
prepare() is called before every request method (GET, POST, PUT, etc.)—no exceptions. Even if you redirect or send an error response, prepare() will run first.
This is your go-to method for logic that needs to execute for every single request handled by the handler, regardless of the HTTP method.
Example Use Case: Enforcing Authentication
If you want to ensure a user is logged in before accessing any endpoint in a handler, put the auth check in prepare() instead of duplicating it in every get()/post() method:
class ProtectedHandler(tornado.web.RequestHandler): def prepare(self): # Check if the user has a valid session cookie user_id = self.get_secure_cookie("authenticated_user") if not user_id: # Redirect to login if not authenticated self.redirect("/login") return # Fetch the user and store it for use in request methods self.current_user = self.db.fetch_user(user_id) def get(self): # No need to re-check auth here—prepare() already handled it self.render("dashboard.html", user=self.current_user) def post(self): # Same here: user is guaranteed to be authenticated self.db.update_user(self.current_user.id, self.get_argument("name"))
Other great uses for prepare():
- Parsing custom request body formats (e.g., non-standard JSON or XML that Tornado doesn’t parse by default)
- Logging request metadata (IP address, user agent, request timestamp)
- Validating mandatory request headers required for all endpoints
Quick Summary
| Aspect | initialize() | prepare() |
|---|---|---|
| Arguments | Accepts route-passed parameters | No arguments (except self) |
| Call Timing | Once per handler instance (per request) | Before every request method (per request) |
| Primary Purpose | Inject static dependencies/config | Dynamic per-request preprocessing |
| Common Use Cases | DB connections, route-specific settings | Auth checks, request parsing, logging |
内容的提问来源于stack exchange,提问作者Lore




