You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基础Python是否有类似Django模板继承的等效实现?

实现Python代码的可复用模板(类似Django模板扩展)

需求:像Django模板通过extends和block复用代码那样,将给定的Python文件改造为可复用模板,后续文件仅需修改特定细节——示例中需定制两处:

  1. uri = config.MUSEUMS_URI
  2. 查询条件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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 06:11:25