Tuyên bố không nhắm mục tiêu Python


340

Câu nonlocallệnh Python làm gì (trong Python 3.0 trở lên)?

Không có tài liệu nào trên trang web Python chính thức và help("nonlocal")cũng không hoạt động.



18
Đây là tài liệu trang web chính thức của Python cho nonlocal: docs.python.org/3/reference/, (tài liệu này đã có sẵn từ Python 3.0, vì vậy, khẳng định của OP rằng không có tài liệu chính thức nào bị sai)
wkschwartz

3
"There is no documentation for nonlocal".Trên thực tế, bạn có thể làm help(keyword_in_string)tài liệu trong Python 3 trở lên
ytpillai

10
Để công bằng các loại tài liệu chính thức hút về chủ đề này. Ví dụ về câu trả lời được chọn làm cho mọi thứ rất rõ ràng, làm cho điều này trở thành một câu hỏi có giá trị.
Nhà vật lý điên

Trong hướng dẫn chính thức của Python có một lời giải thích tốt về khái niệm phạm vi và không gian tên với một ví dụ hay .
jammon

Câu trả lời:


471

So sánh điều này, mà không sử dụng nonlocal:

x = 0
def outer():
    x = 1
    def inner():
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 0

Về điều này, sử dụng nonlocal, nơi inner()xbây giờ cũng là outer()'s x:

x = 0
def outer():
    x = 1
    def inner():
        nonlocal x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 2
# global: 0

Nếu chúng ta sử dụng global, nó sẽ liên kết xvới giá trị "toàn cầu" đúng cách:

x = 0
def outer():
    x = 1
    def inner():
        global x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 2

32
Làm thế nào mà khác với toàn cầu x?
ooboo

52
Nó rất giống nhau - nhưng lưu ý rằng x bên ngoài không phải là toàn cục trong ví dụ mà thay vào đó được định nghĩa trong hàm ngoài.
Anon

3
@Dustin - Trên thực tế, nếu bạn có lớp A với thuộc tính x và lớp con B được xác định trong đó, bạn sẽ gọi x từ bên trong B là Ax
Anon

2
Mã dễ dàng bị thụt vào rất nhiều khi xác định các hàm bên trong và cuối cùng vi phạm khuyến nghị PEP8 79 ký tự. Bất kỳ cách nào để khắc phục vấn đề này? Một chức năng bên trong bằng cách nào đó có thể được đặt bên ngoài chức năng bên ngoài? Tôi biết câu hỏi nghe có vẻ ngu ngốc, nhưng tôi tha thiết.
tommy.carstensen 12/2/2015

3
@ tommy.carstensen bạn có thể vượt qua chức năng như một đối số đó là vẻ đẹp của các chức năng bậc cao. Ngoài ra trong lập trình chức năng, nó được gọi là thành phần, python không phải là ngôn ngữ FP thuần túy nhưng bạn chắc chắn có thể chơi với một tính năng (trình tạo, các hàm bậc cao hơn là một số ví dụ)
superuseroi

90

Nói tóm lại, nó cho phép bạn gán giá trị cho một biến trong phạm vi bên ngoài (nhưng không toàn cầu). Xem PEP 3104 để biết tất cả các thông tin chi tiết.


41

Một tìm kiếm google cho "python nonlocal" đã đưa ra Đề xuất, PEP 3104 , mô tả đầy đủ cú pháp và lý do đằng sau tuyên bố. Nói tóm lại, nó hoạt động chính xác giống như globalcâu lệnh, ngoại trừ việc nó được sử dụng để chỉ các biến không phải là toàn cục cũng không cục bộ của hàm.

Đây là một ví dụ ngắn gọn về những gì bạn có thể làm với điều này. Trình tạo bộ đếm có thể được viết lại để sử dụng cái này để nó trông giống như thành ngữ của các ngôn ngữ có bao đóng.

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

Rõ ràng, bạn có thể viết điều này như một trình tạo, như:

def counter_generator():
    count = 0
    while True:
        count += 1
        yield count

Nhưng trong khi đây là con trăn hoàn toàn thành ngữ, có vẻ như phiên bản đầu tiên sẽ rõ ràng hơn một chút cho người mới bắt đầu. Sử dụng đúng máy phát điện, bằng cách gọi hàm trả về, là một điểm nhầm lẫn phổ biến. Phiên bản đầu tiên trả về một hàm rõ ràng.


1
Tôi chắc chắn đó là những gì mà từ khóa 'toàn cầu' thực hiện - hoạt động với mức độ cao hơn cho đến khi nó đạt đến một biến có tên đó. một biến x có thể được khai báo ở cấp mô-đun, bên trong một lớp, sau đó riêng biệt trong một hàm bên trong lớp này và sau đó là một hàm bên trong của hàm đó - làm thế nào để biết x được đề cập đến?
ooboo

7
điều về toàn cầu là nó chỉ hoạt động cho các biến toàn cầu. nó không thể nhìn thấy các biến trong một phạm vi bao quanh, nonglobal.
SingleNegationElimination

Tôi đã thử make_count - tuy nhiên nó không trả về trình tạo mà là hàm. Có cách nào để trả lại một máy phát điện để sau này tôi có thể lặp lại nó không?
Dejell

@Dejel: ví dụ này nhằm minh họa cho nonlocalcâu lệnh trong Python; Nếu bạn muốn một chuỗi các số tự nhiên, thành ngữ python thực sự làitertools.count()
SingleNegationElimination 5/12/13

Tôi muốn giới thiệu khả năng trả về một trình tạo như với năng suất - năng suất thực sự trả về một trình tạo. Ý tưởng của tôi là không sử dụng năng suất và thay vào đó có thể sử dụng giải pháp không
nhắm mục

15

@ooboo:

Nó lấy điểm "gần nhất" với điểm tham chiếu trong mã nguồn. Điều này được gọi là "Phạm vi từ điển" và là tiêu chuẩn cho> 40 năm nay.

Các thành viên lớp của Python thực sự nằm trong một từ điển được gọi __dict__và sẽ không bao giờ đạt được bằng phạm vi từ vựng.

Nếu bạn không chỉ định nonlocalnhưng thực hiện x = 7, nó sẽ tạo một biến cục bộ mới "x". Nếu bạn chỉ định nonlocal, nó sẽ tìm "x" gần nhất "và gán cho nó. Nếu bạn chỉ định nonlocalvà không có "x", nó sẽ cung cấp cho bạn một thông báo lỗi.

Từ khóa globalluôn có vẻ lạ đối với tôi vì nó sẽ vui vẻ bỏ qua tất cả các "x" khác ngoại trừ từ ngoài cùng. Kỳ dị.


14

help ('nonlocal') nonlocalTuyên bố


    nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*

Câu nonlocallệnh làm cho các định danh được liệt kê đề cập đến các biến bị ràng buộc trước đó trong phạm vi kèm theo gần nhất. Điều này rất quan trọng vì hành vi mặc định cho ràng buộc là tìm kiếm không gian tên cục bộ trước tiên. Câu lệnh cho phép mã được đóng gói để khởi động lại các biến bên ngoài phạm vi cục bộ bên cạnh phạm vi toàn cầu (mô-đun).

Các tên được liệt kê trong một nonlocaltuyên bố, không giống như các tên được liệt kê trong một globaltuyên bố, phải đề cập đến các ràng buộc tồn tại trước trong một phạm vi kèm theo (phạm vi mà một ràng buộc mới sẽ được tạo ra không thể được xác định rõ ràng).

Tên được liệt kê trong một nonlocaltuyên bố không được va chạm với các ràng buộc có sẵn trong phạm vi địa phương.

Xem thêm:

PEP 3104 - Truy cập vào tên trong phạm vi bên ngoài
Đặc điểm kỹ thuật cho nonlocalcâu lệnh.

Các chủ đề trợ giúp liên quan: toàn cầu, NnamPACES

Nguồn: Tài liệu tham khảo ngôn ngữ Python


11
Học điều mới mỗi ngày. Tôi không biết bạn có thể sử dụng help()từ khóa nào (và bây giờ tâm trí tôi bị thổi bay: help()không có đối số nào tương tác ).
Erik Youngren

6

Trích dẫn từ tài liệu tham khảo Python 3 :

Câu lệnh không nhắm mục tiêu làm cho các định danh được liệt kê tham chiếu đến các biến bị ràng buộc trước đó trong phạm vi kèm theo gần nhất, ngoại trừ toàn cục.

Như đã nói trong tài liệu tham khảo, trong trường hợp một số hàm lồng nhau chỉ có biến trong hàm kèm theo gần nhất được sửa đổi:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        x = 2
        innermost()
        if x == 3: print('Inner x has been modified')

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Inner x has been modified

Biến "gần nhất" có thể cách một vài mức:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Outer x has been modified

Nhưng nó không thể là một biến toàn cục:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    inner()

x = 0
outer()
if x == 3: print('Global x has been modified')

# SyntaxError: no binding for nonlocal 'x' found

3
a = 0    #1. global variable with respect to every function in program

def f():
    a = 0          #2. nonlocal with respect to function g
    def g():
        nonlocal a
        a=a+1
        print("The value of 'a' using nonlocal is ", a)
    def h():
        global a               #3. using global variable
        a=a+5
        print("The value of a using global is ", a)
    def i():
        a = 0              #4. variable separated from all others
        print("The value of 'a' inside a function is ", a)

    g()
    h()
    i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)

2

Hiểu biết cá nhân của tôi về câu lệnh "không nhắm mục tiêu" (và xin lỗi vì tôi là người mới đối với Python và Lập trình nói chung) là "không nhắm mục tiêu" là một cách để sử dụng chức năng Toàn cầu trong các hàm lặp chứ không phải là thân mã. . Một tuyên bố toàn cầu giữa các chức năng nếu bạn sẽ.


0

với các hàm bên trong 'không tiêu điểm' (nghĩa là các hàm bên trong lồng nhau) có thể có được quyền đọc & ' ghi ' cho biến cụ thể đó của hàm cha ngoài . Và nonlocal chỉ có thể được sử dụng bên trong các chức năng bên trong, ví dụ:

a = 10
def Outer(msg):
    a = 20
    b = 30
    def Inner():
        c = 50
        d = 60
        print("MU LCL =",locals())
        nonlocal a
        a = 100
        ans = a+c
        print("Hello from Inner",ans)       
        print("value of a Inner : ",a)
    Inner()
    print("value of a Outer : ",a)

res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.