Python使用sorted()后触发AttributeError问题及修复方法咨询
问题分析与修复方案
你猜的没错!问题确实出在sorted()返回的类型上——data.items()是字典的键值对视图,用sorted()处理后会变成一个列表,里面的每个元素是(batch, sample)这样的元组,而列表根本没有.items()方法,这就是你看到AttributeError: 'list' object has no attribute 'items'的原因。
核心修复步骤
1. 修改average函数的循环逻辑
因为sorted_data是列表(每个元素是(批次名, 对应样本列表)的元组),直接遍历这个列表即可,不需要调用.items():
def average(sorted_data): # 把原来的 sorted_data.items() 改成直接遍历 sorted_data for batch, sample in sorted_data: if len(sample) > 0: n = 0 x_sum = 0 for (x, y, val) in sample: if x**2 + y**2 <= 1: x_sum += val n += 1 try: average_val = x_sum/n # 这里变量名不要用average,和函数名重名会有问题 except ZeroDivisionError: # utanför enhetscirkeln print("Other measurements are made outside the unit circle") continue zero_data = False else: zero_data = True print_average(batch, average_val, zero_data)
另外注意:我把变量名average改成了average_val,避免和函数名average重名导致的潜在问题。
2. 清理collect_data函数的冗余代码
你的collect_data函数里有两个return语句,第一个return data会直接终止函数,后面的return sorted_data永远不会执行。如果不需要这个函数返回排序后的列表,可以删掉相关代码;如果需要,可以调整成只返回排序后的列表:
def collect_data(filename): data = dict() with open(filename, 'r') as h: for line in h: four_vals = line.split(',') batch = four_vals[0] if not batch in data: data[batch] = [] try: data[batch] += [(float(four_vals[1]), float(four_vals[2]), float(four_vals[3]))] except ValueError: print("String not a float") # 删掉冗余的return,只返回排序后的列表(或者根据需求返回原始字典) sorted_data = sorted(data.items(), key=operator.itemgetter(0)) return sorted_data
如果做了这个修改,main函数里就可以简化成:
def main(): ''' This is the main body of the program. ''' filename = input('Which data file? ') sorted_data = collect_data(filename) average(sorted_data)
额外优化建议:按数字而非字符串排序你的批次
目前你的batch是字符串类型(比如"3"、"1"),用sorted(data.items(), key=operator.itemgetter(0))是按字符串排序的。如果后续批次号超过9(比如"10"),字符串排序会把"10"排在"2"前面,不符合数字逻辑。
可以把批次号转换成整数来解决:
def collect_data(filename): data = dict() with open(filename, 'r') as h: for line in h: four_vals = line.split(',') # 把batch转换成整数,处理可能的空格 batch = int(four_vals[0].strip()) if not batch in data: data[batch] = [] try: # 同样去掉坐标值的空格,避免转换float出错 x = float(four_vals[1].strip()) y = float(four_vals[2].strip()) val = float(four_vals[3].strip()) data[batch].append((x, y, val)) # 用append比+=更直观 except ValueError: print(f"Invalid number in line: {line.strip()}") # 按数字排序批次 sorted_data = sorted(data.items(), key=operator.itemgetter(0)) return sorted_data
完整修复后的代码
import operator def collect_data(filename): data = dict() with open(filename, 'r') as h: for line in h: four_vals = line.split(',') # 转换批次为整数,处理可能的空格 batch = int(four_vals[0].strip()) if batch not in data: data[batch] = [] try: x = float(four_vals[1].strip()) y = float(four_vals[2].strip()) val = float(four_vals[3].strip()) data[batch].append((x, y, val)) except ValueError: print(f"Warning: Could not parse line '{line.strip()}' - skipping.") # 返回按批次数字排序后的列表 return sorted(data.items(), key=operator.itemgetter(0)) def average(sorted_data): for batch, sample in sorted_data: zero_data = len(sample) == 0 average_val = None if not zero_data: n = 0 x_sum = 0 for (x, y, val) in sample: if x**2 + y**2 <= 1: x_sum += val n += 1 try: average_val = x_sum / n except ZeroDivisionError: print(f"Batch {batch}: All measurements are outside the unit circle") continue print_average(batch, average_val, zero_data) def print_average(batch, average_val, zero_data): if zero_data: print(f"{batch}\tNo data") else: print(f"{batch}\t{average_val:.4f}") # 格式化输出更美观 def main(): ''' This is the main body of the program. ''' filename = input('Which data file? ') sorted_data = collect_data(filename) average(sorted_data) # Start the main program: This is idiomatic python if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者idlatva
相关产品推荐
相关产品推荐

