简体   繁体   English

我可以使用Variablized String Literal替换部分Python“If”语句吗?

[英]Can I Replace Part of a Python “If” Statement with a Variablized String Literal?

I have a very long question with what may be a very short answer. 我有一个很长的问题,可能是一个非常简短的答案。

I'm very new to Python (almost two weeks, now) but I've used VBScript for many years so I understand many of the basic concepts. 我是Python的新手(差不多两周,现在),但我已经使用了很多年的VBScript,所以我理解了许多基本概念。

I've searched Stack Overflow and the internet for a solution but haven't been able to find anything; 我搜索了Stack Overflow和互联网寻求解决方案但却找不到任何东西; I'm not sure if this is even possible in Python, but I'd be a bit surprised if it's not. 我不确定这在Python中是否可行,但如果不是,我会有点惊讶。 I've written a file-search program using Python3 that allows users to search their computer for files. 我使用Python3编写了一个文件搜索程序,允许用户在他们的计算机上搜索文件。 The user can choose to search based on several different parameters: name, size range, date-modified range and, for non-Linux systems, date-created range. 用户可以选择基于几个不同的参数进行搜索:名称,大小范围,日期修改范围,对于非Linux系统,可以选择日期创建的范围。 The search functionaly works quite well for each individual parameter as well as for combinations of parameters (which, by the way, is in no small part thanks to the many answers / discussions I've found here on Stack Overflow). 搜索功能对于每个单独的参数以及参数的组合都能很好地工作(顺便说一句,这要归功于我在Stack Overflow上找到的许多答案/讨论)。 My problem is that the actual search is rather inelegant and, I believe, slower than it could be. 我的问题是,实际的搜索相当不优雅,我相信,它的速度可能比它慢。 The program uses flags (NOT true Python flags, that's just what I happen to call them) to set the search options. 该程序使用标志(不是真正的Python标志,这就是我碰巧称之为),来设置搜索选项。 Let me illustrate with some pseudo code: 让我用一些伪代码来说明:

    # 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

That's only for 3 possible combinations - there are 14 total. 这仅适用于3种可能的组合 - 总共有14种。 While I don't really have a problem with typing all the combinations out, I believe this would severely impact the speed and efficiency of the search. 虽然输入所有组合时我没有遇到任何问题,但我相信这会严重影响搜索的速度和效率。

I've thought of another solution that is a bit more elegant and would probably execute faster, but I still think there's a better method: 我想到了另一个更优雅的解决方案,并且可能执行得更快,但我仍然认为有更好的方法:

    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

Again, this is a bit more elegant and (I believe) a great deal more efficient, but still not ideal. 再次,这更优雅,(我相信)效率更高,但仍然不理想。 What I'd like to do is create ONE "if" statement based on the user's search criteria and use that to conduct the search (note that something similar is possible in VBScript). 我想做的是根据用户的搜索条件创建一个“if”语句,并使用它来进行搜索(注意在VBScript中可能有类似的东西)。 These statements would go BEFORE the search statements take place: 这些陈述将在搜索语句发生之前发生:

Possible option 1: 可能的选择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

Possible option 2: 可能的选择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

And then plug "iClause" in to my search statement like so: 然后将“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

This would streamline the code, making it easier to read and maintain and (I believe) make it more efficient and speedy. 这将简化代码,使其更易于阅读和维护,并且(我相信)使其更加高效和快速。

Is this possible with Python? 这可能与Python有关吗?


Edit: 编辑:

I thank all of you for taking the time to read my lengthy question, but I don't believe you got what I was asking - most likely due to its (over)verbosity. 我感谢你们所有人花时间阅读我冗长的问题,但我不相信你得到的是我所要求的 - 很可能是因为它(过度)冗长。

I would like to know how to implement the following: 我想知道如何实现以下内容:

    a = "sMinSize < fileSize < sMaxSize"
    b = "and sMinSize < fileSize < sMaxSize"
    iClause = a+b

Then plug 'iClause' into my "if" statement as follows: 然后将“iClause”插入我的“if”语句中,如下所示:

    if iClause:
        do_stuff

This would basically be turning a string literal into a variable, then using that variablized (probably not a real word) string literal as my statement. 这基本上是将字符串文字转换为变量,然后使用变量化(可能不是真正的单词)字符串文字作为我的语句。 I hope that was clearer. 我希望这更清楚。

Create a predicate function, one for each case. 创建一个谓词函数,每个案例一个。 Determine what cases you're using and use the associated predicate. 确定您正在使用的案例并使用关联的谓词。 Collect chosen predicates in a list (or compose them into a new predicate) then apply in your loop: 在列表中收集选定的谓词(或将它们组合成新的谓词)然后在循环中应用:

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

You may want to use a named function instead of a lambda depending on your preferences. 您可能希望使用命名函数而不是lambda,具体取决于您的首选项。 And for more complex scenarios, you may want to implement these as functors instead. 对于更复杂的场景,您可能希望将它们实现为仿函数。

Here's a bit of lateral thinking. 这里有一些横向思维。 If you look for things that match criteria, they must all match. 如果你寻找符合标准的东西,它们必须全部匹配。 But if you look for things that don't match, just one needs to be wrong to disqualify. 但是如果你寻找不匹配的东西,那么取消资格只需要一个错误。 So you don't need to write complex queries; 所以你不需要编写复杂的查询; just checking one option at a time is good enough. 只需一次检查一个选项就足够了。 And you can do it in a loop! 你可以循环完成!

# 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

I've found the solution - the "eval()" function. 我找到了解决方案 - “eval()”函数。 This will do exactly what I've been looking for. 这将完全符合我一直在寻找的。 With this I can define my search fragments and write several short "if" statements that look like this: 有了这个,我可以定义我的搜索片段,并编写几个简短的“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

Now that my search string has been put together, I plug it into my "for" loop: 现在我的搜索字符串已经放在一起,我将它插入我的“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

With my search string created before the "for" loop begins, it doesn't have to leave the loop to check for each condition. 在“for”循环开始之前创建了我的搜索字符串,它不必离开循环来检查每个条件。 This should be a relatively efficient search. 应该是一个相对有效的搜索。

Now ... does anybody see anything wrong with this solution? 现在......有没有人看到这个解决方案有什么问题?

Final Edit: 最终编辑:

Per the advice (and admonition) I've received, the "eval" function was not my solution. 根据我收到的建议(和告诫),“eval”功能不是我的解决方案。 Instead, I used the method suggested by Jeff. 相反,我使用了杰夫建议的方法。 His solution is faster, more efficient and easier to maintain. 他的解决方案更快,更高效,更易于维护。

Thanks again for everyone's input and advice! 再次感谢大家的意见和建议!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM