Форум сайта python.su
Делаю функцию, которая рекурсивно считывает все файлы в каталоге.
Хочу сделать так, чтобы через каждые 100 обработанных файлов выводилось информационное сообщение (вида “Найдено файлов: 200…”).
Как лучше сделать? Использовать глобальную переменную-счетчик, или optional-параметр, который будет передаваться при рекурсивных вызовах?
Или может быть в Python есть более подходящие инструменты?
Офлайн
Судя по всему, в Python нельзя передать обычную переменную по ссылке.
Поэтому второй способ в чистом виде невозможен, но можно передавать объект (который по ссылке).
Сделал так:
def scanfiles(base: str, ext: list = None, report: int = 100) -> list: rec = {'level': 0, 'counter': 0, 'report': report} def _scanfiles(base: str, ext: list = None, rec = None) -> list: (fl, dl) = ([], []) if rec is None: rec = {'level': 0, 'counter': 0} log.trace(" " * rec['level'] + "Scanning: %s", base) for f in os.scandir(base): if f.is_dir(): log.trace(" " * rec['level'] + "- subdir: %s", f.path) rec['counter'] += 1 dl.append(f.path) if f.is_file(): log.trace(" " * rec['level'] + "- file: %s", f.path) rec['counter'] += 1 if not ext or os.path.splitext(f.name)[1].lower()[1:] in ext: fl.append(f.path) if rec['report'] and not rec['counter'] % rec['report']: log.debug("Processing: %d...", rec['counter']) for d in list(dl): rec['level'] += 1 (f, s) = _scanfiles(d, ext, rec) rec['level'] -= 1 dl.extend(s) fl.extend(f) if rec['report'] and not rec['level']: log.debug("Processing: %d", rec['counter']) return (fl, dl) (fl, dl) = _scanfiles(base, ext, rec) return fl
Офлайн
При рекурсии нужно через параметр делать.
>>> def fact(n, count=1): ... if n <= 1: ... return 1 ... else: ... if count % 3 == 0: ... print('seen', count, 'numbers', 'on', n) ... return n * fact(n - 1, count + 1) ... >>> fact(10) seen 3 numbers on 8 seen 6 numbers on 5 seen 9 numbers on 2 3628800 >>>
Отредактировано py.user.next (Авг. 15, 2023 11:01:34)
Офлайн
alibekНу ты просто не понимаешь, как работают имена в питоне, потому что ты не читал документацию к питону.
Судя по всему, в Python нельзя передать обычную переменную по ссылке.
alibek
Сделал так:
def scanfiles(base: str, ext: list = None, report: int = 100) -> list: rec = {'level': 0, 'counter': 0, 'report': report} def _scanfiles(base: str, ext: list = None, rec = None) -> list: (fl, dl) = ([], []) if rec is None: rec = {'level': 0, 'counter': 0} log.trace(" " * rec['level'] + "Scanning: %s", base) for f in os.scandir(base): if f.is_dir(): log.trace(" " * rec['level'] + "- subdir: %s", f.path) rec['counter'] += 1 dl.append(f.path) if f.is_file(): log.trace(" " * rec['level'] + "- file: %s", f.path) rec['counter'] += 1 if not ext or os.path.splitext(f.name)[1].lower()[1:] in ext: fl.append(f.path) if rec['report'] and not rec['counter'] % rec['report']: log.debug("Processing: %d...", rec['counter']) for d in list(dl): rec['level'] += 1 (f, s) = _scanfiles(d, ext, rec) rec['level'] -= 1 dl.extend(s) fl.extend(f) if rec['report'] and not rec['level']: log.debug("Processing: %d", rec['counter']) return (fl, dl) (fl, dl) = _scanfiles(base, ext, rec) return fl
Отредактировано py.user.next (Авг. 16, 2023 04:15:31)
Офлайн
Основная функция это _scanfiles, она собственно и выполняет нужную задачу; в нее передается счетчик и она возвращает вспомогательные данные, не нужные для финального результата, но нужные для рекурсии.
Функция scanfiles это просто оболочка _scanfiles, которая сама подготавливает вызов основной функции и возвращает результат в комфортной для пользователя (вызывающего кода) форме. Обычное дело для рекурсивных функций.
То что основная функция вложена в оболочку — сделано специально. Это красиво, когда снаружи не видно ничего постороннего и пользователя не будет возникать вопросов, что это за аргумент rec такой.
Отредактировано alibek (Авг. 16, 2023 16:24:52)
Офлайн
alibekДа, это заметно. Заметно, что ты специально сделал то, чего делать не надо. Видимо, сказывается отсутствие опыта. Про чистые функции ты не в курсе и про юнит-тестирование и что это вообще такое ты тоже не очень-то и знаешь. Как бы ерунды напридумывали какой-то, а ты один такой умный.
То что основная функция вложена в оболочку — сделано специально.
def scanfiles(base: str, ext: list = None, report: int = 100) -> list: rec = {'level': 0, 'counter': 0, 'report': report} def _scanfiles(base: str, ext: list = None, rec = None) -> list: (fl, dl) = ([], []) if rec is None: rec = {'level': 0, 'counter': 0} log.trace(" " * rec['level'] + "Scanning: %s", base) for f in os.scandir(base): if f.is_dir(): log.trace(" " * rec['level'] + "- subdir: %s", f.path) rec['counter'] += 1 dl.append(f.path) if f.is_file(): log.trace(" " * rec['level'] + "- file: %s", f.path) rec['counter'] += 1 if not ext or os.path.splitext(f.name)[1].lower()[1:] in ext: fl.append(f.path) if rec['report'] and not rec['counter'] % rec['report']: log.debug("Processing: %d...", rec['counter']) for d in list(dl): rec['level'] += 1 (f, s) = _scanfiles(d, ext, rec) rec['level'] -= 1 dl.extend(s) fl.extend(s) if rec['report'] and not rec['level']: log.debug("Processing: %d", rec['counter']) return (fl, dl) (fl, dl) = _scanfiles(base, ext, rec) return fl def scanfiles(base: str, ext: list = None, report: int = 100) -> list: rec = {'level': 0, 'counter': 0, 'report': report} def _scanfiles(base: str, ext: list = None, rec = None) -> list: (fl, dl) = ([], []) if rec is None: rec = {'level': 0, 'counter': 0} log.trace(" " * rec['level'] + "Scanning: %s", base) for f in os.scandir(base): if f.is_dir(): log.trace(" " * rec['level'] + "- subdir: %s", f.path) rec['counter'] += 1 dl.append(f.path) if f.is_file(): log.trace(" " * rec['level'] + "- file: %s", f.path) rec['counter'] += 1 if not ext or os.path.splitext(f.name)[1:].lower()[1:] in ext: fl.append(f.path) if rec['report'] and not rec['counter'] % rec['report']: log.debug("Processing: %d...", rec['counter']) for d in list(dl): rec['level'] += 1 (f, s) = _scanfiles(d, ext, rec) rec['level'] -= 1 dl.extend(s) fl.extend(f) if rec['report'] and not rec['level']: log.debug("Processing: %d", rec['counter']) return (fl, dl) (fl, dl) = _scanfiles(base, ext, rec) return fl def scanfiles(base: str, ext: list = None, report: int = 100) -> list: rec = {'level': 0, 'counter': 0, 'report': report} def _scanfiles(base: str, ext: list = None, rec = None) -> list: (fl, dl) = ([], []) if rec is None: rec = {'level': 0, 'counter': 0} log.trace(" " * rec['level'] + "Scanning: %s", base) for f in os.scandir(base): if f.is_dir(): log.trace(" " * rec['level'] + "- subdir: %s", f.path) rec['counter'] += 1 dl.append(f.path) if f.is_file(): log.trace(" " * rec['level'] + "- file: %s", f.path) rec['counter'] += 1 if not ext or os.path.splitext(f.name)[1].lower()[1:] in ext: fl.append(f.path) if rec['report'] and not rec['counter'] % rec['report']: log.debug("Processing: %d...", rec['counter']) for d in list(dl): rec['level'] += 1 (f, s) = scanfiles(d, ext, rec) rec['level'] -= 1 dl.extend(s) fl.extend(f) if rec['report'] and not rec['level']: log.debug("Processing: %d", rec['counter']) return (fl, dl) (fl, dl) = _scanfiles(base, ext, rec) return fl
alibekКому не видно? Ты думаешь, это будет кто-то смотреть и читать вообще? Ты открой хоть одну реальную программу, которыми ты пользуешься каждый день, и посмотри, какой там “красивый” код у неё. Там будет говнокод на говнокоде. Ты ей можешь пользоваться годами и никогда даже не узнать, что там всякая ерунда делается внутри. А вот когда там ошибка будет, которая снаружи там сотрёт тебе полдиска или выведет тебе какую-то ложную информацию, тогда ты сразу это заметишь. А когда ты полезешь туда исправлять эту ошибку или хотя бы оценить, насколько автору программы будет её легко исправить, вот тогда качество кода и сыграет свою роль. Тогда ты по говнокоду сразу поймёшь, что это не будет исправлено никогда. Потому что автор сам же в своём говнокоде не разберётся и просто не сможет её исправить, потому что говнокод писать легко, а разгребать его потом тяжело. Поэтому то, что тяжело, он делать не будет. Он тебя просто проигнорирует, типа ошибки нет никакой или там она некритическая и так далее, и всё. Дальше ты пойдёшь программку получше искать на просторах Интернета.
Это красиво, когда снаружи не видно ничего постороннего
alibekНу ты слышал звон, но не знаешь, где он. Да, вот так вот в голом виде это правильно, но в реале по факту это неправильно. Обёртки такие, да, бывают, но это не значит, что их надо везде делать.
Это красиво, когда снаружи не видно ничего постороннего и пользователя не будет возникать вопросов, что это за аргумент rec такой.
Отредактировано py.user.next (Авг. 17, 2023 02:41:39)
Офлайн