Python: обобщенная оболочка, исключающая попытки для автономного режима и для продолжения цикла

#python #for-loop #exception

#python #для цикла #исключение

Вопрос:

Прошу прощения, если этот вопрос задавался ранее, но я не смог найти похожий вопрос и надеялся, что SO порекомендует мне его при вводе.

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

Вот MWE, использующий упрощенные функции того, как выглядит мой код:

 import os, stat

def folder_info(folder):
    if len(folder) > 20:
        raise Exception('Folder {} name too long'.format(folder))
    print(folder)
    subfolders = os.listdir(folder)
    return len(folder), subfolders

raise_error = False

folders = [f for f in os.listdir() if os.path.isdir(f)]

for folder in folders:
    try: 
        length, subfolders = folder_info(folder)
    except Exception as error:
        if raise_error: raise
        print('Error: {}'.format(error))
        continue

    for subfolder in subfolders:
        subfolder = os.path.join(folder, subfolder)
        try: 
            length, subfolders = folder_info(subfolder)
        except Exception as error:
            if raise_error: raise
            print('Error: {}'.format(error))
            continue
  

В идеале я хотел бы что-то, где мне не нужно вводить оператор try and except для каждого вложенного цикла. На что я надеюсь:

 for folder in folders:
    arg1, arg2 = exceptionwrapper(myfunction1(folder), raise_error)

    for subfolder in arg2:
    subfolder = os.path.join(folder, subfolder)
    arg1, arg2, arg3 = exceptionwrapper(myfunction2(subfolder), raise_error)

        for subsubfolder in arg3:
        arg1, arg2 = exceptionwrapper(myfunction3(subsubfolders), raise_error)
  

Я пробовал следующие решения с функциями декоратора, но я не смог передать continue или выяснить, куда это должно идти. Это моя лучшая попытка, и при попытке передать у меня синтаксическая ошибка continue :

 def exceptionwrapper(function, raise_error, after_error: function = continue):
    def decorator(func):
        def new_func(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as error:
                if raise_error: raise
                print('Error: {}'.format(error))
                return after_error
            return new_func
        return decorator
  

Любая помощь была бы оценена!

Ответ №1:

Весь ваш код можно Pythonic записать в несколько строк, если бы вы могли использовать os.walk.

 import os
for root, folders, files in os.walk(os.getcwd()):
    for folder in folders:
        print('dir is: ', folder)
        try:
            if len(folder) > 20:
                raise Exception('Folder {} name too long'.format(folder))
        except Exception as error_message:
            print('Error in folder: {} due to: {}'.format(folder, error_message))
  

Как вы указали на другом уровне папки, вам нужно вызывать разные функции, вы можете попробовать, как показано ниже:

 import os
curr_folder = os.getcwd()
for root, folders, files in os.walk(curr_folder):
    for folder in folders:
        print('dir is: ', folder)
        folder_level = root[len(curr_folder) 1:].count(os.sep)
        print('level is: ', folder_level)
        if folder_level == 0:
            # call myfunction0
            pass
        elif folder_level == 1:
            # call myfunction1
            pass
        elif folder_level == 2:
            # call myfunction2
            pass
  

Комментарии:

1. Спасибо за предложение. К сожалению, приведенный мной пример, возможно, был слишком упрощен. На разных уровнях вложенных папок я использую разные функции ( myfunction1 , myfunction2 и т.д. как в моем идеальном блоке кода), поэтому os.walk в этом случае не сработало бы.