2011-10-28 30 views
38

Giả sử tôi có mã python sau:Python ghi đè lên các biến trong chức năng lồng nhau

def outer(): 
    string = "" 
    def inner(): 
     string = "String was changed by a nested function!" 
    inner() 
    return string 

Tôi muốn có một cuộc gọi đến bên ngoài() để trở về "! Chuỗi được thay đổi bởi một hàm lồng nhau", nhưng tôi nhận được "" . Tôi kết luận rằng Python nghĩ rằng dòng string = "string was changed by a nested function!" là một khai báo của một biến mới cục bộ để bên trong(). Câu hỏi của tôi là: làm thế nào để tôi nói với Python rằng nó nên sử dụng chuỗi bên ngoài()? Tôi không thể sử dụng từ khóa global, bởi vì chuỗi không phải là toàn cầu, nó chỉ sống trong một phạm vi bên ngoài. Ý tưởng?

+0

Có thể liên quan: http://stackoverflow.com/q/146359/212218 –

Trả lời

35

Trong Python 3.x, bạn có thể sử dụng nonlocal keyword:

def outer(): 
    string = "" 
    def inner(): 
     nonlocal string 
     string = "String was changed by a nested function!" 
    inner() 
    return string 

Trong Python 2.x, bạn có thể sử dụng một danh sách với một yếu tố duy nhất và ghi đè lên rằng yếu tố duy nhất:

def outer(): 
    string = [""] 
    def inner(): 
     string[0] = "String was changed by a nested function!" 
    inner() 
    return string[0] 
+0

+1 công việc thứ hai: Phân công vật phẩm (cùng với phân bổ thuộc tính) không phải là phép gán biến - 'x [...] = ...' chỉ nhận 'x' từ bất kỳ phạm vi nào mà nó có thể, và gọi phương thức' __setitem__' của nó . Một lựa chọn tiết kiệm hơn, nhưng ban đầu hơn là tạo một đối tượng (của một lớp do người dùng định nghĩa, vì 'object()' sẽ không cho phép thêm các thuộc tính) với mục đích duy nhất là giữ một thuộc tính. – delnan

+2

Bạn có thể tạo một đối tượng không gian tên như vậy bằng cách sử dụng 'x = type (" ",(), {})()'. :) –

+0

Vì vậy, 'nonlocal' có nghĩa là:" tìm biến này trong phạm vi ngoài "- nếu biến không được tìm thấy trong phạm vi bên ngoài(), liệu Python có tiếp tục tìm kiếm trong phạm vi bao quanh không? Liệu Python cuối cùng sẽ cố gắng tìm biến trong phạm vi toàn cầu? – Ord

2

để thêm vào Sven's answer:

Trong Python 2.x, bạn chỉ có thể đọc biến phạm vi bên ngoài từ nhà trọ phạm vi er. Việc chỉ định sẽ chỉ tạo một biến cục bộ mới (tức là phạm vi bên trong) mà ẩn một phạm vi bên ngoài.

Nếu bạn muốn đọc và sửa đổi, bạn có thể sử dụng một dict để giữ các biến của bạn trong phạm vi bên ngoài, và sau đó truy cập chúng qua dict trong phạm vi bên trong, cũng giữ mã của bạn khá sạch và có thể đọc được trong sự hiện diện của nhiều phạm vi bên ngoài vars:

def outer(): 
    # hold some text, plus the number of spaces in the text 
    vars = {'text': 'Some text.', 'num_spaces': 1} 
    def inner(): 
     # add some more text 
     more_text = ' Then some more text.' 
     vars['text'] += more_text 
     # keep track of the number of spaces 
     vars['num_spaces'] += more_text.count(' ') 
    inner() 
    return vars['text'], vars['num_spaces'] 

đầu ra:

>>> outer() 
('Some text. Then some more text.', 5) 
19

Bạn cũng có thể giải quyết vấn đề này bằng cách sử dụng các thuộc tính hàm:

def outer(): 
    def inner(): 
     inner.string = "String was changed by a nested function!" 
    inner.string = "" 
    inner() 
    return inner.string 

Làm rõ: điều này hoạt động ở cả hai trăn 2.x và 3.x.

+3

Đây thực sự là một ý tưởng tuyệt vời. – Alice

3

Điều này xảy ra với tôi quá thường xuyên, khi tôi đang viết một hàm và tôi đột nhiên nhận ra rằng có thể có một hàm trợ giúp nhỏ hơn, nhưng không thực sự hữu ích ở bất kỳ nơi nào khác. mà tự nhiên làm cho tôi muốn định nghĩa nó bên trong như một hàm lồng nhau.

nhưng tôi đã có kinh nghiệm với đối tượng ẩn danh JAVA (ví dụ: xác định một runnable), và quy tắc là đối tượng ẩn danh tạo ra một bản sao cứng của môi trường bên ngoài của nó, trong trường hợp này biến của phạm vi bên ngoài. Do đó, nếu biến ngoài là bất biến (int, char), chúng không thể được sửa đổi bởi đối tượng ẩn danh khi chúng được sao chép bởi giá trị trong khi nếu nó có thể thay đổi (collection, objects), chúng có thể thay đổi ... được sao chép theo "con trỏ" (địa chỉ của chúng trong bộ nhớ)

nếu bạn biết về lập trình, hãy nghĩ về việc lập trình, suy nghĩ về nó theo giá trị và vượt qua tham chiếu.

trong python, nó rất giống nhau.x=123 được chuyển nhượng, họ đưa ra những ý nghĩa mới xa biến (không thay đổi x cũ), list[i]/dict[key] là hoạt động truy cập đối tượng, họ thực sự sửa đổi điều

để kết luận, bạn cần một đối tượng có thể thay đổi ... để sửa đổi (mặc dù bạn có thể truy cập một bộ dữ liệu bằng [], bạn không thể sử dụng nó ở đây vì nó không thể thay đổi được)

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