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

Python函数操作外部变量报UnboundLocalError的规范解法

报错根因

Python的作用域规则是:只要函数内部存在对某个变量的赋值操作,解释器就会默认将该变量标记为函数局部变量,不会去全局作用域查找同名变量。
你的代码中在if分支内存在newdict = dict(response_json)的赋值语句,因此newdict被判定为trades()函数的局部变量,但if判断条件中提前读取了newdict['id'],此时局部变量newdict还未完成赋值,就触发了UnboundLocalError。

关于global写法的评价

在函数内加global newdict声明确实可以修复这个报错,语法完全合法,在几十行以内的临时小脚本里这么写不会有实质问题。但这种写法不符合高可维护性的编码规范:全局变量可以被任意位置的代码修改,随着代码量增长,很难追踪变量的修改路径,排查bug的成本会很高,不适合在正式项目里使用。

更合理的实现方案

推荐用类来封装需要持久保存的状态和对应的业务逻辑,完全不需要依赖全局变量,代码内聚性更强,后续扩展也更方便。
另外你的原代码还存在两个隐性bug,修复时一并处理:

  • 原判断条件中[elt['id'] for elt in response_json['data']]是列表类型,直接和整数类型的id值比较属于逻辑错误,Python3环境下会直接抛出类型不匹配的报错
  • 原异常捕获逻辑没有指定捕获类型,且JSON解析失败后没有中断后续流程,会触发response_json未定义的二次报错

修复后的完整参考代码:

import json
import pprint
import schedule
import time
from http import client

class TradeDataFetcher:
    def __init__(self, trading_pair_id=48, limit=1):
        self.trading_pair_id = trading_pair_id
        self.offset = 0
        self.limit = limit
        # 初始化存储最新交易数据,初始id设为0
        self.latest_trade_info = {"id": 0}
        self.conn = client.HTTPSConnection("trade.blocktrade.com")

    def pull_latest_trades(self):
        # 构造请求拉取数据
        req_path = f"/api/v1/trades/{self.trading_pair_id}?offset={self.offset}&limit={self.limit}"
        self.conn.request("GET", req_path, headers={"Content-Type": "application/json"})
        resp = self.conn.getresponse()
        resp_raw = resp.read()

        # 解析响应,解析失败直接返回
        try:
            resp_json = json.loads(resp_raw)
        except json.JSONDecodeError:
            print(f"响应解析失败,原始返回:{resp_raw}")
            return
        
        pprint.pprint(resp_json)
        # 提取最新交易id
        trade_id_list = [item["id"] for item in resp_json["data"]]
        print(f"拉取到的交易id列表:{trade_id_list}")
        current_latest_id = trade_id_list[0]

        # 比对id,有新数据则更新存储、执行业务逻辑
        if current_latest_id > self.latest_trade_info["id"]:
            self.latest_trade_info = resp_json
            print("检测到新交易数据:")
            print(self.latest_trade_info)
            # 后续业务逻辑直接写在这里即可

if __name__ == "__main__":
    fetcher = TradeDataFetcher()
    schedule.every(5).seconds.do(fetcher.pull_latest_trades)
    while True:
        schedule.run_pending()
        time.sleep(1)

这种实现方式把所有和交易数据拉取、状态存储相关的逻辑都收敛在类内部,不会污染全局命名空间,后续要加功能(比如多交易对拉取、数据落盘、告警逻辑)只需要修改类内代码即可,维护成本低很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:39:32