2009-05-16 47 views
5

Tôi muốn thực hiện một số mã Python, gõ khi chạy, vì vậy tôi có được chuỗi và gọiSử dụng exec() với chức năng đệ quy

exec(pp, globals(), locals())

nơi pp là chuỗi. Nó hoạt động tốt, ngoại trừ các cuộc gọi đệ quy, e. . G, ví dụ, mã này là OK:

def horse(): 
    robot.step() 
    robot.step() 
    robot.turn(-1) 
    robot.step() 

while True: 
    horse() 

Nhưng lần này không phải là:

def horse(): 
    robot.step() 
    robot.step() 
    robot.turn(-1) 
    robot.step() 
    horse() 

horse() 

NameError: global name 'horse' is not defined

Có cách nào để chạy mã đệ quy không?

CẬP NHẬT

a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

exec(a) 

trình nếu đưa vào cấp cao nhất. Nhưng nếu chuyển bên trong một hàm:

def fn1(): 
    a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

    exec(a) 

fn1() 

lỗi tương tự xảy ra: NameError: tên toàn cầu 'rec' không được định nghĩa

+0

Xin vui lòng cho tôi chuỗi exec đây không phải là từ người dùng đầu vào. –

+0

@Nadia, tại sao, có, nó _is_ :) – Headcrab

Trả lời

4

Nó làm việc cho tôi:

a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

exec(a) 
5 
6 
7 
8 
9 
10 

Tất cả tôi có thể nói là có thể có lỗi trong mã của bạn.

Sửa

Ở đây bạn đi

def fn1(): 
    glob = {} 
    a = """\ 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 
    exec(a, glob) 

fn1() 
+0

Vâng, không chính xác - hãy xem CẬP NHẬT ở trên ... – Headcrab

+0

Tại sao nó hoạt động? – Headcrab

+0

@Headcrab, bởi vì nó cung cấp cho bạn một cụm từ có thể chỉnh sửa và từ điển địa phương. người dân địa phương() cung cấp cho bạn một từ điển không thể thay đổi các biến cục bộ "thực". – Unknown

0

"NameError: toàn cầu tên 'rec' không được định nghĩa" có nghĩa là nó đang tìm kiếm rec trong phạm vi toàn cầu, không phải là phạm vi địa phương. Có vẻ như nó định nghĩa rec trong phạm vi cục bộ nhưng sau đó cố thực hiện trong toàn cục. Hãy thử in các locals() và globals() bên cạnh chuỗi bạn đang thực hiện.

More info.

3

này làm việc cho tôi (thêm global rec). rec(5) gọi số rec địa phương, nhưng rec(n+1) gọi là lệnh rec toàn cầu (không tồn tại) mà không có nó.

def fn1(): 
    a = """global rec 
def rec(n): 
    if n > 10: 
     return 
    print n 
    return rec(n+1) 

rec(5)""" 

    exec(a) 
4

Điều này làm tôi ngạc nhiên lúc đầu, và dường như là trường hợp góc kỳ lạ khi exec hoạt động không giống như định nghĩa cấp cao nhất hoặc định nghĩa trong một hàm kèm theo. Dường như những gì đang xảy ra là định nghĩa chức năng đang được thực hiện trong các địa phương() dict bạn vượt qua. Tuy nhiên, các chức năng được xác định không thực sự có quyền truy cập vào dict người dân địa phương này.

Thông thường, nếu bạn xác định một hàm ở cấp cao, người dân địa phương và hình cầu là như nhau, vì vậy các hàm sẽ hiển thị bên trong vì chúng có thể thấy hàm trong các hình cầu.

Khi hàm được xác định trong phạm vi hàm khác, python sẽ nhận thấy rằng nó được truy nhập trong hàm, và tạo một đóng để "ngựa" ánh xạ tới ràng buộc trong phạm vi bên ngoài.

Đây là trường hợp nửa chừng kỳ lạ.exec đang hoạt động như thể các định nghĩa ở mức cao nhất, vì vậy không có bao đóng được tạo ra. Tuy nhiên, vì người dân địa phương không giống như globals, định nghĩa không đi đến nơi mà hàm có thể truy cập nó - nó chỉ được định nghĩa trong dict bên ngoài không thể tiếp cận được.

Có một vài điều bạn có thể làm:

  1. Sử dụng các từ điển tương tự cho cả người dân địa phương và globals. tức là "exec s in locals(),locals()" (hoặc tốt hơn, chỉ cần sử dụng dict của riêng bạn). Chỉ cung cấp một globals() dict có cùng tác dụng - tức là "exec s in mydict" #
  2. Đặt hàm func bên trong chức năng riêng của nó, sao cho đóng được tạo ra. ví dụ

    s=""" 
    def go(): 
        def factorial(x): 
         if x==0: return 1 
         return x*factorial(x-1) 
        print factorial(10) 
    go()""" 
    
  3. Force chức năng để đi vào globals() chứ không phải là người dân địa phương bằng cách đặt một "funcname toàn cầu" chỉ thị, theo đề nghị của stephan's answer

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