Theo những gì bạn đã viết, bạn đang thiếu một phần hiểu biết quan trọng: sự khác biệt giữa một lớp và một đối tượng. __init__
không khởi tạo một lớp, nó khởi tạo một thể hiện của một lớp hoặc một đối tượng. Mỗi con chó có màu sắc, nhưng những con chó như một lớp học thì không. Mỗi con chó có bốn chân trở xuống, nhưng loại chó thì không. Lớp là một khái niệm của một đối tượng. Khi bạn nhìn thấy Fido và Spot, bạn nhận ra sự giống nhau của họ, tính giáo điều của họ. Đó là lớp học.
Khi bạn nói
class Dog:
def __init__(self, legs, colour):
self.legs = legs
self.colour = colour
fido = Dog(4, "brown")
spot = Dog(3, "mostly yellow")
Bạn đang nói, Fido là một con chó màu nâu với 4 chân trong khi Spot hơi què quặt và chủ yếu là màu vàng. Các __init__
hàm được gọi một constructor, hoặc khởi tạo, và được tự động gọi khi bạn tạo một đối tượng mới của một lớp. Trong hàm đó, đối tượng mới tạo được gán cho tham số self
. Ký hiệu self.legs
là một thuộc tính được gọi legs
của đối tượng trong biến self
. Các thuộc tính giống như các biến, nhưng chúng mô tả trạng thái của một đối tượng hoặc các hành động cụ thể (chức năng) có sẵn cho đối tượng.
Tuy nhiên, hãy lưu ý rằng bạn không đặt colour
cho bản thân giáo điều - đó là một khái niệm trừu tượng. Có các thuộc tính có ý nghĩa trên các lớp. Ví dụ, population_size
có phải là một như vậy - không hợp lý khi đếm Fido vì Fido luôn là một. Thật có ý nghĩa khi đếm chó. Giả sử có 200 triệu con chó trên thế giới. Đó là tài sản của lớp Dog. Fido không liên quan gì đến con số 200 triệu, Spot cũng vậy. Nó được gọi là "thuộc tính lớp", trái ngược với "thuộc tính cá thể" bằng colour
hoặc legs
cao hơn.
Bây giờ, đến một thứ gì đó ít răng nanh hơn và liên quan đến lập trình nhiều hơn. Như tôi viết dưới đây, lớp để thêm những thứ là không hợp lý - nó là một lớp của cái gì? Các lớp trong Python tạo thành các tập hợp dữ liệu khác nhau, hoạt động tương tự. Lớp chó bao gồm Fido và Spot và 199999999998 động vật khác tương tự như chúng, tất cả chúng đều đi tiểu trên cột đèn. Lớp để thêm những thứ bao gồm những gì? Chúng khác nhau ở những dữ liệu nào vốn có? Và họ chia sẻ những hành động nào?
Tuy nhiên, những con số ... đó là những môn học thú vị hơn. Nói, Số nguyên. Có rất nhiều trong số đó, nhiều hơn cả chó. Tôi biết rằng Python đã có các số nguyên, nhưng chúng ta hãy chơi ngu ngốc và "triển khai" chúng một lần nữa (bằng cách gian lận và sử dụng các số nguyên của Python).
Vì vậy, Số nguyên là một lớp. Chúng có một số dữ liệu (giá trị) và một số hành vi ("thêm tôi vào số khác này"). Hãy thể hiện điều này:
class MyInteger:
def __init__(self, newvalue)
# imagine self as an index card.
# under the heading of "value", we will write
# the contents of the variable newvalue.
self.value = newvalue
def add(self, other):
# when an integer wants to add itself to another integer,
# we'll take their values and add them together,
# then make a new integer with the result value.
return MyInteger(self.value + other.value)
three = MyInteger(3)
# three now contains an object of class MyInteger
# three.value is now 3
five = MyInteger(5)
# five now contains an object of class MyInteger
# five.value is now 5
eight = three.add(five)
# here, we invoked the three's behaviour of adding another integer
# now, eight.value is three.value + five.value = 3 + 5 = 8
print eight.value
# ==> 8
Điều này hơi mong manh (chúng tôi giả định other
sẽ là một MyInteger), nhưng chúng tôi sẽ bỏ qua ngay bây giờ. Trong mã thực, chúng tôi sẽ không; chúng tôi sẽ kiểm tra nó để đảm bảo, và thậm chí có thể ép buộc nó ("bạn không phải là một số nguyên? Thật tuyệt vời, bạn có 10 nano giây để trở thành một! 9 ... 8 ....")
Chúng tôi thậm chí có thể xác định phân số. Phân số cũng biết tự cộng.
class MyFraction:
def __init__(self, newnumerator, newdenominator)
self.numerator = newnumerator
self.denominator = newdenominator
# because every fraction is described by these two things
def add(self, other):
newdenominator = self.denominator * other.denominator
newnumerator = self.numerator * other.denominator + self.denominator * other.numerator
return MyFraction(newnumerator, newdenominator)
Thậm chí có nhiều phân số hơn số nguyên (không hẳn, nhưng máy tính không biết điều đó). Hãy làm hai:
half = MyFraction(1, 2)
third = MyFraction(1, 3)
five_sixths = half.add(third)
print five_sixths.numerator
# ==> 5
print five_sixths.denominator
# ==> 6
Bạn không thực sự khai báo bất cứ điều gì ở đây. Các thuộc tính giống như một loại biến mới. Các biến bình thường chỉ có một giá trị. Hãy để chúng tôi nói rằng bạn viết colour = "grey"
. Bạn không thể có một biến có tên colour
đó là "fuchsia"
- không phải trong cùng một vị trí trong các mã.
Mảng giải quyết điều đó ở một mức độ. Nếu bạn nói colour = ["grey", "fuchsia"]
, bạn đã xếp chồng hai màu vào biến, nhưng bạn phân biệt chúng theo vị trí của chúng (0 hoặc 1, trong trường hợp này).
Thuộc tính là các biến được liên kết với một đối tượng. Giống như với mảng, chúng ta có thể có nhiều colour
biến, trên các con chó khác nhau . Vì vậy, fido.colour
là một biến, nhưng spot.colour
là một biến khác. Cái đầu tiên được liên kết với đối tượng trong biến fido
; thứ hai spot
,. Bây giờ, khi bạn gọi Dog(4, "brown")
, hoặc three.add(five)
, sẽ luôn có một tham số ẩn, sẽ được gán cho tham số phụ nằm ở phía trước danh sách tham số. Nó được gọi theo quy ước self
, và sẽ nhận giá trị của đối tượng đứng trước dấu chấm. Do đó, bên trong Dog's __init__
(constructor), self
sẽ là bất cứ thứ gì mà Dog mới sẽ trở thành; trong MyInteger
's add
, self
sẽ được liên kết với đối tượng trong biến three
. Vì vậy,three.value
sẽ là cùng một biến bên ngoài add
, như self.value
trong add
.
Nếu tôi nói the_mangy_one = fido
, tôi sẽ bắt đầu đề cập đến đối tượng được biết đến fido
với cái tên khác. Từ bây giờ, fido.colour
chính xác là biến giống như the_mangy_one.colour
.
Vì vậy, những thứ bên trong __init__
. Bạn có thể coi chúng như những điều ghi chú vào giấy khai sinh của Chó. colour
tự nó là một biến ngẫu nhiên, có thể chứa bất kỳ thứ gì. fido.colour
hoặc self.colour
giống như một trường biểu mẫu trên trang nhận dạng của Chó; và __init__
là nhân viên điền lần đầu tiên.
Bất kỳ rõ ràng hơn?
CHỈNH SỬA : Mở rộng bình luận bên dưới:
Ý bạn là một danh sách các đối tượng , phải không?
Trước hết, fido
thực sự không phải là một đối tượng. Nó là một biến, hiện đang chứa một đối tượng, giống như khi bạn nói x = 5
, x
là một biến hiện đang chứa số năm. Nếu sau đó bạn thay đổi ý định, bạn có thể làm fido = Cat(4, "pleasing")
(miễn là bạn đã tạo một lớp Cat
) và fido
từ đó trở đi sẽ "chứa" một đối tượng mèo. Nếu bạn làm vậy fido = x
, nó sẽ chứa số năm, và hoàn toàn không phải là một đối tượng động vật.
Bản thân một lớp không biết các cá thể của nó trừ khi bạn viết mã cụ thể để theo dõi chúng. Ví dụ:
class Cat:
census = [] #define census array
def __init__(self, legs, colour):
self.colour = colour
self.legs = legs
Cat.census.append(self)
Đây, census
là một thuộc tính cấp độ Cat
lớp của lớp.
fluffy = Cat(4, "white")
spark = Cat(4, "fiery")
Cat.census
# ==> [<__main__.Cat instance at 0x108982cb0>, <__main__.Cat instance at 0x108982e18>]
# or something like that
Lưu ý rằng bạn sẽ không nhận được [fluffy, sparky]
. Đó chỉ là những tên biến. Nếu bạn muốn mèo có tên, bạn phải tạo một thuộc tính riêng cho tên, sau đó ghi đè __str__
phương thức để trả về tên này. Mục đích của phương thức này (tức là hàm ràng buộc lớp, giống như add
hoặc __init__
) là mô tả cách chuyển đổi đối tượng thành một chuỗi, giống như khi bạn in nó ra.