python - python中如何避免全局变量和重复

标签 python global-variables

我编写了一个脚本,它会遍历字符串列表并在文件中的 (1) 行或目录中的 (2) 个文件名中查找匹配项。

根据搜索模式(用户输入),如果 (1) 与行/文件名完全匹配或 (2) 行/文件名包含该字符串,则每个字符串都会附加到列表中。

import os
import operator

query_list = ["look", "for", "these"]

search_object = "name_of_file_or_directory"

if os.path.isfile(search_object):
    input_object = 1
    with open(search_object, "r") as file:
        lines = file.read().split("\n")

elif os.path.isdir(search_object):
    input_object = 2

search_mode = input("Are you looking for objects that (1) exactly match or (2) contain the query? ")

matched = []

def comparison():
    if search_mode == "1" and operator.eq(string, query) or search_mode == "2" and operator.contains(string, query):
        matched.append(string)
    return matched

for query in query_list:

    def search_loop(container):
    # container is either list of filenames or list of lines
        global string
        for string in container:
            matched = comparison()
        return matched

    if input_object == 1:
        matched = search_loop(lines)

    elif input_object == 2:
        matched = search_loop(os.listdir(search_object))

print(matched)

我定义了 comparison() 函数,这样我以后就可以在脚本中更频繁地使用它,而无需重复这些行。但是,我必须在另一个函数中分配全局字符串,否则会出现以下错误。 NameError:名称“字符串”未定义

我想知道如何避免使用全局变量。我读到类通常可以用来避免这种情况,但我不知道这在这里有什么用处。对于如何以良好的方式解决此任务的任何建议,我将不胜感激。

最佳答案

我们可以采取一些措施来清理代码。最后我们将摆脱全局变量。

使数据一致

我们可以从一开始就获取目录内容,而不是等到最后才获取目录内容。这样我们以后就可以将文本行和目录内容视为完全相同。

import os
import operator

query_list = ["look", "for", "these"]

search_object = "name_of_file_or_directory"

if os.path.isfile(search_object):
    with open(search_object, "r") as file:
        lines = file.read().split("\n")

elif os.path.isdir(search_object):
    lines = os.listdir(search_object)

# At this point, lines is just a list of text - we don't care where it came from.

search_mode = input("Are you looking for objects that (1) exactly match or (2) contain the query? ")

matched = []

def comparison():
    if search_mode == "1" and operator.eq(string, query) or search_mode == "2" and operator.contains(string, query):
        matched.append(string)
    return matched

for query in query_list:

    def search_loop(container):
        # container is either list of filenames or list of lines
        global string
        for string in container:
            matched = comparison()
        return matched

    # We were able to remove checks from here
    matched = search_loop(lines)

print(matched)

当有意义时,尽早选择正确的操作

之前,我们每次都会检查要执行哪种操作(完全匹配或包含)。相反,我们可以在收到用户输入时立即选择该选项,并将其分配给稍后使用的单个名称。

import os
import operator

query_list = ["look", "for", "these"]

search_object = "name_of_file_or_directory"

if os.path.isfile(search_object):
    with open(search_object, "r") as file:
        lines = file.read().split("\n")

elif os.path.isdir(search_object):
    lines = os.listdir(search_object)

search_mode = input("Are you looking for objects that (1) exactly match or (2) contain the query? ")
# Because the interface of both functions is the same we can use them directly.
# If they were not the same then we could write an adapter function that would make them have
# the same signatures so they could be used in the same way below.
if search_mode == "1":
    search_op = operator.eq
elif search_mode == "2":
    search_op = operator.contains

matched = []

for query in query_list:
    for string in lines:
        if search_op(string, query):
            matched.append(string)

print(matched)

将代码重新组织为函数

现在我们对程序的各个部分有了更好的了解,我们可以将其分解为函数。使用函数为程序的各个部分提供了具体名称,还有助于缩小它们使用的变量的范围。任何代码中使用的变量越少,以后就越容易理解。我们通过仔细选择函数来避免全局变量 - 我们可能使用的一个重要标准是函数中的所有内容都是独立的,不需要引用外部的任何内容。

我们还将使用 if __name__ == '__main__' 约定,以便我们可以根据需要包含另一个脚本中的脚本。

import os
import operator


def get_contents(search_object):
    if os.path.isfile(search_object):
        with open(search_object, "r") as file:
            return file.read().split("\n")
    elif os.path.isdir(search_object):
        return os.listdir(search_object)


def get_search_function(user_input):
    if search_mode == "1":
        return operator.eq
    elif search_mode == "2":
        return operator.contains


def find_matches(match_function, query_list, lines):
    matched = []
    for query in query_list:
        for string in lines:
            if match_function(string, query):
                matched.append(string)
    return matched


if __name__ == "__main__":
    search_object = "name_of_file_or_directory"
    lines = get_contents(search_object)

    search_mode_input = input("Are you looking for objects that (1) exactly match or (2) contain the query? ")
    search_function = get_search_function(search_mode_input)

    query_list = ["look", "for", "these"]
    matches = find_matches(search_function, query_list, lines)
    print(matches)

进一步改进

  1. 错误处理 - 无论出现什么问题,我们都可以提出适当的错误(对于可以处理的事情)或断言(对于我们不期望的事情发生并且无法真正恢复)。
  2. 类似 argparse 的模块可以更轻松地将参数带入脚本中,这样我们就不必对变量值进行硬编码。
  3. 我们也可以从 sys.stdin 中读取内容并将其留给用户生成文本,而不是获取“搜索对象”,然后再担心它是文件还是目录以某种方式并将其通过管道传输到程序,例如: cat Words.txt | python script.py 用于内容或 ls 。 | python script.py 用于目录中的文件。

关于python - python中如何避免全局变量和重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54272897/

相关文章:

python - 如何在 numpy.append 中短路扁平化

python - 如何在 Python 中调用默认的字符串相等函数?

javascript - 在 Javascript/node.js 中的模块之间共享变量?

java - 当程序具有全局变量时,如何运行N个测试用例?

javascript - 使用 JavaScript 中的 switch 循环更改背景颜色

python base64字符串解码

python - 我怎样才能在 SQLAlchemy 中做到这一点?

python - 如何将列表中的n个数字一一输入?

c - 为什么我不能在 C 函数外为全局变量赋值?

perl - 为什么有些变量需要初始化而有些变量不需要在同一个脚本中?