我有一个很长的问题,可能是一个非常简短的答案。
我是Python的新手(差不多两周,现在),但我已经使用了很多年的VBScript,所以我理解了许多基本概念。
我在Stack Overflow和互联网上搜索了一个解决方案但却找不到任何东西;我不确定这在Python中是否可行,但如果不是,我会有点惊讶。 我使用Python3编写了一个文件搜索程序,允许用户在他们的计算机上搜索文件。用户可以选择基于几个不同的参数进行搜索:名称,大小范围,日期修改范围,对于非Linux系统,可以选择日期创建的范围。搜索功能对于每个单独的参数以及参数的组合都能很好地工作(顺便说一句,这要归功于我在Stack Overflow上找到的许多答案/讨论)。 我的问题是,实际的搜索相当不优雅,我相信,它的速度可能比它慢。该程序使用标志(不是真正的Python标志,这就是我碰巧称之为),来设置搜索选项。让我用一些伪代码来说明:
# Variables get their values from user entry
sName = "test" # string to search for
sMinSize = 2 # minimum search-by size in MB
sMaxSize = 15 # maximum search-by size in MB
sModded1 = 2008-01-23 # earliest modified-by date
sModded2 = 2017-08-22 # latest modified-by date
sCreated1 = 2008-01-23 # earliest created-by date
sCreated2 = 2017-08-22 # latest created-by date
# Search parameters - choosing one of these changes the value from 0 to 1:
flagName = 0 # search by name
flagSize = 0 # search by size
flagModified = 0 # search by last modified date
flagCreated = 0 # search by last created date
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
fileDate = os.path.getmtime(fName)
fileSize = os.stat(fName).st_size
if flagName = 1:
if fName.find(sName) > 0:
do_stuff
elif flagSize = 1:
if sMinSize < fileSize < sMaxSize:
do_stuff
elif flagName = 1 and flagSize = 1:
if fName.find(sName) > 0 and if sMinSize < fileSize < sMaxSize:
do_stuff
... etc
这仅适用于3种可能的组合 - 总共有14种。虽然输入所有组合并没有问题,但我相信这会严重影响搜索的速度和效率。
我想到了另一种更优雅的解决方案,并且可能执行得更快,但我仍然认为有更好的方法:
if flagName = 1:
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
fileDate = os.path.getmtime(fName)
fileSize = os.stat(fName).st_size
if fName.find(sName) > 0:
do_stuff
elif flagName = 1 and flagSize = 1:
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
fileDate = os.path.getmtime(fName)
fileSize = os.stat(fName).st_size
if fName.find(sName) > 0 and if sMinSize < fileSize < sMaxSize:
do_stuff
... etc
同样,这更优雅,(我相信)效率更高,但仍然不理想。 我想做的是根据用户的搜索条件创建一个“if”语句,并使用它来进行搜索(注意在VBScript中可能有类似的东西)。这些陈述将在搜索语句发生之前进行:
可能的选项1:
if flagName = 1:
iClause = "fName.find(sName) > 0"
elif flagName = 1 and flagSize = 1:
iClause = "fName.find(sName) > 0 and if sMinSize < fileSize < sMaxSize"
... etc
可能的选项2:
flagClause = 0
if flagName = 1:
iClause = "fName.find(sName) > 0"
flagClause = flagClause + 1
if flagClause = 0
iClause = "sMinSize < fileSize < sMaxSize"
else:
iClause = iClause + "and sMinSize < fileSize < sMaxSize"
flagClause = flagClause + 1
... etc
然后将“iClause”插入我的搜索语句中,如下所示:
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
fileDate = os.path.getmtime(fName)
fileSize = os.stat(fName).st_size
if **iClause**:
do_stuff
这将简化代码,使其更易于阅读和维护,并且(我相信)使其更加高效和快速。
这可以用Python吗?
修改
我感谢你们所有人花时间阅读我冗长的问题,但我不相信你得到的是我所要求的 - 很可能是因为它(过度)冗长。
我想知道如何实现以下内容:
a = "sMinSize < fileSize < sMaxSize"
b = "and sMinSize < fileSize < sMaxSize"
iClause = a+b
然后将“iClause”插入我的“if”语句中,如下所示:
if iClause:
do_stuff
这基本上是将字符串文字转换为变量,然后使用变量化(可能不是真正的单词)字符串文字作为我的语句。 我希望这更清楚。
答案 0 :(得分:3)
创建一个谓词函数,每个案例一个。确定您正在使用的案例并使用关联的谓词。在列表中收集选定的谓词(或将它们组合成新的谓词),然后在你的循环中应用:
predicates = []
if flagName:
predicates.append(lambda fileName: fileName.find(sName) > 0)
if flagSize:
predicates.append(lambda fileName: sMinSize < os.stat(fileName).st_size < sMaxSize)
if flagModified:
predicates.append(lambda fileName: sModded1 < os.path.getmtime(fileName) < sModded2)
if flagCreated:
predicates.append(lambda fileName: sCreated1 < os.path.getctime(fileName) < sCreated2)
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
if all(p(fName) for p in predicates):
# do stuff
根据您的偏好,您可能希望使用命名函数而不是lambda。对于更复杂的场景,您可能希望将它们实现为仿函数。
答案 1 :(得分:1)
这是一些横向思考。如果你寻找符合标准的东西,它们必须全部匹配。但是如果你寻找不匹配的东西,那么取消资格只需要一个错误。所以你不需要编写复杂的查询;只需一次检查一个选项就足够了。你可以循环做到这一点!
# supplied by user (you might want to look into argparse)
options = {
"name": "jpg"
"minsize": "1024"
}
# checking code
option_checkers: {
"name": lambda fName, limit: fName.find(limit) != -1
"minsize": lambda fName, limit: limit <= os.stat(fName).st_size
"maxsize": lambda fName, limit: os.stat(fName).st_size < limit
}
def okay(fName, options):
for option, limit in options.items():
if not option_checkers[option](fName, limit)
return False
return True
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
if okay(fName, options):
# fits all criteria: do stuff
答案 2 :(得分:-1)
我找到了解决方案 - “eval()”函数。这将完全符合我一直在寻找的。有了这个,我可以定义我的搜索片段并编写几个简短的“if”语句,如下所示:
flagClause = 0
if flagName = 1:
iClause = "fName.find(sName) > 0"
flagClause = flagClause + 1
if flagClause = 0
iClause = "sMinSize < fileSize < sMaxSize"
else:
iClause = iClause + "and sMinSize < fileSize < sMaxSize"
flagClause = flagClause + 1
... etc
现在我的搜索字符串已经放在一起,我将其插入我的“for”循环:
for root, dirs, files in os.walk(strPath, followlinks=False):
for fName in files:
fileDate = os.path.getmtime(fName)
fileSize = os.stat(fName).st_size
if eval(iClause):
do_stuff
在我的搜索字符串之前“for”循环开始时,它不必离开循环来检查每个条件。 应该是一个相对有效的搜索。
现在......有没有人看到这个解决方案有什么问题?
最终修改:
根据我收到的建议(和告诫),“eval”功能不是我的解决方案。相反,我使用了杰夫建议的方法。他的解决方案更快,更高效,更易于维护。
再次感谢大家的意见和建议!