VII. Phạm vi (scope) và
không gian tên (name space) trong Python
Trong Python sử dụng một tinh xảo phạm vi và không gian tên đối
với các đối tượng của nó, để có thể hiểu đầy đủ về các kiểu
cách đó, ta cần tìm hiểu về phạm vi và không gian tên.
1. Không gian tên:
Một không gian tên là một ánh xạ từ các
tên đến các đối tượng, Hầu hết các không gian tên là được cung cấp như các
từ điển Python, nhưng thông thường nó không được thông báo theo bất
kì cách nào, và nó cũng có thể thay đổi trong tương lai. Ví dụ của
không gian tên là: tập hợp các tên xây dựng sẵn, các tên toàn cục trong một
module, các tên cục bộ trong một đăng kí hàm. Trong trường hợp nhạy cảm,
tập các thuộc tính của một đối tượng cũng là một không gian tên. Điều quan
trọng đối với không gian tên là không hề có sự liên hệ giữa
các tên trong các khong gian tên giống nhau, ví dụ có 2 module khác nhau
cùng định nghĩa một tên giống nhau thì không có gì khó khăn để sử dụng
phân biệt 2 tên đó khi ta thêm tên của module vào đầu các tên đó.
Bằng
cách như vậy ta sử dụng từ attribute cho bất cứ tên nào theo sau một
dấu chấm. Ví dụ, trong biểu thức z.real, real là một thuộc tính của đối tượng
z. Nói đúng ra, tham chiếu đến các tên trong các module là tham chiếu thuộc
tính: sử dụng biểu thức modname.funcname, trong đó modname là tên của một đối
tượng module, còn funcname là một thuộc tính của nó. Trong trường hợp này có
một ánh xạ trực tiếp từ các thuộc tính của module và các tên toàn cục được định
nghĩa trong module: chúng chia sẻ trong cùng một module.
Các thuộc tính có
thể chỉ đọc hoặc có thể ghi. Trong trường hợp có thể ghi, cần phải đăng kí
thuộc tính, các thuộc tính module có thể ghi, ta có thể viết "modname.the_answer
= 42". Các thuộc tính có thể ghi cũng có thể được loại bỏ với câu lệnh
del. Ví dụ, "del modname.the_answer" sẽ loại bỏ thuộc tính
the_answer từ đối tượng có tên là modname
Không
gian tên tao ra tại các thời điểm khác nhau và có thời gian tồn tại cũng khác
nhau. Không gian tên chứa các tên xây dựng sẵn được tạo ra khi trình thông
dịch Python bắt đầu chạy và không bao giờ bị xóa đi. Không gian tên toàn
cục do một module tạo ra khi định nghĩa module đó được đọc, thông thường không
gian tên của module cũng tồn tại đến khi trình thông dịch kết thúc. Các câu
lệnh thực hiện với yêu cầu cao nhất của trình thông dịch, hoặc đọc từ một file
script hoặc tương tác với người sử dụng, được xem như là thành
phần của một module gọi là __main__, vì thế chúng có một không gian tên toàn
cục riêng (Các tên được xây dựng sẵn thực tế nằm trong một module, gọi là
__builtin__)
Các
không gian tên cục bộ của một hàm được tạo ra khi hàm đó được gọi, và bị xóa
khi hàm đó trả về hoặc đưa ra một trường hợp mà không được điều khiển trong hàm
đó. Tất nhiên các yêu cầu đệ qui cũng có không gian tên cục bộ của riêng
nó.
2. Phạm vi
Một
phạm vi là một vùng có liên quan trong một chương trình Python trong
đó một không gian tên được truy nhập một cách trực tiếp. Truy nhập trực
tiếp ở đây được hiểu là tham chiếu tuyệt đối đến một tên cố gắng tìm tên đó
trong không gian tên.
Mặc
dù các phamjv i được định nghĩa một cách cố định, nhưng chúng được sử dụng rất
linh hoạt. Tại bất kì một thời điểm nào trong quá trình thực hiện, có ít
nhất 3 phạm vi lồng nhau mà không gian tên của nó được truy nhập trực
tiếp:
· Phạm vi trong cùng nhất được tìm kiếm đầu tiên
chứa các tên cục bộ; không gian tên đó kết thúc khi bất kì hàm nào được kết
thúc
· Phạm vi ở giữa, được tìm tiếp theo, chứa các
tên toàn cục của module hiện tại
· Và phạm vi ngoài cùng, được tìm cuối
cùng là chứa các không gian tên được xây dựng sẵn.
Nếu
một tên được khai báo là toàn cục, thì tất cả các tham chiếu và đăng kí đều tìm
trực tiếp vào không gian tên ở giữa (mức 2) chứa các tên toàn cục của module
đó.
Thông
thường, phạm vi cục bộ tham chiếu đến các tên của hàm hiện thời
(trong phạm vi đó). Các hàm bên ngoài, phạm vi cục bộ tham chiếu đến
các tên tương tự như phạm vi toàn cục: không gian tên của module đó. Các định
nghĩa lớp lúc này đặt một không gian tên khác trong phạm vi cục bộ.
Cũng
rất quan trọng để nhận ra các phạm vi: phạm vi toàn cục của một hàm được
định nghĩa trong một module là không gian tên của module đó. Mặt khác,
việc tìm kiếm các tên được thực hiện rất linh động.
Một
điều đặc biệt của Python là việc đăng kí luôn luôn ở trong phạm vi trong
cùng nhất. Việc đăng kí đó không sao chép dữ liệu mà chúng chỉ gắn các
tên cho các đối tượng. Vì thế câu lệnh “del x” thực chất chỉ loại bỏ tên
được gắn cho x từ không gian tên được tham chiếu bởi phạm vi cục bộ.
3. Các biến với phạm vi của nó trong
Python
Các biến trong Python
được tự động khai báo bằng cách đăng kí. Các biến luôn luôn tham chiếu đến
các đối tượng và không bảo giờ cần phải định kiểu. Các biến chỉ tồn tại
trong phạm vi hiện thời hoặc phạm vi tonaf cục. Khi ra khỏi phạm vi đó,
các biến sẽ bị phá hủy, nhưng các đối tượng mà chúng tham chiếu thì không
Phạm vi được chỉ ra bởi các khối hàm và lớp. Cả các hàm và
các phạm vi của chúng có thể lồng nhau, Vì thế:
def foo():
def bar():
x = 5 # x is now in scope
return x
+ y # y is defined in the enclosing scope later
y = 10
return bar()
# now that y is defined, bar's scope includes y
Chạy thử đoạn mã
này
>>> foo()
15
>>> bar()
Traceback (most recent
call last):
File
"<pyshell#26>", line 1, in -toplevelbar()
NameError: name 'bar' is
not defined
Tên
‘bar’ không được tìm thấy bởi vì phạm vì cao hơn của nó không được truy nhập đến
phạm vi thấp hơn trong thứ bậc đó. Đây cũng là một lỗi phổ biến
làm hỏng các tìm kiến một thuộc tính (cũng như một phương thức) của một đối
tượng (hay một cái chứa nó) được tham chiếu bởi một biến trước khi biến đó được
đăng kí với đối tượng. Ví dụ:
>>> for x
in range(10):
y.append(x) # append is an attribute of lists
Traceback (most recent call last):
File
"<pyshell#46>", line 2, in -toplevely.
append(x)
NameError: name 'y' is not defined
Ở đây, để chính xác phải
có thêm y=[] trước vòng lặp.
Hãy like nếu bài viết có ích →
Kết bạn với gisgpsrs trên Facebook
để nhận bài viết mới nóng hổi
Không có nhận xét nào:
Đăng nhận xét