Kiến trúc lập trình Python - Phần 7

vào lúc 21:59
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