Ngôn ngữ Python ( Chương VIII. Các kỹ thuật đặc biệt trong Python)

VIII. Các k thut đc bit trong Python:
1. Qun lí li:
        Trong phn này, s tìm hiu v các cơ chế qun lí li trong Python. Bao gm các li cú pháp và cơ chế dùng ngoi l (exception).
a. Li cú pháp:
        Bn cht là li phân tích t trong Python, đây có l là li ph biến nht ca nhng người mi hc lp trình Python. Mt ví d li đơn gin:
 
>>> while True print 'Hello world'
  File "<stdin>", line 1, in ?
    while True print 'Hello world'
                   ^
SyntaxError: invalid syntax
        Vic phân tích lp li trên các dòng mc li và hin th mt con tr đu tiên ti v trí li được dò ra (kiu tương t như pascal). Li gây ra (được dò thy đu tiên) có du hiu con trỏở trước, như trong ví d trên, li dò thy là ti t khóa print, vì nó thiếu du hai chm (“:”) trước. Tên file và s dòng cũng được in ra đ có th biết chính xác trong trường hp đu vào là mt script.

b. Các ngoi l (Exception):
        Mc dù mt câu lnh hoc mt biu thc là chính xác v cú pháp nhưng nó vn có th gây ra li khi chy nó. Các li dò được trong quá trình thc hin được gi là các ngoi l (exception) và không th tránh khi tuyt đi các li này. Phn sau, s tiếp tc nghiên cu v cách điu khin nó trong Python. Hu hết các ngoi l đu không điu khin được bi chương trình, tuy nhiên các có th ch ra các thông báo li:
>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
          Dòng  cuối cùng của thông báo lỗi cho biết chuyện gì đã xảy ra. Các ngoại lệ có nhiều kiểu khác nhau, và các kiểu này được in ở cuối thông báo lỗi. Trong ví dụ trên là:ZeroDivisionError, NameErrorTypeError.  Các xâu in ra là các kiểu ngoại lệ và tên của các ngoại lệ được xây dựng sẵn đưa ra. Điều này là được áp dụng cho tất cả các ngoại lệ cài sẵn, nhưng không áp dụng cho các ngoại lệ người sử dụng tự định nghĩa. Các tên ngoại lệ chuẩn các định danh có sẵn (không trùng với các từ khóa dành riêng).
          Phần còn lại của thông báo cung cấp chi tiết dựa trên kiểu của ngoại lệ và nguyên nhân gây ra lỗi. Phần đặt trước thông báo lỗi chỉ ra ngữ cảnh ngoại lệ đó xảy ra, theo cơ chế dò lùi kiểu ngăn xếp. Tóm lại, nó chứa một danh sách các dòng nguồn, tuy nhiên có sẽ không hiển thị các dòng đọc từ đầu vào chuẩn.
c. Điều khiển các ngoại lệ:
          Có thể viết các chương trình để điều khiển các ngoại lệ nào đó, Xem xét ví dụ dưới đây, yêu cầu người sử dụng nhập vào dữ liệu cho đến khi là số nguyên, nhưng cho phép người sử dụng ngắt chương trình (sử dụng CTRL + C hoặc tương tự do hệ điều hành hỗ trợ). Chú ý rằng các ngắt do người sử dụng tạo ra được nhận dạng bởi các ngoại lệ do ngắt bàn phím (KeyboardInterrupt exeption)
>>> while True:
...     try:
...         x = int(raw_input("Please enter a number: "))
...         break
...     except ValueError:
...         print "Oops!  That was no valid number.  Try again..."
...
Câu lệnh try hoạt động như sau:
  • Đu tiên, mnh đ try (câu lnh gia try và t khóa except được thc hin).
  • Nếu không có ngoi l nào xy ra, mnh đ except được b qua và tiếp tc thc hin try cho đến khi kết thúc.
  • Nếu có mt ngoi l xy ra trong khi đang thc hin mnh đ try thì phn còn li ca mnh đ s b b qua. Sau đó nếu như loi li đó mà tương ng vi tên ca ngoi l được đt sau t khóa except thì mnh đ except s được thc hin, và sau đó tiếp tc thc hin cho đến hết câu lnh try.
  • Nếu mt ngoi l xy ra mà không tương ng vi ngoi l đã được đt sau mnh đ except thì nó s b qua thoát ra khi câu lnh try. Nếu không có điu khin nào được tìn thy, thì đó mt ngoi l không điu khin và quá trình thc hin kết thúc vi mt thông báo như đã ch ra trên.
          Một câu lệnh try có thể có nhiều hơn một mệnh đề except, để xác định các điểu khiển cho các ngoại lệ khác nhau. Toàn bộ một điều khiển sẽ được thực hiện. Các điều khiển chỉ điều khiển các ngoại lệ xảy ra tương ứng với mệnh đề try. Một mệnh đề except có thể cỏ nhiều ngoại lệ theo sau được đặt trong dấu ngoặc đơn như một bộ, ví dụ:
... except (RuntimeError, TypeError, NameError):
...     pass
          Mệnh đề excpet cuối cùng có thể bỏ qua tên của ngoại lệ, để đáp ứng như một kí tự đại diện. Sử dụng điều này phải hết sức cẩn thận, bởi vì rất dễ bỏ qua một lỗi chương trình thực sự. Nó cũng có thể được sử dụng để in ra một thông báo lỗi và sau đó tái đề xuất ngoại lệ đó:
import sys
 
try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError, (errno, strerror):
    print "I/O error(%s): %s" % (errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
          Câu lệnh try… except có một mệnh đề else mở rộng, nó được xuất hiện sau tất cả các mệnh đề except. Nó được sử dụng để viết các đoạn mã mà chỉ thi hành khi mệnh đề try không gây ra một ngoại lệ nào. Ví dụ:
for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()
          Sử dụng mệnh đề else giúp ngăn ngừa được các ngoaik lệ gây ra bởi đoạn code nằm trong try…
          Khi một ngoại lệ xảy ra, nó có thể có một giá trị liên quan, được gọi là đối số của ngoại lệ. Cách biểu diễn và kiểu của đối số đó phụ thuộc vào kiểu ngoại lệ. Mệnh đề except có thể xác định một biến theo sau tên ngoại lệ. Biến đó được gắn với một trường hợp ngoại lệ với các đối số được lưu trong instance.args. Để thuận tiện, trường hợp ngoại lệ đó định nghĩa __getitem__and__str__vì thế các đối số đó có thể được truy nhập hoặc đưa ra trực tiếp không cần tham chiếu .args
>>> try:
...    raise Exception('spam', 'eggs')
... except Exception, inst:
...    print type(inst)     # the exception instance
...    print inst.args      # arguments stored in .args
...    print inst           # __str__ allows args to printed directly
...    x, y = inst          # __getitem__ allows args to be unpacked directly
...    print 'x =', x
...    print 'y =', y
...
<type 'instance'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
 
            Nếu một ngoại lệ có một đối số, nó được đưa ra như phần cuối cùng của một thông báo cho các ngoại lệ không điều khiển.
            Các điều khiển ngoại lệ không chỉ điều khiển các ngoại lệ xảy ra ngay lập tức trong mệnh đề try, mà còn cho cả các lỗi xảy ra trong các hàm mà được gọi trong mệnh đề try. Ví dụ:
>>> def this_fails():
...     x = 1/0
... 
>>> try:
...     this_fails()
... except ZeroDivisionError, detail:
...     print 'Handling run-time error:', detail
... 
Handling run-time error: integer division or modulo by zero

d. Đưa ra các ngoi l:

          Câu lệnh raise cho phép người lập trình tác động đến một ngoại lệ xác định để cho nó xảy ra. Ví dụ:
>>> raise NameError, 'HiThere'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: HiThere
          Đối số đầu tiên tạo ra các tên ngoại lệ sẽ được sinh ra. Đối số thứ hai xác định đối số của ngoại lệ đó. Một cách thay thế khác, câu lệnh ở trên có thể được viết lại. Nếu cần xác định một ngoại lệ được đưa ra nhưng không có ý định điều khiển nó, một dạng đơn giản của câu lệnh raise cho phép tái đưa ra một ngoại lệ:
>>> try:
...     raise NameError, 'HiThere'
... except NameError:
...     print 'An exception flew by!'
...     raise
...
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

e. Các ngoi l do người s dng đnh nghĩa:

          Các chương trình có th đt tên ngoi l ca chúng bng cách to ra mt lp ngoi l mi. Các ngoi l thông thường được tha kế t lp Exception, hoc là kế tha trc tiếp hoc không trc tiếp. Ví d:

      >>> class MyError(Exception):
...     def __init__(self, value):
...         self.value = value
...     def __str__(self):
...         return repr(self.value)
... 
>>> try:
...     raise MyError(2*2)
... except MyError, e:
...     print 'My exception occurred, value:', e.value
... 
My exception occurred, value: 4
>>> raise MyError, 'oops!'
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'
            Trong ví dụ này, phương thức mặc định __init__ của lớp Exception bị ghi chèn lên. Một thuộc tính giá trị mới được tạo ra, nó sẽ thay thế cách thức mặc định tạo ra thuộc tính args.
          Các lớp ngoại lệ có thể được định nghĩa để làm bất cứ điều gì như các lớp thông thường, nhưng thường là nó được xây dựng rất đơn giản, nó chỉ đưa ra một số các thuộc tính thông tin về các lỗi được lấy ra từ bởi các điều khiển đối với các ngoại lệ. Khi tạo ra một module mà có thể gây ra một vài lỗi phân biệt, một thói quen phổ biến là tạo ra một lớp cơ sở cho các ngoại lệ được định nghĩa bởi module đó, và lướp con để tạo ra các lớp ngoại lệ cụ thể cho các điều kiện lỗi khác nhau:
class Error(Exception):
    """Base class for exceptions in this module."""
    pass
 
class InputError(Error):
    """Exception raised for errors in the input.
 
    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """
 
    def __init__(self, expression, message):
        self.expression = expression
        self.message = message
 
class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.
 
    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """
 
    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message
 
          Hầu hết các ngoại lệ do người sử dụng tạo ra được định nghĩa với các tên mà kết thúc là ‘Error’ giống với tên của các ngoại lệ chuẩn.
          Nhiều module chuẩn định nghĩa các ngoại lệ của riêng nó để thông báo các lỗi có thể xảy ra trong các hàm mà chúng định nghĩa. 
 
2. Quản lí bộ nhớ:
            Pyhton có một cơ chế tự động quản lý bộ nhớ (đếm số lần tham chiếu của hầu hết các đối tượng và tập hợp không hợp lệ để loại trừ chúng theo chu kì). Bộ nhớ sẽ được giải phóng ngay sau khi tham chiếu cuối cùng tới nó được loại bỏ.
 

No comments:

Post a Comment

Bài đăng mới: