2015-09-26 2 views
0

Я нашел несколько вариантов ответов здесь и там, но я не могу точно определить, как построить то, что я хочу. Спасибо вам заранее, если вы можете помочь.Maya/Python - функция, которая пеет хотя текстовый файл, за исключением некоторых строк

У меня есть несколько текстовых файлов, все они построены одинаково, но с различной информацией в каждом из них. Я хотел бы перебрать каждый файл и возвращать информацию в нем по строкам. С другой стороны, у меня есть некоторые логические значения, которые определяют, нужно ли пропускать одну конкретную строку в файле или нет. Например: «если boolean1 истинно и 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

Итак, у вас есть текстовый файл, который вы хотите прочитать в некоторых строках, а не в других? И строки, которые вы хотите прочитать, вы хотите вернуть информацию из нее? Кстати, вы должны быть очень осторожны, используя функцию eval() для чего-то подобного. – enigma

+0

Во-первых, это не вопрос, связанный с майей, поэтому вы, скорее всего, получите больше помощи, если просто удалите ссылки на него. Просто сделайте 'rawFile' аргумент' locatorsData' и вырежьте вызовы модуля 'cmds'. – chadrik

+0

Кроме того, похоже, что макет ваших данных является основным источником осложнений. У вас есть контроль над написанием файлов? Можете ли вы использовать [json] (https://docs.python.org/2/library/json.html) или [pickle] (https://docs.python.org/2/library/pickle.html), который поддерживает сериализацию типов данных, таких как dicts и list? Я думаю, что это очень помогло бы, если бы вы могли привести примеры первых нескольких строк файлов, которые вам нужно прочитать. Наконец, до тех пор, пока файлы не будут чрезвычайно большими, может возникнуть больше смысла объединить все данные в одну структуру, а затем извлечь все, что вам нужно. – chadrik

ответ

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 для каждого флага, вместо того, чтобы упаковывать их в одно одиночное условие, как я.

+0

Ничего себе! Спасибо! Это очень полезно, я переписал код по-своему, поскольку я очень новичок в python, и все работает отлично! :) – UKDP