2015-03-31 26 views
3

我有一个测试PsychoPy Builder脚本,我正在使用它来调查一些反直觉行为。其结构为四个程序:了解PsychoPy的数据记录

“初始化”,而不是在一个循环中,在“开始实验”下面的代码:

x = 0 
y = 0 
z = 0 
foo = [0, 0, 0] 

“一”,在一个循环中,在下面的代码“结束常规“:

x = x + 1 
foo[0] = foo[0] + 1 

thisExp.addData("x", x) 
thisExp.addData("y", y) 
thisExp.addData("z", z) 
thisExp.addData("foo", foo) 

“二”,在一个循环中,在下面的代码 “结束常规”:

y = y + 2 
foo[1] = foo[1] + 2 


thisExp.addData("x", x) 
thisExp.addData("y", y) 
thisExp.addData("z", z) 
thisExp.addData("fooY", foo[1]) 
thisExp.addData("foo", foo) 

“三国”,在厕所p,“End Routine”中的以下代码:

z = z + 3 
foo[2] = foo[2] + 3 

thisExp.addData("x", x) 
thisExp.addData("y", y) 
thisExp.addData("z", z) 
thisExp.addData("foo", foo) 

没有其他的代码,没有其他的组件。例程“一”,“二”和“三”形成一个循环,执行五次。 CSV输出文件的相关列如下:

trials.thisRepN trials.thisTrialN trials.thisN trials.thisIndex x y z foo   fooY 
0    0     0    0     1 2 3 [5, 10, 15] 2 
1    0     1    0     2 4 6 [5, 10, 15] 4 
2    0     2    0     3 6 9 [5, 10, 15] 6 
3    0     3    0     4 8 12 [5, 10, 15] 8 
4    0     4    0     5 10 15 [5, 10, 15] 10 

这是预期的输出吗?如果是这样,为什么?请注意,单个变量x,y和z每次通过循环显示更新后的值(循环结束时),而列表foo仅显示循环迭代五次后的最终值,但它在每一行显示了这一点。但是调出列表中的单个元素会显示为单个变量。

这是什么逻辑和基本原理?

有没有办法让列表输出像别人一样执行?

有没有办法强制输出捕获/显示任何这些变量,因为它们是当调用addData()时,而不是等到循环结束时?

回答

4

我想我知道这里出了什么问题。这可能是因为python通过引用而不是复制进行分配。这在别处,但简要地详细解释,

original = [1, 2] 
new = original # new is simply a reference to original! It is not a copy. 
new[0] = 'Oops' # original is now ['Oops', 2] as is new (which is just a reference or pointer 

在你的情况下,TrialHandler接收参考,它只是指出这是整个实验中更新了“foo”的变量。由于日志仅在实验结束时保存,因此“foo”中的所有行现在都指向“foo变量”,该变量现在保存值[5,10,15]。

此分配参考可以非常漂亮和方便,但有时会导致头痛,就像你的例子。它适用于所有python mutables:列表,字典,函数和类。但不适用于不可变数据,如数字,元组和字符串!这就是为什么你的脚本适用于数字而不是列表。

有不同的解决方案。最简单的可能是用thisExp.addData("foo", tuple(foo))替换addData调用,它将可变列表转换为不可变元组。人们也可以做thisExp.addData("foo", [x for x in foo])。对于所有类型的对象,更全面的解决方案是在实验开始时运行import copy,然后在其他代码块中添加像thisExp.addData("foo", copy.copy(foo))这样的数据(如果您有复杂的对象,请改为使用copy.deepcopy)。

+3

我想你已经在这里解决了这个问题,乔纳斯。但我认为你的答案的一个小改进是区分可变对象和不可变对象。列表和字典是可变的,所以会产生OP报告的反直觉行为,而元组不会变化,并且在这里不会出现奇怪的行为。所以PsychoPy只需要制作一个可变(=不可)对象的副本。 – jrgray 2015-03-31 18:48:26

+1

这与我所看到的一致。我会为追随我的脚步的其他人添加,如果使用列表列表(不同于我的玩具示例),则需要正确设置产生的列表理解。 – Novak 2015-03-31 19:08:48

+0

尽管我对“这是Python的工作方式”这个概念持异议,但自动暗示,“这在PsychoPy的日志记录中不是错误。”如果有人试图向数据日志中写入列表,他们想看到实际看到的行为,我会感到非常惊讶。 – Novak 2015-03-31 19:11:23