我正在编写一个脚本来批量重命名文件夹中的所有文件。我试图使其模块化,因此核心算法(生成新文件名的算法)很容易交换。
这是我到目前为止所得到的:
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
现在由于某种原因(对我来说似乎无法解释),调用该函数会引发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
无法解释,因为在第25行它应该已经执行了call_string,从而定义了名称new。 我一直试图弄清楚我的错误超过一个小时了,我已经完成整个代码进入线路两次进入shell,它运行良好,我似乎无法弄清楚问题。
有人可以帮我弄清楚我哪里出错吗?
编辑: 我已经猜到你可能无法使用exec分配名称,所以我测试了它如下,并且它有效:
>>> exec('cat="test"')
>>> cat
'test'
答案 0 :(得分:3)
不要使用exec或eval,只需编写
即可new = algorithm(i, file_index, data, data2)
确保所有算法都可以使用4个参数(忽略它们不需要的参数)。
如果您不喜欢这样,以下内容比使用eval更具有pythonic和效率:
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来连接路径部分而不是字符串连接。当您使用目录名称调用函数而没有尾随'/'
时,这将节省您的调试时间答案 1 :(得分:1)
您在new
- 来电中声明了名称exec
。它在外面是不可见的。这就是为什么当您在调用new
之后尝试访问exec
而不是exec
内部时,会生成错误。
我认为你没有任何理由在这里首先使用exec
。您构建call_string
的方式,可以直接调用algorithm
。
如果您真的希望算法能够采用变量参数,请使用keyword arguments。
答案 2 :(得分: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
改进。
答案 3 :(得分:0)
将call_string = 'new=algorithm(i'
更改为call_string = 'algorithm(i'
并将exec(call_string)
更改为new = eval(call_string)
,您不应该遇到任何问题。