2012-06-27 13 views
6

Tại sao/làm thế nào điều này tạo ra một vòng lặp dường như vô hạn? Không chính xác, tôi cho rằng điều này sẽ gây ra một số dạng lỗi ngăn xếp tràn ngăn xếp.Tại sao kịch bản Python này tạo ra một vòng lặp vô hạn? (đệ quy)

i = 0 

def foo() : 
    global i 

    i += 1 
    try : 
     foo() 
    except RuntimeError : 
     # This call recursively goes off toward infinity, apparently. 
     foo() 

foo() 

print i 
+5

Vâng, bạn cứ tiếp tục gọi 'foo', không dừng điều kiện, vì vậy nó sẽ tiếp tục gọi lại mãi mãi. Và ngay cả khi bạn nhận được một ngoại lệ, bạn recurse _again_. –

+0

Không nên Python hết bộ nhớ hay gì đó? Hoặc là ngăn xếp cuộc gọi được xóa sau 'RuntimeError'? – rectangletangle

+0

Có thể python đang tối ưu hóa nó thành phép lặp – Blorgbeard

Trả lời

4

Nếu bạn thay đổi mã để

i = 0 
def foo(): 
    global i 
    i += 1 
    print i 
    try : 
     foo() 
    except RuntimeError : 
     # This call recursively goes off toward infinity, apparently. 
     foo() 
    finally: 
     i -= 1 
     print i 

foo() 

Bạn sẽ nhận thấy rằng sản lượng dao động ngắn dưới 999 (1000 là giới hạn đệ quy mặc định của Python). Điều đó có nghĩa, khi giới hạn được nhấn (RuntimeError), cuộc gọi cuối cùng của số foo() bị chấm dứt và một cuộc gọi khác được đặt để thay thế ngay lập tức.

Nếu bạn tăng KeyboardInterrupt, bạn sẽ quan sát cách toàn bộ dấu vết đang bị chấm dứt cùng một lúc.


CẬP NHẬT

Điều thú vị là cuộc gọi thứ hai của foo() không được bảo vệ bởi các try ... except -block nữa. Vì vậy, ứng dụng sẽ thực sự chấm dứt cuối cùng. Điều này trở thành apparant nếu bạn đặt giới hạn đệ quy thành một số nhỏ hơn, ví dụ: đầu ra cho sys.setrecursionlimit(3):

$ python test.py 
1 
2 
1 
2 
1 
0 
Traceback (most recent call last): 
    File "test.py", line 19, in <module> 
    foo() 
    File "test.py", line 14, in foo 
    foo() 
    File "test.py", line 14, in foo 
    foo() 
RuntimeError 
6

Ngoại lệ RuntimeError sẽ được tăng lên nếu vượt quá giới hạn đệ quy.

Vì bạn đang bắt ngoại lệ này, máy của bạn sẽ tiếp tục, nhưng bạn chỉ thêm vào một giá trị int toàn cục duy nhất, không sử dụng nhiều bộ nhớ.

Bạn có thể đặt giới hạn đệ quy với sys.setrecursionlimit(). Giới hạn hiện tại có thể được tìm thấy với sys.getrecursionlimit().

>>> import sys 
>>> sys.setrecursionlimit(100) 
>>> 
>>> def foo(i): 
...  i += 1 
...  foo(i) 
... 
>>> foo(1) 
Traceback (most recent call last): 
    ... 
    File "<stdin>", line 3, in foo 
RuntimeError: maximum recursion depth exceeded 
>>> 

Nếu bạn muốn hết bộ nhớ, hãy thử tiêu thụ nhiều bộ nhớ hơn.

>>> def foo(l): 
...     l = l * 100 
...     foo(l) 
... 
>>> foo(["hello"]) 
Traceback (most recent call last): 
    ... 
  File "<stdin>", line 2, in foo 
MemoryError 
>>>