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

Python循环中拼接变量名并将save_i数据写入CSV的问题

问题:将循环生成的元组数据写入CSV文件

我尝试把while循环中生成的save_1至save_i(i等于counter的数值)每个变量作为一行写入CSV文件,每个save变量是包含counter、blast、time_to_button_press、time_to_blast_end的元组。

编写的代码如下:

# Packages
import msvcrt
import time
import sounddevice as sd
import soundfile as sf
import csv


# Settings
PLAY_TIME = 5  # in seconds


# Sound
sound_file_1 = 'C:/Users/am650/Desktop/Audio/aaa_1.mp3'
sound_file_2 = 'C:/Users/am650/Desktop/Audio/aaa_2.mp3'
blast_file_1, fs1 = sf.read(sound_file_1, dtype='float32')
blast_file_2, fs2 = sf.read(sound_file_2, dtype='float32')


# Set Up
time_start = time.perf_counter()
time_stop = time.perf_counter()
time_elapsed = time_stop - time_start
counter = 0

# Basic Logic
while time_elapsed < PLAY_TIME:
    blast = msvcrt.getch()
    if blast == b'1':
        blast = 1
        time_in = time.perf_counter()
        time_to_button_press = time_in - time_start
        sd.play(blast_file_1, device=4)
        status = sd.wait()
        time_in = time.perf_counter()
        time_to_blast_end = time_in - time_start
        counter += 1
        save = "save_"+str(counter)
        globals()[save] = (counter, blast, time_to_button_press, time_to_blast_end)
        print(eval("save_"+str(counter)))
        if time_to_blast_end > PLAY_TIME:
            break
    elif blast == b'2':
        blast = 2
        time_in = time.perf_counter()
        time_to_button_press = time_in - time_start
        sd.play(blast_file_2, device=4)
        status = sd.wait()
        time_in = time.perf_counter()
        time_to_blast_end = time_in - time_start
        counter += 1
        save = "save_"+str(counter)
        globals()[save] = (counter, blast, time_to_button_press, time_to_blast_end)
        print(eval("save_"+str(counter)))
        if time_to_blast_end > PLAY_TIME:
            break
    else:
        print("Invalid Entry")


with open('C:/Users/am650/Desktop/testdata.csv', 'w', newline='') as csvfile:
    datawriter = csv.writer(csvfile, delimiter=' ')
    for i in range(counter):
        datawriter.writerow(eval("save_"+str(i)))

遇到的问题:

  • 原代码返回空CSV文件
  • 直接写入字符串"save_"+str(i)得到变量名而非数据
  • 写入"save_"+str(counter)则重复最后一条数据且所有元素在同一列

期望CSV每行包含四个列,分别对应save变量中的四个元素,格式如下:

1, 4, 0.5, 1
2, 2, 1.7, 2.3
3, 5, 4, 4.5

本人主要使用R语言,代码不够优雅,请求帮助解决该问题。


解决方案

1. 替换动态变量为列表存储

用globals()创建save_1、save_2这类动态变量是Python中的不良实践,不仅维护麻烦,还容易出错。直接用一个列表统一存储所有生成的元组,操作更简洁可靠。

2. 修复循环终止逻辑

原代码中time_elapsed只在初始化时计算一次,循环内未更新,会导致循环无法正确终止。需要在每次循环开始时重新计算time_elapsed并判断是否超时。

3. 修正CSV写入逻辑

用列表存储数据后,直接遍历列表写入即可,无需使用不安全的eval。同时CSV默认分隔符为逗号,无需手动设置delimiter=' '。

修改后的完整代码:

# Packages
import msvcrt
import time
import sounddevice as sd
import soundfile as sf
import csv


# Settings
PLAY_TIME = 5  # in seconds


# Sound
sound_file_1 = 'C:/Users/am650/Desktop/Audio/aaa_1.mp3'
sound_file_2 = 'C:/Users/am650/Desktop/Audio/aaa_2.mp3'
blast_file_1, fs1 = sf.read(sound_file_1, dtype='float32')
blast_file_2, fs2 = sf.read(sound_file_2, dtype='float32')


# Set Up
time_start = time.perf_counter()
counter = 0
# 用列表存储所有数据,替代动态创建的save_1、save_2...
data_list = []

# Basic Logic
while True:
    time_elapsed = time.perf_counter() - time_start
    if time_elapsed >= PLAY_TIME:
        break
        
    blast = msvcrt.getch()
    if blast == b'1':
        blast = 1
        time_in = time.perf_counter()
        time_to_button_press = time_in - time_start
        sd.play(blast_file_1, device=4)
        status = sd.wait()
        time_in = time.perf_counter()
        time_to_blast_end = time_in - time_start
        counter += 1
        # 将元组添加到列表
        data_tuple = (counter, blast, time_to_button_press, time_to_blast_end)
        data_list.append(data_tuple)
        print(data_tuple)
        if time_to_blast_end > PLAY_TIME:
            break
    elif blast == b'2':
        blast = 2
        time_in = time.perf_counter()
        time_to_button_press = time_in - time_start
        sd.play(blast_file_2, device=4)
        status = sd.wait()
        time_in = time.perf_counter()
        time_to_blast_end = time_in - time_start
        counter += 1
        data_tuple = (counter, blast, time_to_button_press, time_to_blast_end)
        data_list.append(data_tuple)
        print(data_tuple)
        if time_to_blast_end > PLAY_TIME:
            break
    else:
        print("Invalid Entry")


with open('C:/Users/am650/Desktop/testdata.csv', 'w', newline='') as csvfile:
    # 默认分隔符是逗号,符合需求
    datawriter = csv.writer(csvfile)
    # 遍历列表写入每一行
    for row in data_list:
        datawriter.writerow(row)

关键修改说明

  • 新增data_list列表,每次生成数据直接append,避免动态变量的混乱
  • 循环改为while True,内部先计算time_elapsed并判断超时,确保循环能正确终止
  • CSV写入时直接遍历data_list,每个元组自动对应一行四列数据
  • 移除了不安全的eval和globals()操作,代码更简洁易维护

内容的提问来源于stack exchange,提问作者grace.cutler

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:05:02