#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. Спасибо, Дасти, я даже не знал, что использую рекурсию.. совершенно непреднамеренно! Приветствия