Tên bóng từ Python phạm vi bên ngoài

Trong bài trước chúng ta đã xem xét các đối số vị trí và từ khóa trong một hàm. Chúng ta đã thấy các đối số vị trí khớp với các đối số trong chữ ký hàm như thế nào. Chúng ta cũng đã thảo luận cách các đối số từ khóa có thể làm cho mã của bạn gọn gàng hơn bằng cách cung cấp rõ ràng các tên đối số trong lệnh gọi hàm.

Trong bài đăng này, chúng ta sẽ xem làm thế nào một biến được khai báo bên trong một hàm có thể làm lu mờ một biến khác được khai báo bên ngoài nó

Phạm vi biến đổi

Phạm vi biến có nghĩa là vị trí giới hạn trong mã nơi biến có thể được sử dụng và có giá trị có ý nghĩa. Loại phạm vi phổ biến nhất là cục bộ. Các biến có phạm vi cục bộ được sử dụng trong một hàm. Chúng tôi đã thấy các ví dụ về điều đó trước đây

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

Các biến “prompt_text” và “user_input” đều là các biến cục bộ có thể được truy cập trong phương thức get_integer_input. Chúng không thể được truy cập bên ngoài chức năng này

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)

Đoạn mã trên sẽ không được biên dịch vì user_input không được xác định ở mức đó

Tất nhiên, các biến có thể được khai báo ở cấp độ cao hơn được gọi là phạm vi toàn cầu

user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)

Biến user_input ở dòng đầu tiên có phạm vi toàn cầu và câu lệnh in sẽ in ra “10”. Biến user_input cục bộ trong get_integer_input không liên quan gì đến user_input được khai báo trên toàn cầu ngay trước đó. Để chứng minh điều này, chúng tôi sẽ mở rộng mã một chút

user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    print(user_input)
    return int(user_input)

int_input = get_integer_input("Provide a number: ")
print(user_input)

Nếu bạn chạy đoạn mã trên và nhập e. g. 40 làm đầu vào trên dòng…

user_input = input(prompt_text)

…thì câu lệnh in ra sẽ cho kết quả 40 và 10. Biến user_input toàn cầu không bị ảnh hưởng bởi khai báo và gán biến user_input cục bộ

Nếu bạn sử dụng PyCharm thì bạn sẽ thấy một dòng nguệch ngoạc màu xám bên dưới user_input trong hàm get_integer_input. Nếu bạn di chuột qua biến, bạn sẽ thấy lý do. tên bóng tối 'user_input' từ phạm vi bên ngoài. Vì vậy, user_input trong get_integer_input che khuất biến user_input được khai báo trên toàn cầu

Lưu ý rằng không có gì sai với điều này theo nghĩa lập trình. Mã biên dịch và chạy và rất có thể bạn có ý định giới thiệu một biến cục bộ có cùng tên với biến toàn cầu. Thông báo trong PyCharm chỉ là kiểm tra an toàn. bạn thực sự muốn che giấu một biến khác hay bạn đang đề cập đến biến toàn cục?

user_input = 10

def get_integer_input(prompt_text):
    global user_input
    user_input = input(prompt_text)
    print(user_input)
    return int(user_input)

int_input = get_integer_input("Provide a number: ")
print(user_input)

Chạy mã với 40 làm đầu vào của người dùng cũng sẽ thay đổi giá trị của biến user_input được khai báo toàn cục thành 40. Các câu lệnh in sẽ in 40 và 40 tương ứng

https. // stackoverflow. com/câu hỏi/43186844/python-static-class-variables/43200798#43200798 https. // stackoverflow. com/câu hỏi/68645/are-static-class-biến-có thể https. // stackoverflow. com/câu hỏi/19902127/what-is-the-pythonic-way-to-avoid-shadowing-variables

Trong hầu hết các ngôn ngữ hỗ trợ phạm vi lồng nhau, mã có thể tham chiếu hoặc liên kết lại (gán) bất kỳ tên nào trong phạm vi kèm theo gần nhất. Hiện tại, mã Python có thể tham chiếu đến một tên trong bất kỳ phạm vi kèm theo nào, nhưng nó chỉ có thể liên kết lại các tên trong hai phạm vi. phạm vi cục bộ (bằng cách gán đơn giản) hoặc phạm vi mô-đun-toàn cầu (sử dụng khai báo

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0)

Giới hạn này đã được nêu ra nhiều lần trong danh sách gửi thư của Python-Dev và các nơi khác, và đã dẫn đến cuộc thảo luận mở rộng và nhiều đề xuất về cách loại bỏ giới hạn này. PEP này tóm tắt các phương án thay thế khác nhau đã được đề xuất, cùng với các ưu điểm và nhược điểm đã được đề cập cho từng phương án.

cơ sở lý luận

Trước phiên bản 2. 1, Cách xử lý phạm vi của Python giống với cách xử lý của tiêu chuẩn C. trong một tệp chỉ có hai mức phạm vi, toàn cầu và cục bộ. Trong C, đây là hệ quả tự nhiên của thực tế là các định nghĩa hàm không thể được lồng vào nhau. Nhưng trong Python, mặc dù các hàm thường được định nghĩa ở mức cao nhất, nhưng một định nghĩa hàm có thể được thực thi ở bất cứ đâu. Điều này mang lại cho Python hình thức cú pháp của phạm vi lồng nhau mà không có ngữ nghĩa, và tạo ra sự không nhất quán khiến một số lập trình viên ngạc nhiên – ví dụ: một hàm đệ quy hoạt động ở mức cao nhất sẽ ngừng hoạt động khi được di chuyển bên trong một hàm khác, bởi vì hàm đệ quy của riêng nó. . Điều này vi phạm trực giác rằng một hàm sẽ hoạt động nhất quán khi được đặt trong các ngữ cảnh khác nhau. Đây là một ví dụ

def enclosing_function():
    def factorial(n):
        if n < 2:
            return 1
        return n * factorial(n - 1)  # fails with NameError
    print factorial(5)

Trăn 2. 1 tiến gần hơn đến phạm vi lồng nhau tĩnh bằng cách hiển thị các tên bị ràng buộc trong tất cả các phạm vi kèm theo (xem PEP 227). Thay đổi này làm cho ví dụ mã trên hoạt động như mong đợi. Tuy nhiên, vì bất kỳ phép gán nào cho một tên đều ngầm khai báo tên đó là cục bộ, nên không thể ràng buộc lại một tên trong phạm vi bên ngoài (ngoại trừ khi khai báo

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 buộc tên đó phải là toàn cầu). Do đó, mã sau đây, nhằm hiển thị một số có thể tăng và giảm bằng cách nhấp vào các nút, không hoạt động như những người quen thuộc với phạm vi từ vựng có thể mong đợi

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label

Cú pháp Python không cung cấp cách để chỉ ra rằng tên

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
2 được đề cập trong
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
3 đề cập đến biến
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
2 được liên kết trong
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
5, không phải là biến cục bộ trong
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
3. Người dùng và nhà phát triển Python đã bày tỏ sự quan tâm đến việc loại bỏ giới hạn này để Python có thể có đầy đủ tính linh hoạt của mô hình phạm vi kiểu Algol hiện là tiêu chuẩn trong nhiều ngôn ngữ lập trình, bao gồm JavaScript, Perl, Ruby, Scheme, Smalltalk, C với . 0

Người ta đã lập luận rằng một tính năng như vậy là không cần thiết, bởi vì một biến bên ngoài có thể rebindable có thể được mô phỏng bằng cách gói nó trong một đối tượng có thể thay đổi

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
5

Tuy nhiên, cách giải quyết này chỉ làm nổi bật những thiếu sót của phạm vi hiện có. mục đích của một chức năng là đóng gói mã trong không gian tên riêng của nó, do đó, có vẻ như không may là lập trình viên phải tạo các không gian tên bổ sung để bù cho chức năng bị thiếu trong các phạm vi cục bộ hiện có và sau đó phải quyết định xem mỗi tên có nên nằm trong đó hay không.

Một phản đối phổ biến khác là thay vào đó, chức năng mong muốn có thể được viết dưới dạng một lớp, mặc dù hơi dài dòng hơn. Một phản bác đối với sự phản đối này là sự tồn tại của một kiểu triển khai khác không phải là lý do để cấu trúc lập trình được hỗ trợ (phạm vi lồng nhau) không hoàn thiện về mặt chức năng. Python đôi khi được gọi là “ngôn ngữ đa mô hình” vì nó có được rất nhiều sức mạnh, tính linh hoạt thực tế và khả năng sư phạm từ sự hỗ trợ và tích hợp duyên dáng của nhiều mô hình lập trình

Một đề xuất về cú pháp xác định phạm vi đã xuất hiện trên Python-Dev từ năm 1994 [1], rất lâu trước khi PEP 227 hỗ trợ cho các phạm vi lồng nhau được thông qua. Vào thời điểm đó, phản ứng của Guido là

Điều này rất nguy hiểm khi giới thiệu CSNS [phạm vi lồng nhau tĩnh cổ điển]. Nếu bạn làm như vậy, ngữ nghĩa được đề xuất của bạn về phạm vi có vẻ ổn. Tôi vẫn nghĩ rằng CSNS không đủ nhu cầu để đảm bảo loại công trình này…

Sau PEP 227, “cuộc thảo luận về việc hủy bỏ tên bên ngoài” đã xuất hiện lại trên Python-Dev đủ số lần để nó trở thành một sự kiện quen thuộc, đã tái diễn ở dạng hiện tại ít nhất là từ năm 2003 [2]. Mặc dù chưa có thay đổi ngôn ngữ nào được đề xuất trong các cuộc thảo luận này được thông qua, Guido đã thừa nhận rằng thay đổi ngôn ngữ đáng được xem xét [12]

Những ngôn ngữ khác

Để cung cấp một số thông tin cơ bản, phần này mô tả cách một số ngôn ngữ khác xử lý các phạm vi lồng nhau và liên kết lại

JavaScript, Perl, Lược đồ, Smalltalk, GNU C, C# 2. 0

Các ngôn ngữ này sử dụng khai báo biến để chỉ ra phạm vi. Trong JavaScript, một biến có phạm vi từ vựng được khai báo bằng từ khóa

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
7; . Trong Perl, một biến phạm vi từ vựng được khai báo với từ khóa
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
8; . Trong Scheme, tất cả các biến phải được khai báo (với
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
9 hoặc
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
50 hoặc dưới dạng tham số chính thức). Trong Smalltalk, bất kỳ khối nào cũng có thể bắt đầu bằng cách khai báo danh sách tên biến cục bộ giữa các thanh dọc. C và C# yêu cầu khai báo kiểu cho tất cả các biến. Đối với tất cả các trường hợp này, biến thuộc phạm vi chứa khai báo

Ruby (kể từ ngày 1. số 8)

Ruby là một ví dụ mang tính hướng dẫn bởi vì nó dường như là ngôn ngữ phổ biến duy nhất hiện nay, giống như Python, cố gắng hỗ trợ các phạm vi lồng nhau tĩnh mà không yêu cầu khai báo biến, và do đó phải đưa ra một giải pháp khác thường. Các hàm trong Ruby có thể chứa các định nghĩa hàm khác và chúng cũng có thể chứa các khối mã được đặt trong dấu ngoặc nhọn. Các khối có quyền truy cập vào các biến bên ngoài, nhưng các hàm lồng nhau thì không. Trong một khối, việc gán cho một tên ngụ ý chỉ khai báo một biến cục bộ nếu nó không che khuất một tên đã bị ràng buộc trong phạm vi bên ngoài; . Cú pháp và quy tắc phạm vi của Ruby cũng đã được tranh luận rất lâu và các thay đổi dường như có thể xảy ra trong Ruby 2. 0 [28]

Tổng quan về đề xuất

Đã có nhiều đề xuất khác nhau trên Python-Dev về cách liên kết lại tên trong phạm vi bên ngoài. Tất cả đều rơi vào hai loại. cú pháp mới trong phạm vi nơi tên bị ràng buộc hoặc cú pháp mới trong phạm vi nơi tên được sử dụng

Cú pháp mới trong phạm vi ràng buộc (bên ngoài)

Tuyên bố ghi đè phạm vi

Các đề xuất trong danh mục này đều đề xuất một loại câu lệnh khai báo mới tương tự như

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
7 của JavaScript. Một vài từ khóa có thể đã được đề xuất cho mục đích này

  • def get_integer_input(prompt_text):
        user_input = input(prompt_text)
        return int(user_input)
    
    print(user_input)
    
    52 [4]
  • def get_integer_input(prompt_text):
        user_input = input(prompt_text)
        return int(user_input)
    
    print(user_input)
    
    53 [4] [9]
  • def get_integer_input(prompt_text):
        user_input = input(prompt_text)
        return int(user_input)
    
    print(user_input)
    
    54 [13]

Trong tất cả các đề xuất này, một khai báo chẳng hạn như

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
53 trong một phạm vi S cụ thể sẽ khiến tất cả các tham chiếu đến
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 trong các phạm vi được lồng trong S để tham chiếu đến ràng buộc
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 trong S

Sự phản đối chính đối với loại đề xuất này là ý nghĩa của một định nghĩa hàm sẽ trở nên nhạy cảm với ngữ cảnh. Di chuyển một định nghĩa hàm bên trong một số khối khác có thể khiến bất kỳ tham chiếu tên cục bộ nào trong hàm trở thành không cục bộ, do các khai báo trong khối kèm theo. Đối với các khối trong Ruby 1. 8, đây thực sự là trường hợp;

user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
7

Lưu ý rằng mặc dù đề xuất này giống với các khai báo trong JavaScript và Perl, nhưng hiệu ứng đối với ngôn ngữ là khác bởi vì trong các ngôn ngữ đó, các biến không được khai báo là toàn cục theo mặc định, trong khi ở Python các biến không được khai báo là cục bộ theo mặc định. Do đó, việc di chuyển một hàm bên trong một số khối khác trong JavaScript hoặc Perl chỉ có thể giảm phạm vi của tham chiếu tên toàn cục trước đó, trong khi ở Python với đề xuất này, nó có thể mở rộng phạm vi của tham chiếu tên cục bộ trước đó

Khai báo biến bắt buộc

Một đề xuất triệt để hơn [21] đề xuất loại bỏ hoàn toàn quy ước đoán phạm vi của Python và yêu cầu tất cả các tên phải được khai báo trong phạm vi mà chúng bị ràng buộc, giống như Đề án. Với đề xuất này,

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
58 sẽ tuyên bố cả
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 thuộc về phạm vi cục bộ và ràng buộc nó, trong khi
user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
70 sẽ ràng buộc lại
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 hiển thị hiện có. Trong ngữ cảnh không có phạm vi kèm theo chứa khai báo
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
53, tuyên bố
user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
70 sẽ được xác định tĩnh là bất hợp pháp

Đề xuất này mang lại một mô hình đơn giản và nhất quán, nhưng nó sẽ không tương thích với tất cả mã Python hiện có

Cú pháp mới trong phạm vi giới thiệu (bên trong)

Có ba loại đề xuất trong danh mục này

Biểu thức tham chiếu bên ngoài

Loại đề xuất này gợi ý một cách mới để đề cập đến một biến trong phạm vi bên ngoài khi sử dụng biến trong một biểu thức. Một cú pháp đã được đề xuất cho điều này là

user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
74 [7], sẽ tham chiếu đến
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 mà không tạo ràng buộc cục bộ cho nó. Một mối quan tâm với đề xuất này là trong nhiều ngữ cảnh,
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 và
user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
74 có thể được sử dụng thay thế cho nhau, điều này sẽ gây nhầm lẫn cho người đọc [31]. Một ý tưởng có liên quan chặt chẽ là sử dụng nhiều dấu chấm để chỉ định số cấp độ phạm vi tăng dần [8], nhưng hầu hết đều cho rằng điều này quá dễ xảy ra lỗi [17]

Toán tử phục hồi

Đề xuất này gợi ý một toán tử giống như phép gán mới, nối lại một tên mà không khai báo tên đó là cục bộ [2]. Trong khi câu lệnh

user_input = 10

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
70 đều khai báo
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 là biến cục bộ và liên kết nó với 3, thì câu lệnh
user_input = input(prompt_text)
00 sẽ thay đổi liên kết hiện có của
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 mà không cần khai báo biến cục bộ

Đây là một giải pháp đơn giản, nhưng theo PEP 3099, nó đã bị từ chối (có lẽ vì nó quá dễ bỏ sót hoặc nhầm lẫn với

user_input = input(prompt_text)
02)

Tuyên bố ghi đè phạm vi

Các đề xuất trong danh mục này đề xuất một loại câu lệnh khai báo mới trong phạm vi bên trong để ngăn tên trở thành địa phương. Câu lệnh này về bản chất sẽ tương tự như câu lệnh

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0, nhưng thay vì đặt tên tham chiếu đến một liên kết trong phạm vi cấp mô-đun cao nhất, nó sẽ đặt tên tham chiếu đến liên kết trong phạm vi kèm theo gần nhất

Cách tiếp cận này hấp dẫn do nó song song với cấu trúc Python quen thuộc và vì nó duy trì tính độc lập với ngữ cảnh cho các định nghĩa hàm

Cách tiếp cận này cũng có lợi thế từ góc độ bảo mật và gỡ lỗi. Python kết quả sẽ không chỉ phù hợp với chức năng của các ngôn ngữ phạm vi lồng nhau khác mà còn làm như vậy với một cú pháp thậm chí còn tốt hơn cho lập trình phòng thủ. Trong hầu hết các ngôn ngữ khác, một khai báo thu hẹp phạm vi của một tên hiện có, do đó, việc vô tình bỏ qua khai báo có thể mang lại khả năng tiếp cận xa hơn (i. e. nguy hiểm hơn) ảnh hưởng hơn mong đợi. Trong Python với đề xuất này, nỗ lực bổ sung thêm khai báo phù hợp với nguy cơ gia tăng các hiệu ứng phi cục bộ (i. e. con đường ít kháng cự nhất là con đường an toàn hơn)

Nhiều cách viết đã được đề xuất cho một tuyên bố như vậy

  • user_input = input(prompt_text)
    
    04 [1]
  • user_input = input(prompt_text)
    
    05 [3] (chỉ rõ phạm vi nào)
  • user_input = input(prompt_text)
    
    06 [5]
  • user_input = input(prompt_text)
    
    07 [6]
  • user_input = input(prompt_text)
    
    08 [9]
  • user_input = input(prompt_text)
    
    09 [10] (thay đổi ý nghĩa của
    def make_scoreboard(frame, score=0):
        label = Label(frame)
        label.pack()
        for i in [-10, -1, 1, 10]:
            def increment(step=i):
                score = score + step  # fails with UnboundLocalError
                label['text'] = score
            button = Button(frame, text='%+d' % i, command=increment)
            button.pack()
        return label
    
    0)
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    11 [11]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    12 [18]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    13 [18]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    14 [18]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    15 [20]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    16 [22]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    17 [22]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    18 [22]
  • user_input = 10
    
    def get_integer_input(prompt_text):
        global user_input
        user_input = input(prompt_text)
        print(user_input)
        return int(user_input)
    
    int_input = get_integer_input("Provide a number: ")
    print(user_input)
    
    19 [22]
  • def make_scoreboard(frame, score=0):
        label = Label(frame)
        label.pack()
        for i in [-10, -1, 1, 10]:
            def increment(step=i):
                score = score + step  # fails with UnboundLocalError
                label['text'] = score
            button = Button(frame, text='%+d' % i, command=increment)
            button.pack()
        return label
    
    00 [22]
  • def make_scoreboard(frame, score=0):
        label = Label(frame)
        label.pack()
        for i in [-10, -1, 1, 10]:
            def increment(step=i):
                score = score + step  # fails with UnboundLocalError
                label['text'] = score
            button = Button(frame, text='%+d' % i, command=increment)
            button.pack()
        return label
    
    01 [22]
  • def make_scoreboard(frame, score=0):
        label = Label(frame)
        label.pack()
        for i in [-10, -1, 1, 10]:
            def increment(step=i):
                score = score + step  # fails with UnboundLocalError
                label['text'] = score
            button = Button(frame, text='%+d' % i, command=increment)
            button.pack()
        return label
    
    02 [22]
  • def make_scoreboard(frame, score=0):
        label = Label(frame)
        label.pack()
        for i in [-10, -1, 1, 10]:
            def increment(step=i):
                score = score + step  # fails with UnboundLocalError
                label['text'] = score
            button = Button(frame, text='%+d' % i, command=increment)
            button.pack()
        return label
    
    03 [23]
  • def make_scoreboard(frame, score=0):
        label = Label(frame)
        label.pack()
        for i in [-10, -1, 1, 10]:
            def increment(step=i):
                score = score + step  # fails with UnboundLocalError
                label['text'] = score
            button = Button(frame, text='%+d' % i, command=increment)
            button.pack()
        return label
    
    04 [25] (chỉ rõ phạm vi nào)

Các lựa chọn được thảo luận phổ biến nhất dường như là

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
05,
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 và
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07.
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
05 đã được sử dụng làm cả tên biến và tên thuộc tính trong thư viện chuẩn. Từ
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 có nghĩa trái ngược nhau, vì “biến toàn cục” thường được hiểu là một biến có phạm vi cấp cao nhất [27]. Trong C, từ khóa
def enclosing_function():
    def factorial(n):
        if n < 2:
            return 1
        return n * factorial(n - 1)  # fails with NameError
    print factorial(5)
00 có nghĩa là một tên đề cập đến một biến trong một đơn vị biên dịch khác. Mặc dù
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07 hơi dài và nghe có vẻ kém dễ chịu hơn so với một số tùy chọn khác, nhưng nó thực sự có ý nghĩa chính xác. nó khai báo một tên không cục bộ

giải pháp đề xuất

Giải pháp được đề xuất bởi PEP này là thêm một khai báo ghi đè phạm vi trong phạm vi giới thiệu (bên trong). Guido đã bày tỏ sự ưu tiên đối với danh mục giải pháp này trên Python-Dev [14] và đã thể hiện sự chấp thuận cho

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07 làm từ khóa [19]

Tuyên bố đề xuất

user_input = input(prompt_text)
0

ngăn

def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 trở thành tên địa phương trong phạm vi hiện tại. Tất cả các lần xuất hiện của
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 trong phạm vi hiện tại sẽ đề cập đến giới hạn
def get_integer_input(prompt_text):
    user_input = input(prompt_text)
    return int(user_input)

print(user_input)
56 trong phạm vi bao quanh bên ngoài. Như với
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0, nhiều tên được phép

user_input = 10

def get_integer_input(prompt_text):
    global user_input
    user_input = input(prompt_text)
    print(user_input)
    return int(user_input)

int_input = get_integer_input("Provide a number: ")
print(user_input)
1

Nếu không có ràng buộc tồn tại trước trong phạm vi kèm theo, trình biên dịch sẽ phát sinh Lỗi Cú pháp. (Có thể hơi dài dòng khi gọi đây là lỗi cú pháp, nhưng cho đến nay SyntaxError được sử dụng cho tất cả các lỗi thời gian biên dịch, bao gồm, ví dụ: __future__ nhập với tên tính năng không xác định. ) Guido đã nói rằng loại khai báo này khi không có ràng buộc bên ngoài nên được coi là một lỗi [16]

Nếu một khai báo

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07 xung đột với tên của một tham số chính thức trong phạm vi cục bộ, trình biên dịch sẽ phát sinh lỗi SyntaxError

Một hình thức tốc ký cũng được cho phép, trong đó

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07 được thêm vào trước một nhiệm vụ hoặc nhiệm vụ bổ sung

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0

Ở trên có ý nghĩa chính xác giống như

def enclosing_function():
    def factorial(n):
        if n < 2:
            return 1
        return n * factorial(n - 1)  # fails with NameError
    print factorial(5)
09. (Guido hỗ trợ một dạng tương tự của câu lệnh
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 [24]. )

Ở phía bên trái của biểu mẫu tốc ký, chỉ các mã định danh mới được phép, không phải các biểu thức đích như

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
41. Mặt khác, tất cả các hình thức chuyển nhượng được cho phép. Ngữ pháp đề xuất của câu lệnh
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07 là

def enclosing_function():
    def factorial(n):
        if n < 2:
            return 1
        return n * factorial(n - 1)  # fails with NameError
    print factorial(5)
0

Lý do cho phép tất cả các hình thức chuyển nhượng này là nó đơn giản hóa việc hiểu câu lệnh

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
07. Tách dạng tốc ký thành một khai báo và một phép gán là đủ để hiểu ý nghĩa của nó và liệu nó có hợp lệ hay không

Ghi chú

Cú pháp tốc ký không được thêm vào trong triển khai ban đầu của PEP. Các cuộc thảo luận sau đó [29] [30] đã kết luận rằng cú pháp này không nên được thực hiện

Khả năng tương thích ngược

PEP này nhắm mục tiêu Python 3000, theo đề xuất của Guido [19]. Tuy nhiên, những người khác đã lưu ý rằng một số tùy chọn được xem xét trong PEP này có thể là những thay đổi đủ nhỏ để khả thi trong Python 2. x [26], trong trường hợp này PEP này có thể được chuyển thành 2. dòng x PEP

Là thước đo (rất sơ bộ) về tác động của việc giới thiệu một từ khóa mới, đây là số lần mà một số từ khóa được đề xuất xuất hiện dưới dạng số nhận dạng trong thư viện chuẩn, theo bản quét kho lưu trữ Python SVN vào ngày 5 tháng 11 năm 2006

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
4

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 xuất hiện 214 lần dưới dạng từ khóa hiện có. Để đo tác động của việc sử dụng
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 làm từ khóa phạm vi bên ngoài, có 18 tệp trong thư viện tiêu chuẩn sẽ bị hỏng do thay đổi đó (vì một hàm khai báo một biến
def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
0 trước khi biến đó được đưa vào trong

def make_scoreboard(frame, score=0):
    label = Label(frame)
    label.pack()
    for i in [-10, -1, 1, 10]:
        def increment(step=i):
            score = score + step  # fails with UnboundLocalError
            label['text'] = score
        button = Button(frame, text='%+d' % i, command=increment)
        button.pack()
    return label
2

Người giới thiệu

[1] (1, 2)Phạm vi (là Re. Liên kết Lambda đã được giải quyết chưa?) (Rafael Bracho) https. //di sản. con trăn. org/search/hypermail/python-1994q1/0301. html[2] (1, 2)Cú pháp hàm mở rộng (Just van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2003-Tháng Hai/032764. html[3]Ngữ nghĩa đóng (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2003-Tháng 10/039214. html[4] (1, 2)Kiểm soát tốt hơn các phạm vi từ vựng lồng nhau (Almann T. hay) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng Hai/061568. html[5]PEP để kiểm soát tốt hơn phạm vi từ vựng lồng nhau (Jeremy Hylton) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng Hai/061602. html[6]PEP để kiểm soát tốt hơn phạm vi từ vựng lồng nhau (Almann T. hay) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng Hai/061603. html[7]Sử dụng và ràng buộc tên họ hàng (Phillip J. Eby) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng Hai/061636. html[8]Sử dụng và ràng buộc tên họ hàng (Steven Bethard) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng Hai/061749. html[9] (1, 2)Phạm vi từ vựng trong Python 3k (Ka-Ping Yee) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066862. html[10]Phạm vi từ vựng trong Python 3k (Greg Ewing) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066889. html[11]Phạm vi từ vựng trong Python 3k (Ka-Ping Yee) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066942. html[12]Phạm vi từ vựng trong Python 3k (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066950. html[13]Phạm vi từ vựng rõ ràng (trước PEP?) (Talin) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066978. html[14]Phạm vi từ vựng rõ ràng (trước PEP?) (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066991. html[15]Phạm vi từ vựng rõ ràng (trước PEP?) (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066995. html[16]Phạm vi từ vựng trong Python 3k (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/066968. html[17]Phạm vi từ vựng rõ ràng (trước PEP?) (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/067004. html[18] (1, 2, 3)Phạm vi từ vựng rõ ràng (tiền PEP?) (Andrew Clover) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/067007. html[19] (1, 2)Phạm vi từ vựng rõ ràng (trước PEP?) (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/067067. html[20]Phạm vi từ vựng rõ ràng (trước PEP?) (Matthew Barnes) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng 7/067221. html[21]Bánh bầu trời. một từ khóa “var” (một chủ đề bắt đầu bởi Neil Toronto) https. //thư. con trăn. org/pipermail/python-3000/2006-Tháng 10/003968. html[22] (1, 2, 3, 4, 5, 6, 7)Các lựa chọn thay thế cho ‘bên ngoài’ (Talin) https. //thư. con trăn. org/pipermail/python-3000/2006-Tháng 10/004021. html[23]Các lựa chọn thay thế cho 'bên ngoài' (Jim Jewett) https. //thư. con trăn. org/pipermail/python-3000/2006-Tháng 11/004153. html[24]Dự thảo PEP cho phạm vi bên ngoài (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-3000/2006-Tháng 11/004166. html[25]Dự thảo PEP cho phạm vi bên ngoài (Talin) https. //thư. con trăn. org/pipermail/python-3000/2006-Tháng 11/004190. html[26]Dự thảo PEP cho phạm vi bên ngoài (Nick Coghlan) https. //thư. con trăn. org/pipermail/python-3000/2006-Tháng 11/004237. html[27]Biến toàn cầu (phiên bản 2006-11-01T01. 23. 16) http. // vi. wikipedia. org/wiki/Global_variable[28]Ruby 2. 0 chặn biến cục bộ http. //thuận tay. hobix. com/inspect/ruby20BlockLocalVariable. html[29]Số 4199. kết hợp chuyển nhượng với toàn cầu và không cục bộ (Guido van Rossum) https. //thư. con trăn. org/pipermail/python-dev/2013-tháng 6/127142. html[30]Điều gì đã xảy ra với 'nonlocal x = y'? . //thư. con trăn. org/pipermail/python-dev/2018-tháng 1/151627. html[31]Sử dụng và ràng buộc tên họ hàng (Almann T. hay) https. //thư. con trăn. org/pipermail/python-dev/2006-Tháng Hai/061761. html

Sự nhìn nhận

Các ý tưởng và đề xuất được đề cập trong PEP này được thu thập từ vô số bài đăng Python-Dev. Cảm ơn Jim Jewett, Mike Orr, Jason Orendorff và Christian Tanzer đã đề xuất các chỉnh sửa cụ thể cho PEP này

Tên bóng có nghĩa là gì trong Python?

Việc sử dụng lại tên trong và ngoài chức năng sẽ được gọi là "tên ẩn" trong PyCharm, do đó gây ra "Tên ẩn từ phạm vi bên ngoài". Đây chỉ là một cảnh báo và không làm cho mã của bạn không chạy được. 01-Mar-2021.

Làm thế nào một biến toàn cầu có thể được che khuất?

Trong JavaScript, các biến có thể được ẩn trong cả phạm vi hàm và toàn cục. Các biến toàn cục có thể bị che khuất bởi các biến phạm vi hàm và các biến phạm vi chức năng có thể bị che khuất bởi các biến phạm vi khối được khai báo bằng từ khóa let hoặc const.

phạm vi biến bối cảnh biến đổ bóng là gì?

Trong lập trình máy tính, ẩn biến xảy ra khi một biến được khai báo trong một phạm vi nhất định (khối quyết định, phương thức hoặc lớp bên trong) có cùng tên với một biến được khai báo trong lớp bên ngoài. . Ở cấp độ định danh (tên, thay vì biến), điều này được gọi là mặt nạ tên. . At the level of identifiers (names, rather than variables), this is known as name masking.