python 目录装饰器

标签 python scripting decorator

我经常发现自己编写了一个带有参数的 python 脚本:

python my_script.py 输入文件 输出文件 other_parameter_a other_parameter_b 可选_parameter_c

现在,我希望可以选择在单个文件上运行脚本(就像上面的操作一样),或者在目录中的每个文件上运行脚本。我发现自己编写了一个新脚本 my_script_run_on_directory.py ,它查找目录中的每个文件,然后调用 my_script.py 所以,我会:

python my_script_run_on_directory.py 目录输入 目录输出 other_parameter_a other_parameter_b 可选_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

还必须返回值:

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 目录装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28763321/

相关文章:

python - 使用分类列附加到 Pandas DataFrame

shell - shell脚本中的间接参数替换

Python SQLite 错误绑定(bind),带字符串的类型不受支持

python - 有没有办法从 python 解释器查看函数、类或模块的源代码?

python - 将新数据附加到python中的json文件中

命令行/脚本/解释环境中的 C# 或 Java?

shell - 在 KornShell 脚本中获取函数名称

python - 如何编写更新关键字参数的 python 装饰器?

Python 单元测试 : Nose @with_setup failing

python - 为什么 Python 中的 @foo.setter 对我不起作用?