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

如何访问被装饰类方法的self变量?优化JSON-RPC调用ID计数器递增实现方案

解决JSON-RPC ID计数器递增的问题

1. 如何访问被装饰类方法的self变量?

首先,你遇到的AttributeError: 'ServiceInterface' object has no attribute 'client_id'大概率是拼写笔误——你的代码里定义的是current_id,但报错信息里提到的是client_id,先检查代码里的变量名是否统一。

回到装饰器访问self的核心问题:类的实例方法被调用时,第一个参数必然是实例本身(也就是self),所以你的装饰器逻辑本身是可行的,但直接用args[0]不够直观,且依赖参数顺序,健壮性不足。更清晰的写法是在wrapper函数里直接把self作为第一个参数接收:

import functools

def increment_id(func):
    @functools.wraps(func)
    def wrapper(self, *args, **kwargs):  # 明确接收self参数
        self.current_id += 1
        return func(self, *args, **kwargs)
    return wrapper

这种写法完全符合Python类方法的调用逻辑,可读性更强,也避免了索引args可能带来的潜在问题。

2. 更优雅的JSON-RPC ID计数器实现方式

其实装饰器在这里属于“过度抽象”,因为ID递增的逻辑和create_payload方法强绑定——只有生成请求payload时才需要递增ID。直接把递增逻辑内嵌到create_payload里会更简洁直观:

import json
import requests

class ServiceInterface:
    def __init__(self, base_url):
        self.base_url = base_url
        self.headers = {"content-type": "application/json"}
        self.current_id = 0

    def send(self, payload):
        """返回JSON-RPC请求的JSON字典。"""
        response = requests.request("POST", self.base_url, data=payload, headers=self.headers)
        if response.ok:
            return response.json()
        else:
            return {"error": {"code": response.status_code, "message": "HTTP Response Error"}}

    def create_payload(self, method, params):
        """创建JSON-RPC请求。"""
        self.current_id += 1  # 直接在生成payload前递增ID
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "id": self.current_id,
            "params": params,
        }
        return json.dumps(payload)

这种写法去掉了额外的装饰器嵌套,代码更易读,维护成本更低。

进阶:线程安全的ID计数器

如果你的代码会在多线程环境下运行,为了避免current_id递增时出现竞态条件,可以用threading.Lock来保护递增操作:

import threading

class ServiceInterface:
    def __init__(self, base_url):
        self.base_url = base_url
        self.headers = {"content-type": "application/json"}
        self.current_id = 0
        self.id_lock = threading.Lock()  # 初始化锁

    def create_payload(self, method, params):
        with self.id_lock:  # 使用上下文管理器确保线程安全
            self.current_id += 1
            payload_id = self.current_id
        payload = {
            "jsonrpc": "2.0",
            "method": method,
            "id": payload_id,
            "params": params,
        }
        return json.dumps(payload)

测试代码验证

修正后的代码可以通过你的测试用例:第一次调用create_payload生成的ID为1,第二次为2,完全符合预期的断言逻辑。

内容的提问来源于stack exchange,提问作者Oddaspa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:13:12