使用os.path.walk时出现变量在赋值前引用的问题

0 投票
3 回答
1130 浏览
提问于 2025-04-16 07:06

好的。我之前有一些Matlab的基础,现在我正在转向Python。我在64位Linux上使用Python 2.6.5写了一段代码,这段代码会浏览目录,找到名为'GeneralData.dat'的文件,从中提取一些数据,并把它们拼接成一个新的数据集:

import pylab as p
import os, re
import linecache as ln

def LoadGenomeMeanSize(arg, dirname, files):
        for file in files:
            filepath = os.path.join(dirname, file)
            if filepath == os.path.join(dirname,'GeneralData.dat'):
                data = p.genfromtxt(filepath)
                if data[-1,4] != 0.0: # checking if data set is OK 
                    data_chopped = data[1000:-1,:] # removing some of data
                    Grand_mean = data_chopped[:,2].mean()
                    Grand_STD = p.sqrt((sum(data_chopped[:,4]*data_chopped[:,3]**2) + sum((data_chopped[:,2]-Grand_mean)**2))/sum(data_chopped[:,4]))
                else:
                    break
            if filepath == os.path.join(dirname,'ModelParams.dat'):
                l = re.split(" ", ln.getline(filepath, 6))
                turb_param = float(l[2])                
                arg.append((Grand_mean, Grand_STD, turb_param))

GrandMeansData = []
os.path.walk(os.getcwd(), LoadGenomeMeanSize, GrandMeansData)
GrandMeansData = sorted(GrandMeansData, key=lambda data_sort: data_sort[2])

TheMeans = p.zeros((len(GrandMeansData), 3 ))
i = 0
for item in GrandMeansData:
    TheMeans[i,0] = item[0]
    TheMeans[i,1] = item[1]
    TheMeans[i,2] = item[2]
    i += 1

print TheMeans # just checking...
# later do some computation on TheMeans in NumPy

然后它给我抛出了这个错误(虽然我发誓一个月前它是正常工作的):

Traceback (most recent call last):
  File "/home/User/01_PyScripts/TESTtest.py", line 29, in <module>
    os.path.walk(os.getcwd(), LoadGenomeMeanSize, GrandMeansData)
  File "/usr/lib/python2.6/posixpath.py", line 233, in walk
    walk(name, func, arg)
  File "/usr/lib/python2.6/posixpath.py", line 225, in walk
    func(arg, top, names)
  File "/home/User/01_PyScripts/TESTtest.py", line 26, in LoadGenomeMeanSize
    arg.append((Grand_mean, Grand_STD, turb_param))
UnboundLocalError: local variable 'Grand_mean' referenced before assignment

好吧……所以我去查了一些资料,想出了这个全局变量:

import pylab as p
import os, re
import linecache as ln

Grand_mean = p.nan
Grand_STD = p.nan
def LoadGenomeMeanSize(arg, dirname, files):
        for file in files:
            global Grand_mean
            global Grand_STD
            filepath = os.path.join(dirname, file)
            if filepath == os.path.join(dirname,'GeneralData.dat'):
                data = p.genfromtxt(filepath)
                if data[-1,4] != 0.0: # checking if data set is OK 
                    data_chopped = data[1000:-1,:]  # removing some of data
                    Grand_mean = data_chopped[:,2].mean()
                    Grand_STD = p.sqrt((sum(data_chopped[:,4]*data_chopped[:,3]**2) + sum((data_chopped[:,2]-Grand_mean)**2))/sum(data_chopped[:,4]))
                else:
                    break
            if filepath == os.path.join(dirname,'ModelParams.dat'):
                l = re.split(" ", ln.getline(filepath, 6))
                turb_param = float(l[2])                
                arg.append((Grand_mean, Grand_STD, turb_param))

GrandMeansData = []
os.path.walk(os.getcwd(), LoadGenomeMeanSize, GrandMeansData)
GrandMeansData = sorted(GrandMeansData, key=lambda data_sort: data_sort[2])

TheMeans = p.zeros((len(GrandMeansData), 3 ))
i = 0
for item in GrandMeansData:
    TheMeans[i,0] = item[0]
    TheMeans[i,1] = item[1]
    TheMeans[i,2] = item[2]
    i += 1

print TheMeans # just checking...
# later do some computation on TheMeans in NumPy

它没有给我错误信息。甚至还生成了一个包含数据的文件……但是数据完全不对!我通过运行命令手动检查了一些文件:

import pylab as p
data = p.genfromtxt(filepath)
data_chopped = data[1000:-1,:]
Grand_mean = data_chopped[:,2].mean()
Grand_STD = p.sqrt((sum(data_chopped[:,4]*data_chopped[:,3]**2) \
+ sum((data_chopped[:,2]-Grand_mean)**2))/sum(data_chopped[:,4]))

结果它们是不同的 :-(

1) 有没有人能告诉我哪里出错了?

2) 有没有人知道解决办法?

我会非常感激任何帮助 :-)

谢谢,
PTR

3 个回答

0

我发现你提供的代码和解决方案中有一个问题。

不要通过让变量可见来掩盖“变量在赋值前引用”的问题。 试着理解为什么会发生这种情况。

在你创建全局变量“Grand_mean”之前,你遇到了一个问题,就是在给它赋值之前就试图访问它。在这种情况下,如果你在函数外部初始化这个变量并把它标记为全局变量,这只是掩盖了问题。

你看到错误的结果是因为你让这个变量变得可见了(通过声明为全局变量),但问题依然存在。你的 Grand_mean 从来没有被赋值为正确的数据。

这意味着在“if filepath == os.path.join(dirname,...” 这段代码下的部分从来没有被执行过。

0

我想说这个条件没有通过:

if filepath == os.path.join(dirname,'GeneralData.dat'):

这意味着你在处理文件的时候,没有先找到 GeneralData.dat 文件再找到 ModelParams.dat 文件。可能你需要按字母顺序排序一下,或者是这个文件根本就不存在。

0

使用全局变量并不是一个好的解决办法。只有在你确实想要引用和赋值给全局的“Grand_mean”这个名字时,这样做才有意义。需要区分的原因是解释器在函数声明时会预先扫描赋值操作符。

你应该先在LoadGenomeMeanSize()这个函数的范围内给Grand_mean赋一个默认值。在一次循环中,你有四个分支可以给Grand_mean赋一个有意义的值。你可能遇到的情况是:

if filepath == os.path.join(dirname,'ModelParams.dat'):这个条件成立,但要么if filepath == os.path.join(dirname,'GeneralData.dat'):不成立,要么if data[-1,4] != 0.0:不成立。很可能是第二个条件没有通过。你需要调整一下代码。

简单来说,你可能需要像这样重新安排你的代码:

...
            if filepath == os.path.join(dirname,'GeneralData.dat'):
                data = p.genfromtxt(filepath)
                if data[-1,4] != 0.0: # checking if data set is OK 
                    data_chopped = data[1000:-1,:]  # removing some of data
                    Grand_mean = data_chopped[:,2].mean()
                    Grand_STD = p.sqrt((sum(data_chopped[:,4]*data_chopped[:,3]**2) + sum((data_chopped[:,2]-Grand_mean)**2))/sum(data_chopped[:,4]))

                    if filepath == os.path.join(dirname,'ModelParams.dat'):
                        l = re.split(" ", ln.getline(filepath, 6))
                        turb_param = float(l[2])                
                        arg.append((Grand_mean, Grand_STD, turb_param))
                else:
                    break

...

撰写回答