Ограничение рекурсии Python

#python #recursion

#python #рекурсия

Вопрос:

Итак, я понимаю причину ограничения рекурсии 1000. Я хочу запускать скрипт непрерывно, но правильно ли я понимаю, что в конечном итоге будет достигнут предел рекурсии (даже если я установлю его выше) и Python сломается?

По сути, это не имеет большого значения, потому что я мог бы заставить ОС продолжать перезапускать скрипт, но я подумал, что может быть более элегантное решение, которое я могу использовать в самом скрипте (замена потоков ??).

Мой скрипт:

 import os
import subprocess
import time
import logging
import datetime
from sys import argv

if len(argv) < 3:
    exit('Please provide two arguments - Source Destination')


LOC_DIR = argv[1]
REM_DIR = argv[2]

POLL_INT = 10
RUN_INT = 60
FILE_EXT = '.mov'


# logging setup
logging.basicConfig(filename='%s' % os.path.join(LOC_DIR, '%s the_log.log' % datetime.datetime.now()),level=logging.DEBUG)

# make an easy print and logging function
def printLog(string):
    print '%s %s' % (datetime.datetime.now(), string)
    logging.info('%s %s' % (datetime.datetime.now(), string))


# get the files with absolute paths
def getFiles(path):
    return [os.path.join(path, entry) for entry in os.listdir(path)]


# check if file is still being copied (file size has changed within the poll interval)
def checkSize(path):
    same = False
    while same is False:
        printLog("Processing '%s'" % os.path.basename(path))
        printLog('Waiting %s seconds for any filesize change' % POLL_INT)
        size1 = os.path.getsize(path)
        time.sleep(POLL_INT)
        size2 = os.path.getsize(path)
        if size1 == size2:
            same = True
            printLog('File size stayed the same for %s seconds' % POLL_INT)
            return same
        else:
            printLog('File size change detected. Waiting a further %s seconds' % POLL_INT)


# check if correct file extension
def checkExt(path):
    if path.endswith(FILE_EXT):
        return True


# rsync subprocess
def rsyncFile(path):
    printLog("Syncing file '%s'" % os.path.basename(path))
    try:
        command = ['rsync', '-a', '--remove-source-files', path, REM_DIR]
        p = subprocess.Popen(command, stdout=subprocess.PIPE)
        for line in p.stdout:
            printLog("rsync: '%s'" %line)
        p.wait()
        if p.returncode == 0:
            printLog('<<< File synced successfully :) >>>')
        elif p.returncode == 10:
            printLog('****** Please check your internet connection!! ******  Rsync error code: %s' % p.returncode)
        else:
            printLog('There was a problem. Error code: %s' % p.returncode)
    except Exception as e:
        logging.debug(e)


# main logic
def main():
    all_files = getFiles(LOC_DIR)
    files = []
    for f in all_files:
        if checkExt(f):
            files.append(f)
    if len(files) == 1:
        printLog('<<< Found %s matching file >>>' % len(files))
    elif len(files) > 1:
        printLog('<<< Found %s matching files >>>' % len(files))
    for f in files:
        if checkSize(f):
            rsyncFile(f)
    printLog('No files found.  Checking again in %s seconds' % RUN_INT)
    time.sleep(RUN_INT)
    printLog('Checking for files')
    main()

if __name__ == "__main__":


    main()
  

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

1. Информатика говорит нам, что любая рекурсия может быть переписана как цикл.

Ответ №1:

В CPython нет оптимизаций для рекурсии, поэтому вы действительно хотите избежать глубоко рекурсивного кода в пользу регулярных циклов:

 def main():
    while True:
        all_files = getFiles(LOC_DIR)
        files = []
        for f in all_files:
            if checkExt(f):
                files.append(f)
        if len(files) == 1:
            printLog('<<< Found %s matching file >>>' % len(files))
        elif len(files) > 1:
            printLog('<<< Found %s matching files >>>' % len(files))
        for f in files:
            if checkSize(f):
                rsyncFile(f)
        printLog('No files found.  Checking again in %s seconds' % RUN_INT)
        time.sleep(RUN_INT)
        printLog('Checking for files')

if __name__ == "__main__":    
    main()
  

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

1. Спасибо Blender, я не знал, что повторяю без необходимости. Премного благодарен!

Ответ №2:

Вы подходите к этому неправильно.

Замените основной цикл циклом.

 # main logic
def main():
    while True:
        all_files = getFiles(LOC_DIR)
        files = []
        for f in all_files:
            if checkExt(f):
                files.append(f)
        if len(files) == 1:
            printLog('<<< Found %s matching file >>>' % len(files))
        elif len(files) > 1:
            printLog('<<< Found %s matching files >>>' % len(files))
        for f in files:
            if checkSize(f):
                rsyncFile(f)
        printLog('No files found.  Checking again in %s seconds' % RUN_INT)
        time.sleep(RUN_INT)
        printLog('Checking for files')
  

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

1. Спасибо, Ник, я тоже попробую. Приветствую!

Ответ №3:

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

 while True:
   #repeated stuff goes here
  

Рекурсия — удивительный инструмент, но обращайтесь с ним осторожно, это часто может привести к ожогам. Вы были правы в том, что python может рекурсивно выполнять только 1000 вызовов в глубину, поэтому, если ваш рекурсивный метод не завершается к тому времени, генерируется исключение.

Удачи.

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

1. Спасибо, Дасти, я даже не знал, что использую рекурсию.. совершенно непреднамеренно! Приветствия