Pandas DataFrame条件格式化函数传递额外参数时触发NameError错误的解决求助
Pandas DataFrame条件格式化函数传递额外参数时触发NameError错误的解决求助
你遇到的这个NameError问题,根源在于Python函数默认参数的求值时机——默认参数是在函数定义的时候就计算的,而不是调用的时候。
你在定义condFormat时写了def condFormat(s, df=dfdefs),这行代码在Python解析函数定义的时候就会尝试查找dfdefs这个变量,但此时dfdefs还没有被创建(它是在main函数内部才会从数据库读取赋值的),所以自然会抛出“name 'dfdefs' is not defined”的错误。
方案一:调用时显式传递参数(推荐)
修改condFormat函数,去掉默认的df参数,然后在调用applymap的时候通过关键字参数把dfdefs传递进去。同时注意:df.style.applymap()返回的是一个Styler对象,不会修改原DataFrame,你需要用这个Styler对象来生成HTML,否则导出的内容不会包含样式。
修改后的完整代码:
def condFormat(s, df): dcolors = {"GREEN": "rgb(146, 208, 80)", "YELLOW": "rgb(255, 255, 153)", "RED": "rgb(218, 150, 148)", None: "rgb(255, 255, 255)"} dftemp = df.query("STATUS == @s") scolor = dcolors[dftemp["COLOR"].iloc[0]] return "background-color: " + scolor def main(): dfhealth = pd.read_sql("SELECT name, status FROM health", conn) dfdefs = pd.read_sql("SELECT status, color FROM definitions", conn) # 调用applymap时显式传递df参数 styled_df = dfhealth.style.applymap(condFormat, df=dfdefs) # 使用Styler对象生成HTML html = styled_df.to_html() return html
方案二:避免定义时的默认参数求值
如果一定要保留默认参数的形式,可以把默认值设为None,然后在函数内部做判断,避免定义时就查找未存在的变量:
def condFormat(s, df=None): if df is None: raise ValueError("必须传入df参数,用于匹配状态与颜色的映射") dcolors = {"GREEN": "rgb(146, 208, 80)", "YELLOW": "rgb(255, 255, 153)", "RED": "rgb(218, 150, 148)", None: "rgb(255, 255, 255)"} dftemp = df.query("STATUS == @s") scolor = dcolors[dftemp["COLOR"].iloc[0]] return "background-color: " + scolor def main(): dfhealth = pd.read_sql("SELECT name, status FROM health", conn) dfdefs = pd.read_sql("SELECT status, color FROM definitions", conn) styled_df = dfhealth.style.applymap(condFormat, df=dfdefs) html = styled_df.to_html() return html
额外优化:提前构建状态-颜色映射字典
每次调用condFormat都执行df.query()会有点低效,尤其是当数据量较大的时候。你可以在main函数里先把dfdefs转换成字典,直接通过状态值获取颜色名称,提升效率:
def main(): dfhealth = pd.read_sql("SELECT name, status FROM health", conn) dfdefs = pd.read_sql("SELECT status, color FROM definitions", conn) # 提前构建状态到颜色名称的映射字典 status_to_color = dfdefs.set_index("STATUS")["COLOR"].to_dict() def condFormat(s): dcolors = {"GREEN": "rgb(146, 208, 80)", "YELLOW": "rgb(255, 255, 153)", "RED": "rgb(218, 150, 148)", None: "rgb(255, 255, 255)"} # 直接通过字典获取颜色名称,不存在则用默认白色 color_name = status_to_color.get(s) scolor = dcolors.get(color_name, dcolors[None]) return f"background-color: {scolor}" styled_df = dfhealth.style.applymap(condFormat) html = styled_df.to_html() return html
备注:内容来源于stack exchange,提问作者Kes Perron
相关产品推荐
相关产品推荐

