python 目录装饰器
python decorator for directory
我经常发现自己在写一个 python 脚本,它接受参数:
python my_script.py input_file output_file other_parameter_a other_parameter_b optional_parameter_c
现在,我想要选择 运行 单个文件上的脚本,就像上面那样,或者 运行 目录中的每个文件上的脚本。我发现自己正在编写一个新脚本 my_script_run_on_directory.py
来查找目录中的每个文件,然后调用 my_script.py
所以,我会:
python my_script_run_on_directory.py directory_input directory_output other_parameter_a other_parameter_b optional_parameter_c
我需要经常这样做,并且我一直在为每个 my_script
编写一个新的目录脚本。有一个更好的方法吗?我想过使用装饰器,但不确定最好的方法是什么。
我想我想要的是
python general_run_on_directory_script.py my_script directory_input directory_output <and all other paremeters needed for my_script>
关于你问的用什么。一般来说,我会说将通用代码抽象到一个以特定函数作为参数的函数中。使用装饰器是一种相当干净的方式来做到这一点。所以在我看来,是的,这是一个很好的解决方案。
简单的情况(总是期望你的函数有相同的参数):
import os
#Define decorator, takes the function to execute as an argument
def dir_or_file_decorator(func):
def newFunc(path):
if os.path.isdir(path):
filenames = os.listdir(path)
for filename in filenames:
filepath = os.path.join(path,filename)
func(filepath)
else:
func(path)
return newFunc
#Define the function we want to decorate
@dir_or_file_decorator
def print_file_name(filepath):
print filepath
#Run some tests
print 'Testing file'
print_file_name(r'c:\testdir\testfile1.txt')
print 'Testing dir'
print_file_name(r'c:\testdir')
#The @decorator is just syntactic sugar. The code below shows what actually happens
def print_file_name2(filepath):
print filepath
decorated_func = dir_or_file_decorator(print_file_name2)
print 'Testing file'
decorated_func(r'c:\testdir\testfile1.txt')
print 'Testing dir'
decorated_func(r'c:\testdir')
#Output:
# Testing file
# c:\testdir\testfile1.txt
# Testing dir
# c:\testdir\testfile1.txt
# c:\testdir\testfile2.txt
更复杂的案例:
函数中的额外参数:
import os
def dir_or_file_decorator(func):
def newFunc(path, *args, **kwargs):
if os.path.isdir(path):
filenames = os.listdir(path)
for filename in filenames:
filepath = os.path.join(path,filename)
func(filepath, *args, **kwargs)
else:
func(path, *args, **kwargs)
return newFunc
@dir_or_file_decorator
def print_file_name_and_args(path, extra):
print extra, path
#We can use the parameter order in the function (our decorator assumes path is the first one)
print_file_name_and_args(r'c:\testdir', 'extra for test 1')
#Or we can just be safe and use named arguments (our decorator assumes the argument is named path)
print_file_name_and_args(extra='extra for test 1', path=r'c:\testdir')
#A combination of both is possible too (but I feel it's more complicated and hence more prone to error)
print_file_name_and_args(r'c:\testdir', extra='extra for test 1')
#Output (in all 3 cases):
# extra for test 1 c:\testdir\testfile1.txt
# extra for test 1 c:\testdir\testfile2.txt
也必须 return 值:
import os
def dir_or_file_decorator_with_results(concatenateResultFunc):
def dir_or_file_decorator(func):
def newFunc(path, *args, **kwargs):
if os.path.isdir(path):
results = []
filenames = os.listdir(path)
for filename in filenames:
filepath = os.path.join(path,filename)
results.append(func(filepath, *args, **kwargs))
return concatenateResultFunc(results)
else:
return func(path, *args, **kwargs)
return newFunc
return dir_or_file_decorator
#Our function to concatenate the results in case of a directory
def concatenate_results(results):
return ','.join(results)
#We pass the function used to concatenate the results in case of a directory when we apply to decorator
#What happens is that we create a new dir_or_file_decorator that uses the specified concatenateResultFunc
#That newly created decorator is then applied to our function
@dir_or_file_decorator_with_results(concatenate_results)
def get_file_name_and_args(extra, path):
return extra + ' -> ' + path
#Test again
print get_file_name_and_args(r'c:\testdir', 'extra for test 1')
#Output:
# c:\testdir\testfile1.txt -> extra for test 1,c:\testdir\testfile2.txt -> extra for test 1
我经常发现自己在写一个 python 脚本,它接受参数:
python my_script.py input_file output_file other_parameter_a other_parameter_b optional_parameter_c
现在,我想要选择 运行 单个文件上的脚本,就像上面那样,或者 运行 目录中的每个文件上的脚本。我发现自己正在编写一个新脚本 my_script_run_on_directory.py
来查找目录中的每个文件,然后调用 my_script.py
所以,我会:
python my_script_run_on_directory.py directory_input directory_output other_parameter_a other_parameter_b optional_parameter_c
我需要经常这样做,并且我一直在为每个 my_script
编写一个新的目录脚本。有一个更好的方法吗?我想过使用装饰器,但不确定最好的方法是什么。
我想我想要的是
python general_run_on_directory_script.py my_script directory_input directory_output <and all other paremeters needed for my_script>
关于你问的用什么。一般来说,我会说将通用代码抽象到一个以特定函数作为参数的函数中。使用装饰器是一种相当干净的方式来做到这一点。所以在我看来,是的,这是一个很好的解决方案。
简单的情况(总是期望你的函数有相同的参数):
import os
#Define decorator, takes the function to execute as an argument
def dir_or_file_decorator(func):
def newFunc(path):
if os.path.isdir(path):
filenames = os.listdir(path)
for filename in filenames:
filepath = os.path.join(path,filename)
func(filepath)
else:
func(path)
return newFunc
#Define the function we want to decorate
@dir_or_file_decorator
def print_file_name(filepath):
print filepath
#Run some tests
print 'Testing file'
print_file_name(r'c:\testdir\testfile1.txt')
print 'Testing dir'
print_file_name(r'c:\testdir')
#The @decorator is just syntactic sugar. The code below shows what actually happens
def print_file_name2(filepath):
print filepath
decorated_func = dir_or_file_decorator(print_file_name2)
print 'Testing file'
decorated_func(r'c:\testdir\testfile1.txt')
print 'Testing dir'
decorated_func(r'c:\testdir')
#Output:
# Testing file
# c:\testdir\testfile1.txt
# Testing dir
# c:\testdir\testfile1.txt
# c:\testdir\testfile2.txt
更复杂的案例:
函数中的额外参数:
import os
def dir_or_file_decorator(func):
def newFunc(path, *args, **kwargs):
if os.path.isdir(path):
filenames = os.listdir(path)
for filename in filenames:
filepath = os.path.join(path,filename)
func(filepath, *args, **kwargs)
else:
func(path, *args, **kwargs)
return newFunc
@dir_or_file_decorator
def print_file_name_and_args(path, extra):
print extra, path
#We can use the parameter order in the function (our decorator assumes path is the first one)
print_file_name_and_args(r'c:\testdir', 'extra for test 1')
#Or we can just be safe and use named arguments (our decorator assumes the argument is named path)
print_file_name_and_args(extra='extra for test 1', path=r'c:\testdir')
#A combination of both is possible too (but I feel it's more complicated and hence more prone to error)
print_file_name_and_args(r'c:\testdir', extra='extra for test 1')
#Output (in all 3 cases):
# extra for test 1 c:\testdir\testfile1.txt
# extra for test 1 c:\testdir\testfile2.txt
也必须 return 值:
import os
def dir_or_file_decorator_with_results(concatenateResultFunc):
def dir_or_file_decorator(func):
def newFunc(path, *args, **kwargs):
if os.path.isdir(path):
results = []
filenames = os.listdir(path)
for filename in filenames:
filepath = os.path.join(path,filename)
results.append(func(filepath, *args, **kwargs))
return concatenateResultFunc(results)
else:
return func(path, *args, **kwargs)
return newFunc
return dir_or_file_decorator
#Our function to concatenate the results in case of a directory
def concatenate_results(results):
return ','.join(results)
#We pass the function used to concatenate the results in case of a directory when we apply to decorator
#What happens is that we create a new dir_or_file_decorator that uses the specified concatenateResultFunc
#That newly created decorator is then applied to our function
@dir_or_file_decorator_with_results(concatenate_results)
def get_file_name_and_args(extra, path):
return extra + ' -> ' + path
#Test again
print get_file_name_and_args(r'c:\testdir', 'extra for test 1')
#Output:
# c:\testdir\testfile1.txt -> extra for test 1,c:\testdir\testfile2.txt -> extra for test 1