簡體   English   中英

python變量內容在不打算更改的情況下被函數更改

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM