2011-08-04 48 views
11

Tôi có 2 giải pháp cho một vấn đề đệ quy mà tôi cần cho một hàm (thực ra là một phương thức). Tôi muốn nó được đệ quy, nhưng tôi muốn thiết lập giới hạn đệ quy đến 10 và thiết lập lại nó sau khi chức năng được gọi là (hoặc không lộn xộn với giới hạn đệ quy ở tất cả). Bất cứ ai có thể nghĩ ra một cách tốt hơn để làm điều này hoặc khuyên bạn nên sử dụng một trong những người khác? Tôi đang nghiêng về phía người quản lý ngữ cảnh vì nó giữ cho mã của tôi sạch hơn và không thiết lập tracebacklimit, nhưng có thể có cảnh báo?đặt giới hạn đệ quy python cho hàm

import sys 

def func(i=1): 
    print i 
    if i > 10: 
     import sys 
     sys.tracebacklimit = 1 
     raise ValueError("Recursion Limit") 
    i += 1 
    func(i) 

class recursion_limit(object): 
    def __init__(self, val): 
     self.val = val 
     self.old_val = sys.getrecursionlimit() 
    def __enter__(self): 
     sys.setrecursionlimit(self.val) 
    def __exit__(self, *args): 
     sys.setrecursionlimit(self.old_val) 
     raise ValueError("Recursion Limit") 

def func2(i=1): 
    """ 
    Call as 

    with recursion_limit(12): 
     func2() 
    """ 
    print i 
    i += 1 
    func2(i) 

if __name__ == "__main__": 
    # print 'Running func1' 
    # func() 

    with recursion_limit(12): 
     func2() 

Tôi thấy một số hành vi kỳ lạ mặc dù với trình quản lý ngữ cảnh. Nếu tôi đặt trong chính

with recursion_limit(12): 
    func2() 

Nó in từ 1 đến 10. Tôi cho rằng có điều gì đó đang xảy ra khi tôi nhập nội dung?

EDIT: Đối với hậu thế này là những gì tôi đã đưa ra cho một chức năng biết chiều sâu cuộc gọi của nó. Tôi nghi ngờ tôi sẽ sử dụng nó trong bất kỳ mã sản xuất, nhưng nó được công việc làm.

import sys 
import inspect 
class KeepTrack(object): 
    def __init__(self): 
     self.calldepth = sys.maxint 

    def func(self): 
     zero = len(inspect.stack()) 
     if zero < self.calldepth: 
      self.calldepth = zero 
     i = len(inspect.stack()) 
     print i - self.calldepth 
     if i - self.calldepth < 9: 
      self.func() 

keeping_track = KeepTrack() 
keeping_track.func() 
+4

Tại sao không chỉ sử dụng 'for _ in xrange (N)' để làm điều gì đó N lần? Đơn giản hơn về khái niệm hơn là lạm dụng 'RuntimeError', cho phép gọi các hàm khác mà không thoát sớm (hoặc tệ hơn, yêu cầu người gọi phải quan tâm đến điều đó), và nên hiệu quả hơn như tiền thưởng. – delnan

+2

Khi bạn làm điều đó trong chính, bạn đã có một chức năng. Khi bạn đang ở trong thông dịch viên, bạn thì không. – agf

+0

Tại sao bạn có thể muốn làm điều này? –

Trả lời

7

Bạn không nên thay đổi giới hạn đệ quy hệ thống. Bạn nên viết mã hàm của bạn để biết nó sâu bao nhiêu và kết thúc đệ quy khi nó quá sâu.

Lý do giới hạn đệ quy có vẻ được áp dụng khác nhau trong chương trình của bạn và thông dịch viên là vì chúng có các cấp chồng khác nhau: các hàm được gọi trong trình thông dịch để đến thời điểm chạy mã của bạn.

0

Tôi chắc chắn sẽ chọn cách tiếp cận đầu tiên, nó đơn giản và tự giải thích. Sau khi tất cả các giới hạn đệ quy là sự lựa chọn rõ ràng của bạn, vậy tại sao làm xáo trộn nó?

1

Trong khi hơi tiếp tuyến (Tôi muốn đã đặt nó trong một chú thích, nhưng tôi không nghĩ rằng có chỗ), cần lưu ý rằng setrecursionlimit có phần sai lạc mang tên - nó thực sự đặt ngăn xếp độ sâu tối đa:

http://docs.python.org/library/sys.html#sys.setrecursionlimit

Đó là lý do tại sao hàm hoạt động khác nhau tùy thuộc vào nơi bạn gọi nó. Ngoài ra, nếu func2 được thực hiện một cuộc gọi stdlib (hoặc bất cứ điều gì) mà kết thúc lên gọi một số chức năng như vậy mà nó được thêm nhiều hơn N để ngăn xếp, ngoại lệ sẽ kích hoạt sớm.

Ngoài ra, tôi cũng sẽ không thay đổi sys.tracebacklimit; sẽ có ảnh hưởng đến phần còn lại của chương trình của bạn. Đi với câu trả lời của Ned.

1

bỏ qua các vấn đề chung chung hơn, có vẻ như bạn có thể có độ sâu khung hình hiện tại bằng cách xem chiều dài của inspect.getouterframes(). mà sẽ cung cấp cho bạn một "điểm không" mà từ đó bạn có thể thiết lập giới hạn chiều sâu (từ chối trách nhiệm: tôi đã không cố gắng này).

chỉnh sửa: hoặc len (inspect.stack()) - điều đó không rõ ràng đối với tôi sự khác biệt là gì. tôi sẽ muốn biết liệu điều này có hiệu quả không, và liệu chúng có khác nhau hay không.

Các vấn đề liên quan