SimPy日志写入Pandas DataFrame后类外读取为空的问题排查
问题根因
- 核心是类属性与实例属性的作用域混淆:你在类定义层级初始化的
s_df是类级别的共享属性,但在do_somehting方法中执行self.s_df = self.s_df.append(...)时,赋值操作会给当前运行的Seller实例单独创建一个同名实例属性,后续所有append生成的新DataFrame都绑定在各个实例自己身上。你在方法内部打印看到的数据增长,实际是各个实例自有s_df的变化,类本身持有的s_df始终是初始化时的空DataFrame,所以外部调用类方法df()拿到的永远是空值。 - 语法问题:原代码
__init__方法中self._s_list.append(self)这一行缩进多了一级,直接运行会报缩进错误。 - 性能问题:pandas的
append方法每次调用都会生成全新的DataFrame对象,仿真循环里高频调用的性能极差,不适合做运行时日志存储。
修复后代码
import pandas as pd import simpy class Seller(object): _s_list = [] # 存储所有卖家实例 _log_records = [] # 运行时先用列表存日志,避免频繁拼接DataFrame def __init__ (self, env, name): self._s_list.append(self) self.env, self.name = env, name self.action = env.process(self.do_something()) def do_something(self): while True: # 直接往类级别的日志列表追加记录,不给实例绑定同名属性 self._log_records.append({ "time": self.env.now, "name": self.name, }) yield self.env.timeout(1) @classmethod def lst(cls): return cls._s_list @classmethod def df(cls): # 需要取数时一次性把列表转为DataFrame return pd.DataFrame.from_dict(cls._log_records) env = simpy.Environment() for i in range(0,3): Seller(env, "seller n. %d" % i) env.run(until=5) print(Seller.lst()) print(Seller.df())
修复说明
- 把运行时日志存储介质从DataFrame换成普通列表,列表的
append是原地操作,性能比反复拼接DataFrame高几个数量级,适配仿真场景的高频写入需求。 - 所有类级别的共享数据操作,避免通过
self.xxx =的形式赋值,防止意外创建实例属性覆盖类属性引用。类方法中统一用cls指代类本身,实例方法中如果要修改类属性,直接通过类名或者self.__class__引用即可。 - 同步修正了原代码的缩进错误、方法名拼写错误(原
do_somehting改为正确拼写do_something)。
内容的提问来源于stack exchange,提问作者Giuseppe Bonavita
相关产品推荐
相关产品推荐

