2015-03-31 432 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