【问题标题】:How to deal with multiple arguments in function?如何处理函数中的多个参数?
【发布时间】:2018-04-03 10:10:40
【问题描述】:

从函数中过滤掉数据的正确方法是什么?我应该尝试尽可能地压缩所有内容(search_query),还是应该在每次需要包含新参数时通过列表进行过滤(search_query2)。我有更多的论据,我会更快地变得更加困惑如何处理这个问题。示例:

import os

query = ""
my_path = os.getcwd()


def search_query(query, path, extensions_only=False, case_sensitive=False):
    results = []
    if extensions_only is True:
        for f in os.listdir(path):
            if case_sensitive:
                if f.endswith(query):
                    results.append(os.path.join(path, f))
            else:
                if f.endswith(query):
                    results.append(os.path.join(path, f).lower())

    elif case_sensitive is not True:
        for f in os.listdir(path):
            if query.lower() in f.lower():
                results.append(os.path.join(path, f))

    return results


results = search_query("_c", my_path)
print(results)


# Alternative way to deal with this
def search_query2(query, path, extensions_only=False, case_sensitive=False):
    results = []

    for f in os.listdir(path):
        results.append(os.path.join(path, f))

    if extensions_only:
        filtered_lst = []
        for part in results:
            if part.endswith(query):
                filtered_lst.append(part)
        results = filtered_lst

    if case_sensitive:
        filtered_lst = []
        for part in results:
            if query in part:
                filtered_lst.append(part)
        results = filtered_lst
    elif not case_sensitive:
        filtered_lst = []
        for part in results:
            if query.lower() in part.lower():
                filtered_lst.append(part)
        results = filtered_lst

    print(results)
    return results


search_query2("pyc", my_path, case_sensitive=True)

【问题讨论】:

  • 例如,queryextensions_only 是多余的。您应该只有一个可以包含通配符(并且可能默认为“*”?)我猜如果您使用 glob,它也可能使case_sensitive 无效。您可以查看stackoverflow.com/questions/3207219/… 了解更多(与此问题没有直接关系)详细信息。

标签: python python-3.x python-2.7 search


【解决方案1】:

没有万能的“正确”方式来做这样的事情。另一种选择是制作单独的函数,或作为包装器调用的私有子函数。

在您的具体情况下,有一些方法可以优化您想要做的事情以使其更清晰。

你做了很多

x = []
for i in y:
    if cond(i):
        x.append(i)
y = x

这被称为过滤器,python 有几种方法可以在一行中做到这一点

y = list(filter(cond, y))  # the 'functional' style

y = [i for i in y if cond(i)]  # comprehension

这让事情变得更加清晰。你写的映射也有类似的东西:

x = []
for i in y:
        x.append(func(i))
y = x

# instead do:
y = list(map(func, y))  # functional 
# or
y = [func(i) for i in y]  # comprehension

我们还可以结合地图和过滤器:

x = list(map(func, filter(cond, y)))
x = [func(i) for i in y if cond(i)]

使用这些我们可以连续构建许多过滤器和地图,同时非常清楚我们在做什么。这是functional programming的优势之一。


我已将您的代码修改为使用 generator expressions,它只会在我们调用 list(results) 时正确评估,从而节省每次创建新列表的大量时间:

def search_query2(query, path, extensions_only=False, case_sensitive=False):

    results = (os.path.join(path, f) for f in os.listdir(path))

    if extensions_only:
        results = (part for part in results if part.endswith(query))
    elif case_sensitive:  # I'm pretty sure this is actually the logic you want
        results = (part for part in results if query in part)
    else:
        results = (part for part in results if query.lower() in part.lower())

    return list(results)

【讨论】:

  • 无论每个参数的效果是否相互排斥,这种方法都有效。 results 只是随着您的使用而成为一个越来越嵌套的基因expr,每一层都执行一个额外的过滤器或映射操作。它比 OP 构造多个具有任意不同名称的临时 lists 的方法要简单得多,即使每个名称都可以替换原始名称以用于返回目的。
  • 感谢您的回答。这看起来很棒。我喜欢代码看起来多么干净。在我的情况下,虽然每个选项都应该是如果没有额外的 elifs,因为我可能想在一个查询中使用扩展触发器和区分大小写的触发器(以及其他几个)。所以我的问题是。生成器是否比每次都制作新列表更好?根据我阅读的内容(如果我错了,请纠正我)制作新列表是一种很好的做法,因为使用的最大列表会保留在内存中,直到我创建新列表(或类似的东西),所以不建议在缩小搜索范围时迭代它.
  • @Hsin 生成器是最好的方法。问题不在于内存(尽管生成器无论如何内存效率更高),但实际上是速度之一。每次运行 map 或 filter 操作时都需要时间来创建列表,因为解释器需要动态分配内存。因此,在创建列表时使用list.append 或等效项可能会导致显着变慢。每当列表需要大于它当前分配的内存时,就会发生这种情况。显然这一切都发生在后台,但我的建议是尽可能使用生成器而不是列表。
  • 感谢您的解释。我将不胜感激提供更多信息的链接。我真的很纠结于列表理解和生成器。我很难读懂它们。
  • @Hsin 基本上就像我上面说的:x = [func(i) for i in y if cond(i)]x = []; for i in y: if cond(i): x.append(func(i)) 相同。难点在于顺序不同,但你习惯了。 更多链接: List comprehensions & Generators and comprehensions
【解决方案2】:

您要过滤所有相同类型的文件吗?您可以使用 glob 模块来做到这一点。 例如

import glob

# Gets all the images in the specified directory.
print(glob.glob(r"E:/Picture/*/*.jpg"))

# Gets all the .py files from the parent directory.
print glob.glob(r'../*.py') 

【讨论】:

  • 我想在 pyw tkinter 窗口中创建快速搜索功能。我还想为我的搜索查询添加更精确的参数(这就是为什么我有扩展搜索器和关闭区分大小写的可能性)
【解决方案3】:

我喜欢在一开始就“准备好”我的条件,让事情变得整洁有序,并在以后变得更容易。确定不同参数对代码的影响。在这种情况下,“case_sensitive”定义了您是否使用 f.lower(),“extensions”定义了您的比较方法。 在这种情况下,我会写这样的东西。

def search_query(query, path, extensions_only=False, case_sensitive=False):
results = []

for f in os.listdir(path):
    if case_sensitive is True:
        fCase=f.lower()
        queryCase = query.lower()
    elif case sensitive is False:
        fCase = f
        queryCase = query

if extensions_only is True:
    if f.endswith(query):
                results.append(os.path.join(path, f))
elif extensions_only is False:
    if query in f:
            results.append(os.path.join(path, f))
return results

results = search_query("_c", my_path)
print(results)

这让我可以定义每个结果在不同级别上对函数的影响,而无需将它们嵌套起来,并且跟踪起来有点让人头疼!

【讨论】:

    【解决方案4】:

    另一种可能性:您可以只使用一个条件列表理解:

    def search_query2(query, path, extensions_only=False, case_sensitive=False):
        files = [os.path.join(path, f) for f in os.listdir(path)]
    
        result = [part for part in files
                  if (not extensions_only or part.endswith(query)) and
                     (query in part if case_sensitive
                      else query.lower() in part.lower())]
    
        print(results)
        return results
    

    起初这可能看起来非常“密集”且难以理解,但恕我直言,它非常清楚(甚至比您的变量名称更清晰)所有这些条件都只是过滤而不是例如更改结果列表的实际元素。

    此外,如 cmets 中所述,您可以只使用默认参数 extension="" 而不是 extensions_only(所有内容都以 "" 结尾,您甚至可以传递一个有效扩展的元组)。无论哪种方式,endswithin 约束应该如何一起发挥作用,或者扩展是否也应该匹配 case_sensitive 并不完全清楚。此外,files 可以简化为glob.glob(path + "/*")

    但这些观点并没有改变使用单个列表推导过滤结果列表的论点。

    【讨论】:

      猜你喜欢
      • 2021-11-16
      • 2021-08-15
      • 1970-01-01
      • 2011-01-14
      • 2016-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多