Lớp thêm một ít cú pháp mới, ba kiểu đối tượng mới, và một ít ngữ nghĩa mới.
9.3.1 Cú pháp định nghĩa lớp
Kiểu đơn giản nhất của việc định nghĩa lớp nhìn giống như:
class ClassName:
<statement-1>
. . .
<statement-N>
Định nghĩa lớp, cũng như định nghĩa hàm (câu lệnhdef ) phải được thực thi trước khi chúng có hiệu lực. (Bạn có thể đặt một định nghĩa hàm trong một nhánh của lệnh if , hoặc trong một hàm.)
Trong thực tế, các câu lệnh trong một định nghĩa lớp thường là định nghĩa hàm, nhưng các câu lệnh khác cũng được cho phép, và đôi khi rất hữu dụng. Các định nghĩa hàm trong một lớp thường có một dạng danh sách thông số lạ, vì phải tuân theo cách gọi phương thức.
Khi gặp phải một định nghĩa lớp, một vùng tên mới được tạo ra, và được dùng như là phạm vi nội bộ -- do đó, mọi phép gán vào các biến nội bộ đi vào vùng tên này. Đặc biệt, các định nghĩa hàm buộc tên của hàm mới ở đây.
Khi rời khỏi một định nghĩa lớp một cách bình thường, một đối tượng lớp được tạo ra.
Đây cơ bản là một bộ gói (wrapper) của nội dung của vùng tên tạo ra bởi định nghĩa lớp. Phạm vi nội bộ ban đấu (trước khi vào định nghĩa lớp) được thiết lập lại, và đối tượng lớp được buộc vào đây qua tên lớp đã chỉ định ở định nghĩa lớp, (ClassName trong ví dụ này).
9. Lớp http://www.vithon.org/tutorial/2.5/node11.html
9.3.2 Đối tượng lớp
Các đối tượng lớp hỗ trợ hai loại tác vụ: tham chiếu thuộc tính và tạo trường hợp (instantiation).
Tham chiếu thuộc tính dùng cú pháp chuẩn được dùng cho mọi tham chiếu thuộc tính trong Python: obj.name. Các tên thuộc tính hợp lệ gồm mọi tên trong vùng tên của lớp khi đối tượng lớp được tạo ra. Do đó, nếu định nghĩa lớp có dạng như sau:
class MyClass:
"A simple example class"
i = 12345 def f(self):
return 'hello world'
thì MyClass.i và MyClass.f là những tham chiếu thuộc tính hợp lệ, trả về một số nguyên và một đối tượng hàm, theo thứ tự đó. Các thuộc tính lớp cũng có thể gán vào, cho nên bạn có thể thay đổi giá trị của MyClass.i bằng phép gán. __doc__ cũng là một thuộc tính hợp lệ, trả về chuỗi tài liệu của lớp: "A simple example class".
Class instantiation (tạo trường hợp lớp) dùng cùng cách viết như gọi hàm. Hãy tưởng tượng một đối tượng lớp là một hàm không thông số trả về một trường hợp của lớp. Ví dụ (với lớp trên):
x = MyClass()
tạo một trường hợp mới của lớp và gán đối tượng này vào biến nội bộ x.
Tác vụ tạo trường hợp (``gọi'' một đối tượng lớp) tạo một đối tượng rỗng. Nhiều lớp thích tạo đối tượng với các trường hợp được khởi tạo ở một trạng thái đấu nào đó. Do đó một lớp có thể định nghĩa một phương thức đặc biệt tên __init__(), như sau:
def __init__(self):
self.data = []
Khi một lớp định nghĩa một phương thức __init__() , việc tạo trường hợp lớp sẽ tự động gọi __init__() ở trường hợp lớp mới vừa được tạo. Trong ví dụ nạy, một trường hợp đã khởi tạo mới có thể được tại ra từ:
x = MyClass()
Dĩ nhiên, __init__() (phương thức) có thể nhận thêm thông số. Trong trường hợp đó, các thông số đưa vào phép tạo trường hợp lớp sẽ được truyền vào __init__(). Ví dụ,
>>> class Complex:
... def __init__(self, realpart, imagpart):
... self.r = realpart ... self.i = imagpart ... >>> x = Complex(3.0, -4.5)
>>> x.r, x.i (3.0, -4.5)
9.3.3 Đối tượng trường hợp
9. Lớp http://www.vithon.org/tutorial/2.5/node11.html
Chúng ta có thể làm được gì với những đối tượng trường hợp? Tác vụ duy nhất mà các đối tượng trường hợp hiểu được là tham chiếu thuộc tính. Có hai loại tên thuộc tính hợp lệ, thuộc tính dữ liệu và phương thức.
data attributes (thuộc tính dữ liệu lớp) tương ứng với ``biến trường hợp'' trong
Smalltalk, và ''thành viên dữ liệu'' trong C++. Thuộc tính dữ liệu không cấn được khai báo; như các biến nội bộ, chúng tự động tồn tại khi được gán vào. Ví dụ, nếu x là một trường hợp của MyClass được tạo ra ở trên, đoạn mã sau in ra giá trị 16, mà không chừa lại dấu vết:
x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2 print x.counter
del x.counter
Loại tham chiếu thuộc tính trường hợp khác là một method (phương thức). Một phương thức là một hàm ``của'' một đối tượng. (Trong Python, từ phương thức không chỉ riêng cho trường hợp lớp: các kiểu đối tượng khác cũng có thể có phương thức. Ví dụ, đối tượng danh sách có phương thức tên append, insert, remove, sort, v.v... Tuy nhiên, trong phấn sau chúng ta sẽ chỉ dùng từ phương thức dể chỉ các phương thức của đối tượng trường hợp lớp, trừ khi được chỉ định khác đi.)
Các tên phương thức hợp lệ của một đối tượng trường hợp phụ thuộc vào lớp của nó.
Theo định nghĩa, mọi thuộc tính của một lớp mà là những đối tượng hàm định nghĩa các phương thức tương ứng của các trường hợp của lớp đó. Trong ví dụ của chúng ta, x.f là một tham chiếu phương thức hợp lệ, vì MyClass.f là một hàm, nhưng x.i không phải, bởi vì MyClass.i không phải. Nhưng x.f không phải là một thứ như MyClass.f -- nó là một method object (đối tượng phương thức), không phải là một đối tượng hàm.
9.3.4 Đối tượng phương thức
Thông thường, một phương thức được gọi ngay sau khi nó bị buộc:
x.f()
Trong MyClass , nó sẽ trả về chuỗi 'hello world'. Tuy nhiên, cũng không nhất thiết phải gọi một phương thức ngay lập tức: x.f là một đối tượng phương thức, và có thể được cất đi và gọi vào một thời điểm khác. Ví dụ:
xf = x.f while True:
print xf()
sẽ tiếp tục in "hello world" mãi mãi.
Chuyện gì thật sự xảy ra khi một phương thức được gọi? Bạn có thể đã nhận ra rằng x.f() được gọi với không thông số, mặc dù định nghĩa hàm của f chỉ định một thông số. Chuyện gì xảy ra với thông số đó? Python chắc chắn nâng một biệt lệ khi một hàm cấn một thông số được gọi suông -- cho dù thông số đó có được dùng hay không đi nữa...
Thật ra, bạn cũng có thể đã đoán ra được câu trả lời: điểm đặc biệt của phương thức
9. Lớp http://www.vithon.org/tutorial/2.5/node11.html
là đối tượng đó được truyền vào ở thông số đấu tiên của hàm. Trong ví dụ của chúng ta, lời gọi x.f() hoàn toàn tương đương với MyClass.f(x). Nói chung, gọi một hàm với một danh sách n thông số thì tương đương với việc gọi hàm tương ứng với một danh sách thông số được tạo ra bằng cách chèn đối tượng của phương thức vào trước thông số thứ nhất.
(Hiểu đơn giản là obj.name(arg1, arg2) tương đương với Class.name(obj, arg1, arg2) trong đó obj là đối tượng trường hợp của lớp Class, name là một thuộc tính hợp lệ không phải dữ liệu, tức là đối tượng hàm của lớp đó.)