如何避免重复代码处理异常、未定义变量及特定比较逻辑
解决重复异常/条件处理代码的小技巧(无需新函数)
嘿,我完全懂你这种重复写相同处理代码的烦躁——不仅代码冗余,后期改一处就得改两处,很容易出错。针对你不想定义新函数的需求,咱们可以用标志位统一触发的方式,把所有需要走错误处理的情况都导向同一段代码,下面结合你的代码给你具体说明:
核心思路
用一个布尔变量(比如fit_success)来标记拟合是否成功,不管是抛出ValueError/RuntimeError异常,还是拟合参数不满足条件的情况,都把这个变量设为False。最后只需要判断这个变量的值,执行一次统一的处理逻辑就行,不用重复写两遍代码。
修改后的代码示例
if fitfn not in ['gauss','lorentz']: raise IOError("Fitting function name must be 'lorentz' or 'gauss'") cubedims = np.shape(cube) frames = np.array([(n,w) for n,w in enumerate(wvl) if (lc-0.2 < w < lc+0.2)]) inds,wls = np.transpose(frames) # 初始化各种结果数组 fdencube = np.zeros((cubedims[1], cubedims[2])) fduncube = np.zeros((cubedims[1], cubedims[2])) spindex = np.zeros((cubedims[1], cubedims[2])) spundex = np.zeros((cubedims[1], cubedims[2])) lincube = np.zeros((len(frames), cubedims[1], cubedims[2])) elincube = np.zeros((len(frames), cubedims[1], cubedims[2])) concube = np.zeros((cubedims)) econcube = np.zeros((cubedims)) for x in xrange(cubedims[1]): for y in xrange(cubedims[2]): spec = cube[:,x,y] uspec = ecube[:,x,y] fit_success = True # 初始化标志位为成功 try: p, pcov = curvf(globals()[fitfn], wvl[~np.isnan(spec)], spec[~np.isnan(spec)], sigma=uspec[~np.isnan(spec)], bounds = [[0.01, min(wvl), np.mean(wvl[1:]-wvl[:-1]), -10, 0.], [50., max(wvl), 0.4, 10, 10.0]]) fwhm = 2*abs(p[2]) if fitfn=='lorentz' else p[2]*np.sqrt(8*np.log(2)) # 检查初始拟合参数是否符合要求 if not (fwhm < 0.16 and (lc-0.05 < p[1] < lc+0.05) and 'pcov' in globals()): fit_success = False # 尝试分段拟合 try: s = spec[~inds.astype(int)] u = uspec[~inds.astype(int)] q, qcov = curvf(lreg, wls[~np.isnan(s)], s[~np.isnan(s)], sigma=u[~np.isnan(s)], bounds = [[-10,0.], [10,10.0]]) r, rcov = curvf(globals()[fitfn], wvl[inds.astype(int)], spec[inds.astype(int)], sigma=uspec[inds.astype(int)], bounds = [[0.01, min(wvl), np.mean(wvl[1:]-wvl[:-1]), -10, 0.], [50., max(wvl), 0.4, 10, 10.0]]) fwhmr = 2*abs(r[2]) if fitfn=='lorentz' else r[2]*np.sqrt(8*np.log(2)) # 检查分段拟合参数是否符合要求 if (fwhmr < 0.16 and (lc-0.05 < r[1] < lc+0.05) and 'rcov' in globals()): # 分段拟合成功,更新结果 stdr = np.sqrt(np.diag(rcov)) stdq = np.sqrt(np.diag(qcov)) lvw = gauss(wvl, r[0], r[1], r[2], 0, 0) concube[:,x,y] = spec - lvw econcube[:,x,y] = np.sqrt(uspec**2 + stdr[0]**2 + stdr[1]**2 + stdr[2]**2) cvw = q[0]*frames[:,1] + q[1] lincube[:,x,y] = spec[inds.astype(int)] - cvw elincube[:,x,y] = np.sqrt(uspec[inds.astype(int)]**2 + stdq[-2]**2 + stdq[-1]**2) spindex[x,y] = q[0] spundex[x,y] = stdq fdencube[x,y] = r[0] fduncube[x,y] = stdr[0] fit_success = True # 分段拟合成功,重置标志位 else: fit_success = False except (ValueError, RuntimeError): fit_success = False else: # 初始拟合成功,更新结果 stdp = np.sqrt(np.diag(pcov)) cvw = p[-2]*frames[:,1] + p[-1] lincube[:,x,y] = spec[inds.astype(int)] - cvw elincube[:,x,y] = np.sqrt(uspec[inds.astype(int)]**2 + stdp[-2]**2 + stdp[-1]**2) lvw = gauss(wvl, p[0], p[1], p[2], 0, 0) concube[:,x,y] = spec - lvw econcube[:,x,y] = np.sqrt(uspec**2 + stdp[0]**2 + stdp[1]**2 + stdp[2]**2) spindex[x,y] = p[-2] spundex[x,y] = stdp[-2] fdencube[x,y] = p[0] fduncube[x,y] = stdp[0] except (ValueError, RuntimeError): fit_success = False # 统一处理所有拟合失败的情况 if not fit_success: fdencube[x,y] = np.NaN fduncube[x,y] = np.NaN lincube[:,x,y] = np.NaN elincube[:,x,y] = np.NaN try: q, qcov = curvf(lreg, wvl[~np.isnan(spec)], spec[~np.isnan(spec)], sigma=uspec[~np.isnan(spec)], bounds = [[-10,0.], [10,10.0]]) if 'qcov' in globals(): concube[:,x,y] = spec econcube[:,x,y] = uspec spindex[x,y] = q[0] spundex[x,y] = np.sqrt(np.diag(qcov))[0] else: concube[:,x,y] = spec econcube[:,x,y] = uspec spindex[x,y] = q[0] spundex[x,y] = np.NaN except (ValueError, RuntimeError): print('fit failed') concube[:,x,y] = spec econcube[:,x,y] = uspec spindex[x,y] = np.NaN spundex[x,y] = np.NaN
为什么这样有效?
- 所有可能导致失败的场景(初始拟合异常、初始参数不合格、分段拟合异常、分段参数不合格)都会把
fit_success设为False - 最后只需要执行一次失败处理逻辑,不用重复编写相同的代码块
- 代码结构更清晰,后期修改处理逻辑只需要改一处即可
另外,虽然你不想定义新函数,但其实可以把失败处理逻辑封装成一个小型的嵌套函数(比如在for循环里定义),这样代码会更整洁,不过标志位的方式已经完全满足你的需求啦。
内容的提问来源于stack exchange,提问作者ColorOutOfSpace
相关产品推荐
相关产品推荐

