Maya / Python - 通过文本文件循环的函数,除了某些行

时间:2015-09-26 17:22:54

标签: python maya

我在这里和那里找到了一些答案,但我无法确定构建我想要的东西的确切方法。如果你能提供帮助,请提前感谢你。

我有多个文本文件,所有文件都以相同的方式构建,但每个文件都有不同的信息。我想循环遍历每个文件并逐行返回其中的信息。另一方面,我有一些布尔值,它们定义是否必须跳过文件中的一个特定行。例如:“如果boolean1为true且lineInTheCorrespondingFile = 40,则跳过该行,否则,读取它但跳过第36和37行”

事情是我不知道如何继续该功能知道哪个文件被打开哪条线被读取如果它必须跳过它或不。知道我需要在函数结束时独立返回每一行。

到目前为止,这是我的代码:

def locatorsDatas (self):

    preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
    rawFile = presetsDir + preset.lower() + ".txt"

    with open(rawFile) as file:
        file.seek (0)
        for lineNum, line in enumerate(file, start = 1):
            if lineNum > 8 : # Skip header
                locator = eval (line)
                locName = locator[0]
                xVal = locator[1]
                yVal = locator[2]
                zVal = locator[3]
                locScale = locator[4]
                locColor = locator[5]
                if locator == "":
                    break

                return (locName, xVal, yVal, zVal, locScale, locColor)

我不知道我应该传递给函数的值是什么,以使它跳过我想要的行,知道我不能直接写入它,因为每个文件不会在同一行中断。 哦,它只返回文件的一行而不是单独的一行。

希望它清楚,你可以帮助我,再次感谢。

1 个答案:

答案 0 :(得分:0)

我发现您的代码存在许多问题。

首先,您总是从第8行返回数据,而不是任何其他数据。如果要从文件中提取许多值,则可能需要使用yield语句而不是return使函数成为生成器。然后调用代码可以使用for循环访问数据,或者将生成器传递给list或另一个接受任何迭代的函数。

def locatorsDatas(self):
    # ...
    lineNum, line in enumerate(file, start=1):
        # ...
        yield results

如果你不能使用生成器但需要你的函数来返回连续的行,你需要在函数范围之外的某个地方保存文件迭代器(或者可能是enumerate迭代器)。这意味着每次调用函数时都不需要重新打开文件。你可以这样做:

def __init__(self):
    preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
    rawFile = presetsDir + preset.lower() + ".txt"
    self.preset_file_enumerator = enumerate(open(rawFile)) # save the iterator on self

def locatorsDatas(self):
    try:
        lineNum, line = next(self.preset_file_enumerator) # get a value from the iterator
        # do your processing
        return results
    except StopIteration:
        # do whatever is appropriate when there's no more data in the file here
        raise ValueError("no more data") # such as raising an exception

我看到的下一个问题是你如何处理每一行来获取单独的数据。您正在使用eval,如果您正在处理的数据甚至受到轻微委托,那么这是一个非常糟糕的主意。那是因为eval将其参数解释为Python代码。它可以执行任何,包括删除硬盘中的文件!更安全的版本可用ast.literal_eval,它只允许字符串包含Python文字(包括列表,字典和集合,但不包含变量查找,函数调用或其他更复杂的代码)。

您还有一个错误检查我认为不会按照您的意图执行操作。 if locator == ""测试可能放得太迟,以避免早期行从eval'd行提取数据时出错。并且您运行的break语句将导致函数退出而不返回任何其他内容。如果您只想跳过空行,则应将检查放在循环的顶部,并使用continue而不是break

现在我们终于可以在问题的标题中找到你所问的问题了。如果你想根据各种标志跳过某些行,你只需要在循环时检查这些标志,并执行continue跳过你不想阅读的行。我不完全理解你所询问的关于如何传递标志的内容,但假设你可以将它们作为参数给出,这里是代码看起来如何的草图:

def locatorsDatas(self, skip_40=False, skip_50=True):
    # open file, ...
    for lineNum, line in enumerate(file, start = 1):
        if  (not line or
             lineNum < 8 or
             skip_40 and lineNum == 40 or
             skip_50 and lineNum == 50):
            continue
        # parse the line
        yield result

显然你应该使用你自己的标志名称和逻辑,而不是我为我的示例代码编写的那些。如果你的逻辑更复杂,你可能更喜欢为每个标志使用单独的if语句,而不是像我一样将它们全部打包成一个单独的条件。