Phạm vi của một biến được khởi tạo trong câu lệnh if là gì?


266

Tôi chưa quen với Python, vì vậy đây có lẽ là một câu hỏi đơn giản. Đoạn mã sau trong tệp Python (mô-đun) làm tôi hơi bối rối:

if __name__ == '__main__':
    x = 1

print x

Trong các ngôn ngữ khác mà tôi đã làm việc, mã này sẽ đưa ra một ngoại lệ, vì xbiến này là cục bộ của ifcâu lệnh và không nên tồn tại bên ngoài nó. Nhưng mã này thực thi và in 1. Có ai có thể giải thích hành vi này không? Có phải tất cả các biến được tạo trong một mô-đun toàn cầu / có sẵn cho toàn bộ mô-đun?


17
Những đứa khác, bạn có thể không nhận thức được: nếu iftuyên bố trên không giữ đúng (ví dụ, __name__không '__main__' , ví dụ như khi bạn nhập các module thay vì thực hiện nó cấp cao nhất), sau đó xsẽ không bao giờ bị ràng buộc, và sau đó print xtuyên bố sẽ ném a NameError: name 'x' is not defined.
Santa

Câu trả lời:


302

Các biến Python được đặt trong phạm vi hàm, lớp hoặc mô-đun trong cùng mà chúng được gán. Các khối điều khiển như ifwhilecác khối không được tính, do đó, một biến được gán bên trong ifvẫn nằm trong phạm vi của một hàm, lớp hoặc mô-đun.

(Chức năng Implicit xác định bởi một biểu hiện phát hoặc danh sách / bộ / dict hiểu làm đếm, cũng như lambda biểu thức. Bạn không thể nhét một câu lệnh gán vào bất kỳ của những người, nhưng thông số lambda và forcác mục tiêu quy định tại khoản là nhiệm vụ ngầm.)



105

Có, chúng nằm trong cùng "phạm vi cục bộ" và thực tế mã như thế này là phổ biến trong Python:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

Lưu ý rằng xkhông được khai báo hoặc khởi tạo trước điều kiện, chẳng hạn như trong C hoặc Java chẳng hạn.

Nói cách khác, Python không có phạm vi cấp khối. Tuy nhiên, hãy cẩn thận với các ví dụ như

if False:
    x = 3
print(x)

mà rõ ràng sẽ đưa ra một NameErrorngoại lệ.


42

Phạm vi trong python theo thứ tự này:

  • Tìm kiếm phạm vi địa phương

  • Tìm kiếm phạm vi của bất kỳ chức năng kèm theo

  • Tìm kiếm phạm vi toàn cầu

  • Tìm kiếm tích hợp

( nguồn )

Lưu ý rằng ifvà các cấu trúc lặp / phân nhánh khác không được liệt kê - chỉ các lớp, hàm và mô-đun cung cấp phạm vi trong Python, vì vậy mọi thứ được khai báo trong một ifkhối đều có cùng phạm vi như mọi thứ được khai báo bên ngoài khối. Các biến không được kiểm tra tại thời điểm biên dịch, đó là lý do tại sao các ngôn ngữ khác đưa ra một ngoại lệ. Trong python, miễn là biến tồn tại vào thời điểm bạn yêu cầu, sẽ không có ngoại lệ nào được ném ra.


9

Như Eli đã nói, Python không yêu cầu khai báo biến. Trong C bạn sẽ nói:

int x;
if(something)
    x = 1;
else
    x = 2;

nhưng trong khai báo Python là ẩn, vì vậy khi bạn gán cho x, nó sẽ tự động được khai báo. Đó là vì Python được gõ động - nó sẽ không hoạt động trong ngôn ngữ được nhập tĩnh, bởi vì tùy thuộc vào đường dẫn được sử dụng, một biến có thể được sử dụng mà không được khai báo. Điều này sẽ được bắt gặp tại thời điểm biên dịch bằng ngôn ngữ gõ tĩnh, nhưng với ngôn ngữ được gõ động, nó được phép.

Lý do duy nhất khiến một ngôn ngữ gõ tĩnh bị giới hạn là phải khai báo các biến bên ngoài các ifcâu lệnh vì vấn đề này. Nắm bắt sự năng động!


9

Không giống như các ngôn ngữ như C, một biến Python nằm trong phạm vi cho toàn bộ hàm (hoặc lớp hoặc mô-đun) nơi nó xuất hiện, không chỉ trong "khối" trong cùng. Như thể bạn đã khai báo int xở đầu hàm (hoặc lớp hoặc mô-đun), ngoại trừ trong Python bạn không phải khai báo biến.

Lưu ý rằng sự tồn tại của biến xchỉ được kiểm tra khi chạy - nghĩa là khi bạn nhận được print xcâu lệnh. Nếu __name__không bằng nhau "__main__"thì bạn sẽ có một ngoại lệ : NameError: name 'x' is not defined.


Các lớp học không tạo ra một phạm vi; một biến "cục bộ" trong một lớp chỉ đơn giản được thêm vào chính tả của lớp khi tạo.
chepner

3

Đúng. Nó cũng đúng với forphạm vi. Nhưng tất nhiên không phải chức năng.

Trong ví dụ của bạn: nếu điều kiện trong ifcâu lệnh là sai, xsẽ không được xác định mặc dù.


2

bạn đang thực thi mã này từ dòng lệnh do đó ifđiều kiện là đúng và xđược đặt. Đối chiếu:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined

0

Và lưu ý rằng vì các loại Python chỉ được kiểm tra trong thời gian chạy, bạn có thể có mã như:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

Nhưng tôi gặp khó khăn khi nghĩ về các cách khác mà mã sẽ hoạt động mà không có lỗi do các vấn đề về loại.

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.