[英]python variable contents changed by function when no change is intended
這是一個代碼示例,其中對一個輸入變量(good_ens除外)的大多數輸入變量使用新信息重復運行一個函數。 不應更改的輸入變量good_ens被更改。 這里發生了什么? 這違背了我對范圍的理解。
def doFile(infileName, outfileName, goodens, timetype, flen):
print('infilename = %s' % infileName)
print('outfilename = %s' % outfileName)
print('goodens at input are from %d to %d' % (goodens[0],goodens[1]))
print('timetype is %s' % timetype)
maxens = flen # fake file length
print('%s time variable has %d ensembles' % (infileName,maxens))
# TODO - goodens[1] has the file size from the previous file run when multiple files are processed!
if goodens[1] < 0:
goodens[1] = maxens
print('goodens adjusted for input file length are from %d to %d' % (goodens[0],goodens[1]))
nens = goodens[1]-goodens[0]
print('creating new netCDF file %s with %d records (should match input file)' % (outfileName, nens))
# user settings
datapath = ""
datafiles = ['file0.nc',\
'file1.nc',\
'file2.nc',\
'file3.nc']
# fake file lengths for this demonstration
datalengths = [357056, 357086, 357060, 199866]
outfileroot = 'outfile'
attFile = datapath + 'attfile.txt'
# this gets changed! It should never be changed!
# ask for all ensembles in the file
good_ens = [0,-1]
# -------------- beyond here the user should not need to change things
for filenum in range(len(datafiles)):
print('\n--------------\n')
print('Input Parameters before function call')
print(good_ens)
inputFile = datapath + datafiles[filenum]
print(inputFile)
l = datalengths[filenum]
print(l)
outputFile = datapath + ('%s%03d.cdf' % (outfileroot,filenum))
print(outputFile)
print('Converting from %s to %s' % (inputFile,outputFile))
# the variable good_ens gets changed by this calling function, and should not be
doFile(inputFile, outputFile, good_ens, 'CF', l)
# this works, but will not work for me in using this function
#doNortekRawFile(inputFile, outputFile, [0,-1], 'CF', l)
for循環的前兩次迭代的輸出如下。 注意good_ens從[0,-1]更改為函數內部的goodens值。 為什么? 沒關系,變量名的區別,它們甚至不共享相同的作用域。
--------------
Input Parameters before function call
[0, -1]
file0.nc
357056
outfile000.cdf
Converting from file0.nc to outfile000.cdf
infilename = file0.nc
outfilename = outfile000.cdf
goodens at input are from 0 to -1
timetype is CF
file0.nc time variable has 357056 ensembles
goodens adjusted for input file length are from 0 to 357056
creating new netCDF file outfile000.cdf with 357056 records (should match input file)
--------------
Input Parameters before function call
[0, 357056]
file1.nc
357086
outfile001.cdf
Converting from file1.nc to outfile001.cdf
infilename = file1.nc
outfilename = outfile001.cdf
goodens at input are from 0 to 357056
timetype is CF
file1.nc time variable has 357086 ensembles
goodens adjusted for input file length are from 0 to 357056
creating new netCDF file outfile001.cdf with 357056 records (should match input file)
--------------
這里有一個類似的問題:
超出循環范圍時,Python的屬性發行值更改
但是我不想將變量good_ens嵌入到for循環中。 我希望它的值由用戶在腳本開頭設置一次,然后在for循環中使用。
調用doFile
時,請嘗試以下操作:
doFile(inputFile, outputFile, list(good_ens), 'CF', l)
我是這樣想的:列表是一個指向列表中每個元素的值的東西。 當您將列表傳遞給函數時, 執行指向操作的對象將被復制,但是指向對象 的值將不會被復制。
執行list(good_ens)
實際上會在列表元素的內存中進行復制,並且將保持原始值不變。 見下文:
>>> def change_list(the_list):
... the_list[0] = 77
... return
...
>>> a=[0,1,2,3,4]
>>> change_list(a)
>>> a
[77, 1, 2, 3, 4]
>>>
>>> a=[0,1,2,3,4]
>>> change_list(list(a))
>>> a
[0, 1, 2, 3, 4]
編輯:這樣做的原因是,正如其他答案所示,列表是python中的可變數據類型。 可變數據類型可以更改,而可變數據類型不能更改,而是在嘗試更新時返回新對象。
在python中,列表是可變的。
>>> a = [1,2,3]
>>> def fun(d):
... d.append(55)
...
>>> a
[1, 2, 3]
>>> fun(a)
>>> a
[1, 2, 3, 55]
>>> fun(a[:])
>>> a
[1, 2, 3, 55]
>>> fun(a)
>>> a
[1, 2, 3, 55, 55]
如果希望它們不可變,請考慮使用元組。
其他答案包括列表可變的想法。 下面是一種可能的重構,它以我認為是明智的方式解決了這個問題。
def doFile(infileName, outfileName, goodens, timetype, flen):
# ...
min_ens, max_ens = goodens
if max_ens < 0:
max_ens = flen
nens = max_ens - min_ens
# ...
這樣,您仍然可以像往常一樣調用該函數,該函數中的變量將更恰當地命名,並且您從不更改提供的列表對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.