2011-11-08 41 views
6

Câu hỏi này là theo dõi trên a question about Python variable scope. Bạn có thể tìm thấy câu hỏi bổ sung q1, q2answers trên SO, thậm chí nhiều hơn nữa. Chính thức Python documentationPEP 3104 có nghĩa vụ giải thích chi tiết, nhưng dường như chúng không hoàn toàn tự giải thích cho tôi.Nonlocal của Python phụ thuộc vào mức độ phân cấp?

Chủ đề tôi đang cố gắng giải quyết là tái cấu trúc mã có chứa nonlocal/global bằng cách di chuyển mã lên/xuống một cấp phân cấp.

Những gì tôi không hiểu là ý nghĩa của câu này từ tài liệu tham khảo Python:

Names listed in a nonlocal statement, unlike to those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).

Với đoạn mã sau vào phạm vi toàn cầu:

var = 0 
def outer(): 
    global var     # line A 
    var = 1 
    def inner(): 
     nonlocal var   # line B 
     var = 2 

     print('inner:', var) 

    inner() 
    print('outer:', var) 

outer() 
print('main:', var) 

Thực hiện đặt ra một lỗi:

SyntaxError: no binding for nonlocal 'var' found 

Mã hoạt động (với các ngữ nghĩa khác nhau, Dĩ nhiên, nếu một trong hai dòng A được nhận xét ra:

inner: 2 
outer: 2 
main: 0 

hoặc dòng B là nhận xét ra:

inner: 2 
outer: 1 
main: 1 

Tuy nhiên, trong ví dụ trên, và kể từ nonlocal là nghĩa vụ để ràng buộc var cho " kèm theo phạm vi ", tôi đã có thể mong đợi rằng dòng A liên kết bên ngoài/var vào phạm vi toàn cầu và dòng B sau đó tìm bên ngoài/var và cũng rebinds bên trong/var để toàn cầu/var. Thay vào đó có vẻ như không tìm thấy nó ở tất cả (do rebinding trong dòng A, tôi giả sử) và đưa ra một lỗi.

Các kết quả mong muốn tôi mong đợi là:

inner: 2 
outer: 2 
main: 2 

Đây có phải là ví dụ chỉ cần thêm một trong những trạng thái khó hiểu của tâm trí của Phạm vi bằng Python?

Hoặc, để làm điều này một câu hỏi mang tính xây dựng:

  • Làm thế nào một ví dụ như vậy có thể được viết theo một cách mà nó không quan trọng mà tại đó mức một chức năng cư trú (có trao đổi global với nonlocal và ngược lại)?
  • Nếu các chức năng cư trú ở cấp bậc trung gian và không xác định, làm cách nào để tác giả của outer() thay đổi mã không ở mức ngoài cùng (trong trường hợp này), cũng không phải mức độ inner() phải được xúc động? -

Theo hiểu biết khiêm tốn của tôi về ngôn ngữ, việc xây dựng như thế này (phụ thuộc vào đóng cửa) chỉ cần tránh. Những người khác đã đề xuất sử dụng các tính năng ngôn ngữ khác (classes, func attrs) để đạt được loại độ nhạy ngữ cảnh này.

+0

Biến toàn cục và cục bộ về cơ bản là khác nhau trong Python. Các câu lệnh 'nonlocal' chỉ có thể tham chiếu đến các biến cục bộ của một phạm vi kèm theo và không bao giờ đến các biến toàn cục - đó là cái' toàn cục' là sau cùng. Các khái niệm đằng sau 'global' và' nonlocal' khá khác nhau. Lập luận của bạn như thế nào hiện trạng nhà nước nên đặt ra một vấn đề được xây dựng hoàn toàn. Câu trả lời của tôi là: Không sử dụng các biến toàn cầu, và không sử dụng 'global', và tất cả các vấn đề" đã đề cập "(và một vài thứ nữa) sẽ biến mất. –

+0

Mặc dù tôi thường đồng ý tránh sử dụng hình cầu, những người khác dường như thấy khái niệm hữu ích đến nỗi Python cung cấp từ khóa 'global' và Py3k thậm chí còn thêm một' nonlocal'. Tôi đang cố gắng hiểu những tác động của việc sử dụng kết hợp của họ. – cfi

+1

"... và Py3k thậm chí còn thêm một' nonlocal'. " 'nonlocal' có nghĩa là làm cho các bao đóng hữu ích hơn. Nó không liên quan đến các biến toàn cục. –

Trả lời

6

globalnonlocal không được kết hợp.Họ có nghĩa là những thứ khác nhau:

  • global nghĩa tên tồn tại ở các cấp module
  • nonlocal nghĩa tên tồn tại trong một phạm vi chức năng từ vựng ngoài

Lý do bạn đang nhận được ngoại lệ ban đầu là vì bạn đã nói với Python rằng var là không trung tâm (nghĩa là nó nằm trong định nghĩa hàm ngoài), nhưng có không có ràng buộc mức chức năng cho var trong bất kỳ định nghĩa hàm bên ngoài nào vì bạn đã nói với Python trong chức năng bên ngoài mà var là toàn cầu.

+0

"toàn cầu và không trung tâm không có nghĩa là để được kết hợp" và đó là chính xác vấn đề của tôi: Nếu không, sau đó tái cấu trúc mã được thực hiện khó khăn hơn. Cho rằng một hàm trong cùng sử dụng một 'nonlocal' và hàm xung quanh ngay lập tức. Nếu hàm xung quanh thay đổi liên kết thành 'global', thì hàm bên trong nhất phải được thay đổi. Nhưng, than ôi, với cú pháp ở bàn tay tôi không thấy một cách khác. (Nhưng để sử dụng trình bao bọc lớp học và như vậy) – cfi

+0

Tôi thấy quan điểm của bạn, nhưng dường như tôi không phải là một lượng công việc không hợp lý nếu bạn đang tái cấu trúc các đóng cửa thành không đóng cửa. –

0

How can such an example be written in a way that it does not matter at which level a function resides (having to exchange global with nonlocal and vice versa)?

Không quan trọng ở mức độ mà một hàm cư trú. Nó chỉ quan trọng ở cấp độ mà biến đó cư trú.

If the functions reside at an intermediate, and unknown level of hierarchy, how could the author of outer() change the code that neither the outermost (in this case global) level, nor the inner() level have to be touched?

Bạn đang tự hỏi liệu nó có thể cho một chức năng ở mức độ trung gian, bằng cách thay đổi một cái gì đó trong mã của nó, gây ra một biến trong một chức năng bên trong để luân phiên thay đổi một cái gì đó ở một phạm vi toàn cầu hoặc một cái gì đó trong phạm vi địa phương của hàm bên ngoài. Điều này có vẻ giống như một điều thực sự kỳ lạ để có thể làm được.

+0

Quan điểm của tôi là về tái cấu trúc: Nếu hàm trung tâm cùng với hàm bên trong của nó được di chuyển một mức thấp hơn, một 'nonlocal' sẽ phải được thay đổi trong' global', ngay cả khi hàm xung quanh ngay lập tức cũng sử dụng biến đó. Hm, tôi bắt đầu nghĩ rằng tôi đã chọn một ví dụ tồi để nêu chi tiết vấn đề tôi có với cú pháp/phạm vi này. – cfi

+0

@cfi Tôi chỉ muốn chắc chắn rằng tôi hiểu ý bạn là gì: "Nếu chức năng ở giữa cùng với chức năng bên trong của nó được di chuyển xuống một mức thấp hơn". Ban đầu, cả 'var' và' outer' đều nằm trong khối của hàm khác, do đó cả 'bên ngoài' và' bên trong' sử dụng 'nonlocal var'. Bằng cách di chuyển "hàm trung tâm cùng với hàm bên trong của nó một mức thấp hơn", bạn có nghĩa là di chuyển cả 'var' và' outer' gần với phạm vi toàn cục hơn? Và nếu phạm vi mới này cho 'var' và' outer' là phạm vi toàn cục, bạn sẽ phải thay đổi cả 'nonlocal var' trong' outer' và trong 'inner' thành' global var'? – user42768

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