我正在弄乱*和**,并弄清楚这些运营商的用例是什么。为了这个"研究",我写了一个遍历目录的函数scandir_and_execute
(默认递归)并在遇到的每个文件上执行函数exec_func
。该函数是可变的,这意味着在调用scandir_and_execute
时,程序员可以指示在每个文件上运行哪个函数。另外,为了找出*
,我添加了一个func_args
变量(默认为空列表),可以包含任意数量的参数。
这个想法是程序员可以使用他们已定义(或内置)文件是第一个参数的任何exec_func
,并且他们自己在列表中提供所需的参数,然后在exec_func
电话上展开。
注意:运行此功能至少需要Python 3.5。
import os
def scandir_and_execute(root, exec_func, func_args=[], recursive=True, verbose=False):
if verbose:
print(f"TRAVERSING {root}")
# Use scandir to return iterator rather than list
for entry in os.scandir(root):
if entry.is_dir() and not entry.name.startswith('.'):
if recursive:
scan_and_execute(entry.path, exec_func, func_args, True, verbose)
elif entry.is_file():
if verbose:
print(f"\tProcessing {entry.name}")
# Unpack (splat) argument list, i.e. turn func_args into separate arguments and run exec_func
exec_func(entry.path, *func_args)
这是使用*
的正确方法,还是我误解了文档和运算符的概念?就我测试过而来说,这个功能是有效的,但也许我做了一些警告或非pythonic的事情?例如,编写这样的函数会更好吗?未命名的"多余的"参数是一起组合的(或另一种方式)?
def scandir_and_execute(root, exec_func, recursive=True, verbose=False, *func_args):
答案 0 :(得分:1)
是你如何使用splat运算符,但要考虑它是否需要你的函数根据参数传递参数。假设您现在正在使用它:
scandir_and_execute(root, foo, (foo_arg1, foo_arg2), recursive=True)
你可以重写scandir_and_execute
接受一个可调用的一个参数:
def scandir_and_execute(root, exec_func, recursive=True, verbose=False):
if verbose:
print(f"TRAVERSING {root}")
# Use scandir to return iterator rather than list
for entry in os.scandir(root):
if entry.is_dir() and not entry.name.startswith('.'):
if recursive:
scandir_and_execute(entry.path, exec_func, True, verbose)
elif entry.is_file():
if verbose:
print(f"\tProcessing {entry.name}")
exec_func(entry.path)
让调用者处理其业务:
scandir_and_execute(root, lambda path: foo(path, foo_arg1, foo_arg2))
然后完全放弃回调并创建一个生成器:
def scandir(root, recursive=True, verbose=False):
if verbose:
print(f"TRAVERSING {root}")
# Use scandir to return iterator rather than list
for entry in os.scandir(root):
if entry.is_dir() and not entry.name.startswith('.'):
if recursive:
yield from scandir(entry.path, True, verbose)
elif entry.is_file():
if verbose:
print(f"\tProcessing {entry.name}")
yield entry.path
for path in scandir(root, recursive=True):
foo(path, foo_arg1, foo_arg2)
(接近walk
,但不完全!)现在非递归版本就是这个生成器:
(entry.path for entry in os.scandir(root) if entry.is_file())
所以你也可以只提供递归版本:
import os
def is_hidden(dir_entry):
return dir_entry.name.startswith('.')
def scandir_recursive(root, *, exclude_dir=is_hidden):
for entry in os.scandir(root):
yield entry
if entry.is_dir() and not exclude_dir(entry):
yield from scandir_recursive(entry.path, exclude_dir=exclude_dir)
import logging
logging.info(f'TRAVERSING {root}')
for entry in scandir_recursive(root):
if entry.is_dir():
logging.info(f'TRAVERSING {entry.path}')
elif entry.is_file():
logging.info(f'\tProcessing {entry.name}')
foo(entry.path, foo_arg1, foo_arg2)