2011-07-18 60 views
3

我正在編寫腳本來批量重命名文件夾內的所有文件。我試圖使它成爲模塊化的,所以核心算法(生成新文件名的算法)很容易交換。意外的名稱錯誤

這裏是我到目前爲止有:

from os import listdir, rename 

def renamer(path, algorithm, counter=False, data=None, data2=None, safe=True): 

    call_string = 'new=algorithm(i' 
    if counter: 
     call_string += ', file_index' 
    if data != None: 
     call_string += ', data' 
    if data2 != None: 
     call_string += ', data2' 
    call_string += ')' 

    if safe: 
     print('Press Enter to accept changes. '+ 
     'Type anything to jump to the next file.\n') 

    files_list = listdir(path) 
    for i in files_list: 
     file_index = files_list.index(i) 
     old = i 
     exec(call_string) 
     if safe: 
      check = input('\nOld:\n'+old+'\nNew:\n'+new+'\n\nCheck?\n\n') 
      if check is not '': 
       continue 
     rename(path+old, path+new) 

    return 

現在由於某種原因(似乎unexplicable對我來說),調用函數引發NameError:

>>> def f(s): 
    return 'S08'+s 

>>> path='C:\\Users\\****\\test\\' 
>>> renamer(path, f) 
Press Enter to accept changes. Type anything to jump to the next file. 

Traceback (most recent call last): 
    File "<pyshell#39>", line 1, in <module> 
    renamer(path, f) 
    File "C:\Python32\renamer.py", line 25, in renamer 
    check = input('\nOld:\n'+old+'\nNew:\n'+new+'\n\nCheck?\n\n') 
NameError: global name 'new' is not defined 

Unexplicable因爲,在第25行它應該已經執行了call_string,從而定義了新的名稱。 我一直試圖找出我的錯誤現在一個多小時,我已經通過了整個代碼輸入行的線兩次進入外殼,它運行良好,我似乎無法找出問題。

有人可以幫我找出我出錯的地方嗎?

編輯: 我已經猜到有可能不能分配使用EXEC的名字,所以我如下測試它,和它的工作:

>>> exec('cat="test"') 
>>> cat 
'test' 
+2

呃,呃,呃!!!!不要像這樣使用'exec'!讓人們寫出他們自己的名字,生成_functions_並傳給他們! – katrielalex

回答

3

不要使用EXEC或EVAL對於這一點,和只寫

new = algorithm(i, file_index, data, data2) 

確保所有的算法,可以使用4個參數(忽略那些他們並不需要)。

如果你不喜歡這一點,以下是比使用eval更符合Python和高效:

args = [i] 
if counter: 
    args.append(file_index) 
for arg in (data, data2): 
    if arg is not None: 
     args.append(arg) 

new = algorithm(*args) 

而且醜陋的替代:

for i in files_list: 
    file_index = files_list.index(i) 

for index, filename in enumerate(file_list): 
    ... 

最後,使用os.path.join來連接路徑部分而不是字符串連接。當您使用目錄名稱調用沒有尾隨的'/'功能時,這將爲您節省調試時間。

+0

thx,不錯的提示。我將通過一個字符串來調用算法,但是,由於我發現使用參數定義函數並不需要干擾^^ – Axim

+1

@Axim:我堅持認爲,你真的想限制你使用eval和exec在你的Python代碼。我已經添加了一種避免它的方法,它使您不會爲算法添加不必要的參數。 –

+2

@Axim:雖然'exec'和'eval'有一些合法的用途,這肯定不是其中的一個!一個經驗法則是先考慮exec/eval一個「代碼味道」,並且只有在認真努力證明自己和其他人之後才允許這些 - 而不是這種情況。 – mjv

1

你聲明的名稱newexec -call裏面。外面看不見。這就是爲什麼在撥打exec後嘗試訪問new而不是在exec的內部時,生成錯誤的原因。

我看不出有什麼理由爲什麼你會在這裏首先使用exec。您建立call_string的方式,您可以直接撥打algorithm

如果您確實希望您的算法能夠採用可變參數,請使用keyword arguments

+0

我構建call_string的方式是因爲有時我希望它們能夠使用多達4個參數,而有時(如示例中)我只是希望它們使用一個參數。 – Axim

+0

你可以只需要(這應該寫在你的文檔中),'algorithm'應該能夠使用1到4個參數。 –

0

更改call_string = 'new=algorithm(i'call_string = 'algorithm(i'並將exec(call_string)更改爲new = eval(call_string)並且您不應該有任何問題。

+0

thx工作很好:) – Axim

+0

@Axim接受答案,如果它是你想要的。 – agf

+1

@Axim:雖然這可能效果很好,但請注意,'exec'和'eval' [幾乎從不是合適的選擇](http://stackoverflow.com/questions/1832940/)。如果你想提高你的Python程序員的技能,不要在這裏使用它。請。 –

1

您不需要exec

def renamer(path, algorithm, counter=False, data=None, data2=None, safe=True): 

    if safe: 
     print('Press Enter to accept changes. '+ 
     'Type anything to jump to the next file.\n') 

    files_list = listdir(path) 
    for file_index, old in enumerate(files_list): 
     opt_args = [] 
     if counter: 
      opt_args.append(file_index) 
     if data is not None: 
      opt_args.append(data) 
     if data2 is not None: 
      opt_args.append(data2) 
     new = algorithm(old, *opt_args) 
     if safe: 
      check = input('\nOld:\n'+old+'\nNew:\n'+new+'\n\nCheck?\n\n') 
      if check: 
       continue 
     rename(path+old, path+new) 

其他一些小問題:使其適應您可以調整傳遞給函數的參數使用「不無」,而不是「=無!」看一個字符串是否爲空,只需使用「if check」;而且你不需要在函數結束時返回。我還包括@gurney alex建議的enumerate改進。