基础Python是否有类似Django模板继承的等效实现?
实现Python代码的可复用模板(类似Django模板扩展)
需求:像Django模板通过
extends和block复用代码那样,将给定的Python文件改造为可复用模板,后续文件仅需修改特定细节——示例中需定制两处:
uri = config.MUSEUMS_URI- 查询条件
where(Post.feed == 'museums')
以下是三种常用实现方案:
方法一:类继承
将通用逻辑封装为基类,子类仅需重写需要定制的属性或方法,保持原有调用方式不变。
基类文件(base_feed_handler.py)
from datetime import datetime from typing import Optional from etc.database import Post CURSOR_EOF = 'eof' class BaseFeedHandler: # 定义需子类重写的占位属性 FEED_URI = None FEED_NAME = None @classmethod def handler(cls, cursor: Optional[str], limit: int) -> dict: if cls.FEED_URI is None or cls.FEED_NAME is None: raise NotImplementedError("必须重写FEED_URI和FEED_NAME属性") posts = Post.select().\ where(Post.feed == cls.FEED_NAME).\ order_by(Post.cid.desc()).\ order_by(Post.indexed_at.desc()).\ limit(limit) if cursor: if cursor == CURSOR_EOF: return {'cursor': CURSOR_EOF, 'feed': []} cursor_parts = cursor.split('::') if len(cursor_parts) != 2: raise ValueError('Malformed cursor') indexed_at, cid = cursor_parts indexed_at = datetime.fromtimestamp(int(indexed_at) / 1000) posts = posts.where(((Post.indexed_at == indexed_at) & (Post.cid < cid)) | (Post.indexed_at < indexed_at)) feed = [{'post': post.uri} for post in posts] cursor = CURSOR_EOF last_post = posts[-1] if posts else None if last_post: cursor = f'{int(last_post.indexed_at.timestamp() * 1000)}::{last_post.cid}' return {'cursor': cursor, 'feed': feed}
子类文件(museums_handler.py)
from etc import config from base_feed_handler import BaseFeedHandler class MuseumsFeedHandler(BaseFeedHandler): FEED_URI = config.MUSEUMS_URI FEED_NAME = 'museums' # 对外暴露handler,保持原有调用接口一致 handler = MuseumsFeedHandler.handler
其他子类示例(books_handler.py)
from etc import config from base_feed_handler import BaseFeedHandler class BooksFeedHandler(BaseFeedHandler): FEED_URI = config.BOOKS_URI FEED_NAME = 'books' handler = BooksFeedHandler.handler
方法二:工厂函数(高阶函数)
通过工厂函数生成定制化的handler,将可变参数传入,直接得到符合需求的处理函数。
工厂文件(feed_handler_factory.py)
from datetime import datetime from typing import Optional, Callable from etc.database import Post CURSOR_EOF = 'eof' def create_feed_handler(feed_uri: str, feed_name: str) -> Callable[[Optional[str], int], dict]: def handler(cursor: Optional[str], limit: int) -> dict: posts = Post.select().\ where(Post.feed == feed_name).\ order_by(Post.cid.desc()).\ order_by(Post.indexed_at.desc()).\ limit(limit) if cursor: if cursor == CURSOR_EOF: return {'cursor': CURSOR_EOF, 'feed': []} cursor_parts = cursor.split('::') if len(cursor_parts) != 2: raise ValueError('Malformed cursor') indexed_at, cid = cursor_parts indexed_at = datetime.fromtimestamp(int(indexed_at) / 1000) posts = posts.where(((Post.indexed_at == indexed_at) & (Post.cid < cid)) | (Post.indexed_at < indexed_at)) feed = [{'post': post.uri} for post in posts] cursor = CURSOR_EOF last_post = posts[-1] if posts else None if last_post: cursor = f'{int(last_post.indexed_at.timestamp() * 1000)}::{last_post.cid}' return {'cursor': cursor, 'feed': feed} # 将feed_uri绑定到handler上,方便后续调用 handler.feed_uri = feed_uri return handler
业务文件(museums_handler.py)
from etc import config from feed_handler_factory import create_feed_handler # 传入定制参数生成handler handler = create_feed_handler(feed_uri=config.MUSEUMS_URI, feed_name='museums')
方法三:核心逻辑拆分+配置导入
将通用逻辑单独封装,业务文件仅需导入核心逻辑并传入定制配置。
核心逻辑文件(core_feed_logic.py)
from datetime import datetime from typing import Optional from etc.database import Post CURSOR_EOF = 'eof' def get_feed_data(feed_name: str, cursor: Optional[str], limit: int) -> dict: posts = Post.select().\ where(Post.feed == feed_name).\ order_by(Post.cid.desc()).\ order_by(Post.indexed_at.desc()).\ limit(limit) if cursor: if cursor == CURSOR_EOF: return {'cursor': CURSOR_EOF, 'feed': []} cursor_parts = cursor.split('::') if len(cursor_parts) != 2: raise ValueError('Malformed cursor') indexed_at, cid = cursor_parts indexed_at = datetime.fromtimestamp(int(indexed_at) / 1000) posts = posts.where(((Post.indexed_at == indexed_at) & (Post.cid < cid)) | (Post.indexed_at < indexed_at)) feed = [{'post': post.uri} for post in posts] cursor = CURSOR_EOF last_post = posts[-1] if posts else None if last_post: cursor = f'{int(last_post.indexed_at.timestamp() * 1000)}::{last_post.cid}' return {'cursor': cursor, 'feed': feed}
业务文件(museums_handler.py)
from etc import config from core_feed_logic import get_feed_data, CURSOR_EOF uri = config.MUSEUMS_URI def handler(cursor: Optional[str], limit: int) -> dict: return get_feed_data(feed_name='museums', cursor=cursor, limit=limit)
内容的提问来源于stack exchange,提问作者derrgill
相关产品推荐
相关产品推荐

