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

为何get_post_end()触发NameError而get_pre_end()可正常运行?

问题描述

定义了以下函数:

import math
from numpy import nan
from datetime import date
mismatch_day = date(2022, 12, 1)

def get_pre_end(row, mism_day):
    global end_pre
    if row['date'] < mism_day:
        end_pre = row['date_end']
    return end_pre

def get_post_end(row, mism_day):
    global end_post
    if row['date'] >= mism_day:
        end_post = row['date_end']
    return end_post

调用get_pre_end()能得到预期输出:

post_end_df = pd.DataFrame()
post_end_df['post_end'] = bydate_df.apply(lambda row: get_pre_end(row, mismatch_day), axis=1)
post_end_list = post_end_df['post_end'].tolist()
post_end_list = [item for item in post_end_list if not(math.isnan(item)) == True]

输出示例:[228.7, 179.3, 168.7, 111.9, 189.2, 220.6, 165.7, 183.8, 215.6,...

但调用get_post_end()时触发NameError:

post_end_df = pd.DataFrame()
post_end_df['post_end'] = bydate_df.apply(lambda row: get_post_end(row, mismatch_day), axis=1)
post_end_list = post_end_df['post_end'].tolist()
post_end_list = [item for item in post_end_list if not(math.isnan(item)) == True]

报错信息:

---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[32], line 2
      1 post_end_df = pd.DataFrame()
----> 2 post_end_df['post_end'] = bydate_df.apply(lambda row: get_post_end(row, mismatch_day), axis=1)
      3 post_end_list = post_end_df['post_end'].tolist()
      4 post_end_list = [item for item in post_end_list if not(math.isnan(item)) == True]

File ~\Anaconda3\lib\site-packages\pandas\core\frame.py:8839, in DataFrame.apply(self, func, axis, raw, result_type, args, **kwargs)
   8828 from pandas.core.apply import frame_apply
   8830 op = frame_apply(
   8831     self,
   8832     func=func,
   (...)
   8837     kwargs=kwargs,
   8838 )
-> 8839 return op.apply().__finalize__(self, method="apply")

File ~\Anaconda3\lib\site-packages\pandas\core\apply.py:727, in FrameApply.apply(self)
    724 elif self.raw:
    725     return self.apply_raw()
-> 727 return self.apply_standard()

File ~\Anaconda3\lib\site-packages\pandas\core\apply.py:851, in FrameApply.apply_standard(self)
    850 def apply_standard(self):
-> 851     results, res_index = self.apply_series_generator()
    853     # wrap results
    854     return self.wrap_results(results, res_index)

File ~\Anaconda3\lib\site-packages\pandas\core\apply.py:867, in FrameApply.apply_series_generator(self)
    864 with option_context("mode.chained_assignment", None):
    865     for i, v in enumerate(series_gen):
    866         # ignore SettingWithCopy here in case the user mutates
-> 867         results[i] = self.f(v)
    868         if isinstance(results[i], ABCSeries):
    869             # If we have a view on v, we need to make a copy because
    870             #  series_generator will swap out the underlying data
    871             results[i] = results[i].copy(deep=False)

Cell In[32], line 2, in <lambda>(row)
      1 post_end_df = pd.DataFrame()
----> 2 post_end_df['post_end'] = bydate_df.apply(lambda row: get_post_end(row, mismatch_day), axis=1)
      3 post_end_list = post_end_df['post_end'].tolist()
      4 post_end_list = [item for item in post_end_list if not(math.isnan(item)) == True]

Cell In[20], line 5, in get_post_end(row, mism_day)
      3 if row['date'] >= mism_day:
      4     end_post = row['date_end']
----> 5 return end_post

NameError: name 'end_post' is not defined

疑问:无法理解为何get_post_end()触发该错误,以为end_post是全局定义的,且else分支会处理不满足if条件的行。

报错原因
  1. 全局变量未初始化:global end_post仅声明函数内部要使用全局作用域的end_post变量,但你从未在全局作用域定义过这个变量。当函数执行时,如果没有满足if条件的行先给end_post赋值,直接return就会找不到该变量。
  2. get_pre_end能运行是侥幸:get_pre_end正常输出只是因为bydate_df的第一行数据满足row['date'] < mism_day,提前给end_pre赋了值,后续不满足条件的行可以返回之前的全局变量值。如果bydate_df的第一行不满足条件,get_pre_end同样会触发NameError。
  3. 无隐式else分支:函数里没有写else分支,不满足if条件时不会执行任何赋值操作,直接return未定义的变量,必然报错。
修复方法

方法1:提前初始化全局变量

在全局作用域先定义end_post和end_pre,给一个初始值(比如nan),这样即使第一行不满足条件,也能返回初始值:

import math
from numpy import nan
from datetime import date
mismatch_day = date(2022, 12, 1)

# 初始化全局变量
end_pre = nan
end_post = nan

def get_pre_end(row, mism_day):
    global end_pre
    if row['date'] < mism_day:
        end_pre = row['date_end']
    return end_pre

def get_post_end(row, mism_day):
    global end_post
    if row['date'] >= mism_day:
        end_post = row['date_end']
    return end_post

方法2:放弃全局变量(更推荐)

全局变量在pandas的apply操作中容易引发不可控的副作用,改用pandas原生逻辑实现更安全:

import pandas as pd
import math
from numpy import nan
from datetime import date
mismatch_day = date(2022, 12, 1)

# 获取满足条件的第一个date_end值,无满足条件的则设为nan
post_end_value = bydate_df.loc[bydate_df['date'] >= mismatch_day, 'date_end'].iloc[0] if not bydate_df.loc[bydate_df['date'] >= mismatch_day].empty else nan

# 将值填充到整列
bydate_df['post_end'] = post_end_value
post_end_list = bydate_df['post_end'].dropna().tolist()

如果需要保留最后一个满足条件的值,只需把iloc[0]改为iloc[-1]即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 17:43:13