2016-07-02 1 views
0

После спотыкания на this question Я играл с exec(), чтобы лучше понять, как это работает. Я пытаюсь получить эту мерзость скрипта, чтобы увеличить глобальную переменную, прочитать себя и вызвать exec с новым глобальным значением, пока не будет достигнут предел рекурсии. Лучшее, что я смог придумать, - это один файл объявить глобальный, а затем вызвать следующий файл (точный дубликат минус объявление переменной), который затем рекурсивно вызовет сам. Вот код для первого:Рекурсия на уровне exec() с глобалями

# recurse.py 

def func(): 
    global x 
    x += 1 
    with open('recurse2.py', 'r') as f:  
     try: 
      exec(f.read(), {'x': x}) 
     except RecursionError: 
      print('maximum recursion depth reached at', x) 

x = 0 
func() 

А вот файл он выполняет, который будет выполнять сам:

# recurse2.py 

def func(): 
    global x 
    x += 1 
    with open('recurse2.py', 'r') as f:  
     try: 
      exec(f.read(), {'x': x}) 
     except RecursionError: 
      print('maximum recursion depth reached at', x) 

func() 

Можно ли достичь того же эффекта только с одним файлом?

ответ

2

Вы можете сделать это:

# recurse.py 

def func(): 
    global x 
    x += 1 
    with open('recurse.py', 'r') as f:  
     try: 
      exec(f.read(), {'x': x}) 
     except RuntimeError: 
      print('maximum recursion depth reached at', x) 

try: 
    x 
except NameError: 
    x = 0 
func() 

Проблема с начальным, например, не является действительно специфичны для exec. Это просто, что сама программа устанавливает x в ноль перед вызовом func. Таким образом, прохождение стартового значения x не влияет: код, который вы выполняете, устанавливает новое значение x в любом случае. В этой новой версии блок try/except проверяет, существует ли это имя до его инициализации до нуля.

(я использовал RuntimeError здесь, потому что у меня нет Python 3.5, где был введен RecursionError, но он должен работать так же с RecursionError.)

+0

В моей системе это не сбой из-за глубины рекурсии, сбой: OSError: [Errno 24] Слишком много открытых файлов: 'recurse.py' (или IOError в Python 2) - я понимаю, что это разные для каждой системы, но IOError можно предотвратить. – cdlane

2

Разновидность отличное решение @ BrenBarn, что не удается с RuntimeError (@ ~ 500 рекурсии) вместо IOError (@ ~ 256 рекурсии) из-за слишком много файлов быть открытым:

# recurse.py

def func(): 
    global x 
    x += 1 
    with open('recurse.py') as source: 
     string = source.read() 
    try: 
     exec(string, {'x': x}) 
    except RuntimeError: 
     print('maximum recursion depth reached at', x) 

try: 
    x 
except NameError: 
    x = 0 

func() 

Однако можно также расширить стек рекурсии (sys.setrecursionlimit())nd/или открыть лимит файла (ulimit -n) по мере необходимости.

+0

Ах, я не заметил потенциальную проблему IOError, поскольку в прошлом я столкнулся с моим открытым файловым лимитом. Хорошая точка зрения! – Alec