使用类来代替全局变量

3
我有一个程序,用于对数组进行一些操作(小波变换和其他复杂操作),然后将其与先前的数组及其属性进行比较,输出比较图表,并最终更新“先前”的数组以包含此信息。 基本上,我的程序开始变得有点冗长和难以阅读,但我无法将其拆分为函数,因为所有函数都在读取和更改相同的变量。如果不是每次想要函数更改它们时都定义这些变量作为全局变量,则非常困难。
然后我在网上找到了这个:
您可能有几个使用相同状态变量(读取或写入)的函数。您正在传递许多参数。您有需要将其参数转发给所使用的函数的嵌套函数。您想让一些模块变量保存该状态。
您可以代替制作一个类!类的所有方法都可以访问类的所有实例数据。通过将共享状态存储在类中,您避免了将其作为参数传递给方法的需要。
所以我想知道如何调整我的程序,以改用类来编写? 如果附加我的代码有助于解决问题,请告诉我,但它相当冗长,我不想填满论坛!
以下是代码:
import os, sys, string, math
from optparse import OptionParser
import numpy as np
import pywt
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
from matplotlib.ticker import MaxNLocator
import glob

dir = os.getcwd()
profiles = glob.glob(dir+"/B0740-28/*_edit.FT.ascii")
for x in range(0,len(profiles)):
    profiles[x] = profiles[x][28:]
#produce list of profile file names

mode = 'per'
wavelets = ['db12']
levels = range(3,4)
starts = []
fig = 1
ix = 0 #profile index
changes = np.zeros(len(profiles))
#array to record shape changes

for num_levels in levels:
    for wavelet in wavelets:
        for profile in profiles:

            prof_name = profile.partition('.')[0]
            #remove file extension

            pfile=open(dir+'/B0740-28/'+profile)
            data = []
            for line in pfile:
                data.append(float(line))
            data = np.array(data)
            end = len(data)
            data = np.array(data)/max(data)
            #get pulse profile and normalise
            #ignore first 2 lines

            wav_name = wavelet.partition('.')[0]
            w = pywt.Wavelet(wavelet)
            useful = pywt.dwt_max_level(end,w)
            #find max level of decomposition

            coeffs = pywt.wavedec(data,wavelet,mode,level=num_levels)
            #create wavelet coefficients: cAn, cDn, cD(n-1)... cD1

            lowpass = pywt.upcoef('a',coeffs[0],wavelet,level=num_levels,take=end)
            highpass = np.zeros(end)
            for x in range(1,(num_levels+1)):
                highpass += pywt.upcoef('d',coeffs[len(coeffs)-x],wavelet,\
                                        level=x,take=end)
            #reverse transform by upcoef
            #define highpass and lowpass components

            for n in range(0,len(data)):
                if float(data[n]) > 0.4:
                    value = n
                    starts.append(value)
                    break
            if profile != profiles[0]:
                offset = starts[0]- value
                data = np.roll(data,offset)
                lowpass = np.roll(lowpass,offset)
                highpass = np.roll(highpass,offset)
            #adjust profiles so that they line up
            
            if profile == profiles[0]:
                data_prev = 0
                lowpass_prev = 0
                highpass_prev = 0
                mxm = data.argmax()

            diff_low = lowpass - lowpass_prev
            diff_high = highpass - highpass_prev
            if max(diff_low) >= 0.15 or min(diff_low) <= -0.15:
                changes[ix] = 1
            else: changes[ix] = 0
            #significant change?

            def doPlotting(name,yaxis):
                plt.plot(name)
                plt.xlim([mxm-80,mxm+100])
                plt.ylabel(yaxis)
                plt.gca().yaxis.set_major_locator(MaxNLocator(nbins=4))
            
            figure = plt.figure(fig)
            figure.subplots_adjust(hspace =.5)
            plt.suptitle('Comparison of Consecutive Profiles')
            plt.subplot(411); plt.plot(data_prev); \
                              doPlotting(data,'Data'); plt.ylim(ymax=1.1)
            plt.subplot(412); plt.plot(lowpass_prev); \
                              doPlotting(lowpass,'Lowpass'); plt.ylim(ymax=1.1)
            plt.subplot(413); plt.plot(highpass_prev); doPlotting(highpass,'Highpass')
            plt.subplot(414); doPlotting(diff_low,'Lowpass\nChange')
            plotname = 'differences_'+str(ix+1)+'_'+wav_name+'_'+str(num_levels)
            plt.savefig(dir+'/B0740-28/Plots/'+plotname)
            #creates plots of two most recent profiles + their decomposition 

            fig += 1
            ix += 1
            #clears the figure content
            #increase array index

            data_prev = data
            lowpass_prev = lowpass
            highpass_prev = highpass
            #reassigns 'previous profile' values

figure = plt.figure(fig)
plt.plot(changes)
plt.title('Lowpass Changes')
plt.xlabel('Profile Number')
plt.ylabel('Change > Threshold?')
plt.ylim(-0.25,1.25)
plt.xlim(0,48)
plt.savefig(dir+'/B0740-28/Plots/changes')
#Save lowpass changes plot

你可以贴出你的代码 - 如果太长,它将被放在一个滚动框中。 - Eric
我会先编写需要大量参数的函数,然后确定哪些代码需要哪些变量。 - Eric
2个回答

4

我可能因为这个答案而被点踩,但就整体来看,在这种特殊情况下,我并不认为向您的程序包添加一些全局变量是有问题的。

类在你想要在许多不同的地方使用一堆功能时非常好用和有用,然而,你所描述的听起来非常具体,并且不太可能在其他地方重复使用。创建一个带有实例变量的单次使用类实际上与在具有全局变量的包中拥有一堆函数并没有太大区别。


对数组进行操作,然后将其与先前的数组及其属性进行比较,听起来像是在这里拥有两个类实例的最佳选择。 - Eric
谢谢 :) 那么,我是否可以在程序一开始就将某些变量定义为全局变量,以便所有不同的函数都可以看到和编辑它们? - astro person
我认为你的意思是“模块”,而不是“包”(在Python中它们是不同的东西)。前者是内置类“module”的实例,其中定义的内容是实例属性 - 因此,按照你所说的做法就是使用类... - martineau

1

你想要的是这样的:

class MyDataProcessor(object):
    def __init__(self, data_array):
        self.data_array = data_array

    def processX(self):
        # do stuff with self.data_array

    def processY(self):
        # do stuff with self.data_array

m = MyDataProcessor([1, 2, 3, 4, 5])
m.processX()

n = MyDataProcessor([5, 4, 3, 2, 1])
n.processX()

谢谢!这很有帮助!不过我有比data_array更多的变量,可能有大约10个,而且我正在循环处理47/48个不同的情况(从文件中读取每个数组),所以我不能真正做到m =,n =等。目前我正在从文件中读取所有数组,然后对它们进行循环处理。 - astro person
@HelenJohnson:这些变量中有多少需要是全局的?有些变量只能在一个函数中使用吗?无论如何,您可以向构造函数添加更多参数。 - Eric
使用类并不能真正消除全局变量,因为它们的实例(例如您答案中的 mn)仍然是全局变量。但是使用它们仍然是一个好习惯,因为它们可以大大减少所需的全局变量数量,并且通常封装了对可能是单个全局变量的东西的访问。 - martineau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接