Không có câu trả lời kỹ lưỡng về thời gian Python3, vì vậy tôi đã trả lời ở đây.
Như được cung cấp trong các câu trả lời khác, có 4 phạm vi cơ bản, LEGB, cho Địa phương, Bao vây, Toàn cầu và được xây dựng. Ngoài ra, có một phạm vi đặc biệt, cơ thể lớp , không bao gồm phạm vi bao quanh cho các phương thức được xác định trong lớp; bất kỳ bài tập nào trong cơ thể lớp làm cho biến từ đó bị ràng buộc trong thân lớp.
Đặc biệt, không có tuyên bố chặn, bên cạnh def
và class
, tạo phạm vi thay đổi. Trong Python 2 việc hiểu danh sách không tạo ra một phạm vi biến đổi, tuy nhiên trong Python 3 biến vòng lặp được tạo ra trong một phạm vi mới.
Để chứng minh tính chất riêng của cơ thể lớp
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
Như vậy không giống như trong cơ quan chức năng, bạn có thể gán biến cùng tên trong cơ thể lớp, để có được một biến lớp học có cùng tên; tìm kiếm thêm về tên này sẽ giải quyết thay vì đối với biến lớp.
Một trong những bất ngờ lớn hơn đối với nhiều người mới đến Python là vòng lặp for
không tạo ra phạm vi thay đổi. Trong Python 2, việc hiểu danh sách không tạo ra một phạm vi (hoặc trong khi các trình tạo và đọc hiểu dict làm!) Thay vào đó họ bị rò rỉ giá trị trong hàm hoặc phạm vi toàn cầu:
>>> [ i for i in range(5) ]
>>> i
4
Các comprehensions có thể được sử dụng như một xảo quyệt (hoặc khủng khiếp nếu bạn sẽ) cách để làm cho các biến thể thay đổi được trong biểu thức lambda bằng Python 2 - một lambda biểu thức không tạo ra một phạm vi biến, như tuyên bố def
sẽ, nhưng trong lambda không có câu lệnh nào được cho phép. Việc gán là một câu lệnh trong Python có nghĩa là không có phép gán biến nào trong lambda được cho phép, nhưng việc hiểu danh sách là một biểu thức ...
Hành vi này đã được sửa trong Python 3 - không có biểu thức hiểu hoặc biến rò máy phát.
Toàn cầu thực sự có nghĩa là phạm vi mô-đun; mô đun python chính là __main__
; tất cả các mô-đun đã nhập có thể truy cập được thông qua biến số sys.modules
; để có quyền truy cập vào __main__
, bạn có thể sử dụng sys.modules['__main__']
hoặc import __main__
; nó là hoàn toàn chấp nhận được để truy cập và gán các thuộc tính ở đó; chúng sẽ hiển thị dưới dạng các biến trong phạm vi toàn cầu của mô-đun chính.
Nếu một tên được bao giờ giao cho trong phạm vi hiện tại (trừ trong phạm vi lớp), nó sẽ được coi là thuộc phạm vi đó, nếu không nó sẽ được coi là thuộc về bất kỳ phạm vi kèm theo đó gán vào biến (nó có thể chưa được gán, hoặc hoàn toàn không), hoặc cuối cùng là phạm vi toàn cục. Nếu biến được coi là cục bộ, nhưng biến chưa được đặt hoặc đã bị xóa, việc đọc giá trị biến sẽ dẫn đến UnboundLocalError
, là lớp con của NameError
.
x = 5
def foobar()
print(x) # UnboundLocalError!
x += 1 # assignment here makes x a local variable!
Phạm vi có thể tuyên bố rằng nó một cách rõ ràng muốn sửa đổi các biến toàn cầu (phạm vi mô-đun), với từ khóa toàn cầu:
x = 5
def foobar():
global x
print(x) # -> 5
x += 1
foobar()
print(x) # -> 6
này cũng có thể ngay cả khi nó đã được che phủ trong kèm theo phạm vi:
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> print 5 911
print(x, y) # -> 6 13
Trong python 2 không có cách nào dễ dàng để sửa đổi giá trị trong phạm vi kèm theo; thường này được mô phỏng bằng cách có một giá trị có thể thay đổi, chẳng hạn như một danh sách với chiều dài 1:
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
Tuy nhiên trong python 3, nonlocal
đến để giải thoát:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
Bất kỳ biến mà không được coi là cục bộ với phạm vi hiện tại, hoặc bất kỳ phạm vi kèm theo nào, là một biến toàn cầu. Một tên toàn cục được tra cứu trong từ điển toàn cục của mô-đun; nếu không tìm thấy, toàn cầu sau đó được tra cứu từ mô đun nội trang; tên của mô-đun đã được thay đổi từ python 2 thành python 3; trong python 2 nó là __builtin__
và trong python 3 nó bây giờ được gọi là builtins
. Nếu bạn gán cho một thuộc tính của mô đun nội trang, nó sẽ được hiển thị sau đó cho bất kỳ mô-đun nào dưới dạng một biến toàn cầu có thể đọc được, trừ khi mô-đun đó che chúng bằng biến toàn cục của chính nó có cùng tên.
Đọc mô đun dựng sẵn cũng có thể hữu ích; giả sử bạn muốn hàm in kiểu python 3 trong một số phần của tệp, nhưng các phần khác của tệp vẫn sử dụng câu lệnh print
, nếu phiên bản python của bạn là> = 2.6, bạn có thể nhận được các chức năng phong cách mới như:
import __builtin__
print3 = __builtin__.__dict__['print']
Các from __future__ import print_function
thực sự không nhập print
chức năng bất cứ nơi nào trong Python 2 - thay vào đó nó chỉ vô hiệu hóa các quy tắc phân tích cú pháp cho print
tuyên bố trong các mô-đun hiện, xử lý print
như bất kỳ biến số nhận dạng biến nào khác, và do đó cho phép hàm print
tra cứu trong nội trang dựng sẵn.
người có thể ngừng làm ít "chỉnh sửa nghiệp" cho câu hỏi này xin vui lòng? –
Chúng không phải là tất cả "chỉnh sửa nghiệp". Một số là vì mọi người không hiểu cách mọi thứ hoạt động. Xem [** _ Câu hỏi có nên bao gồm “thẻ” trong tiêu đề của chúng không? _ **] (https://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles). – martineau