Tuyên bố đúng về lớp python
Python là một ngôn ngữ lập trình hướng đối tượng, có nghĩa là nó cung cấp các tính năng hỗ trợ lập trình hướng đối tượng (OOP) Show
Lập trình hướng đối tượng bắt nguồn từ những năm 1960, nhưng mãi đến giữa những năm 1980, nó mới trở thành mô hình lập trình chính được sử dụng để tạo ra phần mềm mới. Nó được phát triển như một cách để xử lý quy mô và độ phức tạp ngày càng tăng nhanh chóng của các hệ thống phần mềm và giúp dễ dàng sửa đổi các hệ thống lớn và phức tạp này theo thời gian Cho đến bây giờ, chúng tôi đã viết chương trình bằng cách sử dụng mô hình lập trình thủ tục. Trong lập trình thủ tục, trọng tâm là viết các hàm hoặc thủ tục hoạt động trên dữ liệu. Trong lập trình hướng đối tượng, trọng tâm là tạo ra các đối tượng chứa cả dữ liệu và chức năng cùng nhau 7. 2. Các loại kết hợp do người dùng định nghĩa¶Bây giờ chúng ta sẽ giới thiệu một từ khóa Python mới, class, về bản chất nó định nghĩa một kiểu dữ liệu mới. Chúng tôi đã sử dụng một số loại tích hợp sẵn của Python trong suốt cuốn sách này, giờ đây chúng tôi đã sẵn sàng để tạo loại do người dùng xác định của riêng mình. print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 Xét khái niệm điểm toán học. Trong hai chiều, một điểm là hai số (tọa độ) được coi như một đối tượng duy nhất. Trong ký hiệu toán học, điểm thường được viết trong ngoặc đơn với dấu phẩy ngăn cách tọa độ. Ví dụ: print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y6 đại diện cho gốc tọa độ và print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y7 đại diện cho điểm print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 đơn vị ở bên phải và print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y9 đơn vị phía trên so với gốc tọa độ Một cách tự nhiên để biểu thị một điểm trong Python là có hai giá trị số. Sau đó, câu hỏi đặt ra là làm thế nào để nhóm hai giá trị này thành một đối tượng phức hợp. Giải pháp nhanh và bẩn là sử dụng danh sách hoặc bộ dữ liệu và đối với một số ứng dụng, đây có thể là lựa chọn tốt nhất Một cách khác là định nghĩa một loại hợp chất mới do người dùng định nghĩa, được gọi là một lớp. Cách tiếp cận này đòi hỏi nhiều nỗ lực hơn một chút, nhưng nó có những ưu điểm sẽ sớm xuất hiện Một định nghĩa lớp trông như thế này class Point: pass Các định nghĩa lớp có thể xuất hiện ở bất kỳ đâu trong chương trình, nhưng chúng thường ở gần phần đầu (sau các câu lệnh >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "0). Các quy tắc cú pháp cho một định nghĩa lớp cũng giống như đối với các câu lệnh ghép khác. Có một tiêu đề bắt đầu bằng từ khóa, >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "1, theo sau là tên của lớp và kết thúc bằng dấu hai chấm Định nghĩa này tạo ra một lớp mới gọi là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5. Câu lệnh vượt qua không có hiệu lực; . Một chuỗi tài liệu có thể phục vụ cùng một mục đích class Point: "Point class for storing mathematical points." Bằng cách tạo lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5, chúng tôi đã tạo một loại mới, còn được gọi là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5. Các thành viên của loại này được gọi là thể hiện của loại hoặc đối tượng. Việc tạo một thể hiện mới được gọi là khởi tạo và được thực hiện bằng cách gọi lớp. Các lớp, giống như các hàm, có thể gọi được và chúng ta khởi tạo một đối tượng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 bằng cách gọi lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y4 Biến >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7 được gán một tham chiếu đến một đối tượng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 mới Có thể hữu ích khi nghĩ về một lớp như một nhà máy để tạo ra các đối tượng, vì vậy lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 của chúng ta là một nhà máy để tạo ra các điểm. Bản thân lớp không phải là một thể hiện của một điểm, nhưng nó chứa bộ máy để tạo ra các thể hiện của điểm 7. 3. Thuộc tính¶Giống như các đối tượng trong thế giới thực, các thể hiện đối tượng có cả hình thức và chức năng. Biểu mẫu bao gồm các thành phần dữ liệu chứa trong thể hiện Chúng ta có thể thêm các phần tử dữ liệu mới vào một thể hiện bằng cách sử dụng ký hiệu dấu chấm print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 Cú pháp này tương tự như cú pháp để chọn một biến từ một mô-đun, chẳng hạn như print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y90 hoặc print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y91. Cả mô-đun và phiên bản đều tạo không gian tên riêng của chúng và cú pháp để truy cập tên có trong mỗi, được gọi là thuộc tính, là giống nhau. Trong trường hợp này, thuộc tính chúng tôi đang chọn là một mục dữ liệu từ một thể hiện Sơ đồ trạng thái sau đây cho thấy kết quả của các nhiệm vụ này Biến >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7 đề cập đến một đối tượng Điểm, chứa hai thuộc tính. Mỗi thuộc tính đề cập đến một số Chúng ta có thể đọc giá trị của một thuộc tính bằng cùng một cú pháp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y2 Biểu thức print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y93 có nghĩa là, “Đi tới đối tượng mà >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7 đề cập đến và nhận giá trị của print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8”. Trong trường hợp này, chúng ta gán giá trị đó cho một biến có tên là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8. Không có xung đột giữa biến print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 và thuộc tính print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8. Mục đích của ký hiệu dấu chấm là để xác định rõ ràng bạn đang đề cập đến biến nào Bạn có thể sử dụng ký hiệu dấu chấm như một phần của bất kỳ biểu thức nào, vì vậy các câu sau đây là hợp pháp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y Dòng đầu tiên xuất ra print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y99; 7. 4. Phương thức khởi tạo và print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y 10¶Vì lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 của chúng tôi nhằm mục đích biểu diễn các điểm toán học hai chiều, nên tất cả các thể hiện điểm phải có các thuộc tính print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 và print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y9, nhưng điều đó vẫn chưa đúng với các đối tượng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 của chúng tôi >>> p2 = Point() >>> p2.x Traceback (most recent call last): File " Để giải quyết vấn đề này, chúng tôi thêm một phương thức khởi tạo vào lớp của chúng tôi print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y9 Một phương thức hoạt động giống như một hàm nhưng nó là một phần của đối tượng. Giống như một thuộc tính dữ liệu, nó được truy cập bằng ký hiệu dấu chấm Phương thức khởi tạo là một phương thức đặc biệt được gọi tự động khi một đối tượng được tạo bằng cách gọi lớp. Tên của phương thức này là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y15 (hai ký tự gạch dưới, tiếp theo là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y16, và sau đó là hai dấu gạch dưới nữa). Tên này phải được sử dụng để biến một phương thức thành phương thức khởi tạo trong Python Không có xung đột giữa thuộc tính print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y17 và tham số print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8. Ký hiệu dấu chấm chỉ định biến nào chúng ta đang đề cập đến Hãy thêm một phương thức khác, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y19, để hiểu rõ hơn cách thức hoạt động của các phương thức print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y1 Hãy tạo một vài trường hợp điểm, xem xét các thuộc tính của chúng và gọi phương thức mới của chúng ta trên chúng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y4 Khi xác định một phương thức, tham số đầu tiên đề cập đến thể hiện được tạo. Theo thông lệ, tự đặt tên cho tham số này. Trong phiên ví dụ ở trên, tham số print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y10 đề cập đến các phiên bản >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y42 và print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y43 tương ứng 7. 5. Các trường hợp dưới dạng tham số¶Bạn có thể truyền một thể hiện dưới dạng tham số cho hàm theo cách thông thường. Ví dụ class Point: "Point class for storing mathematical points."0 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y44 lấy một điểm làm đối số và hiển thị nó ở định dạng chuẩn. Nếu bạn gọi print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y45 với điểm >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7 như đã định nghĩa trước đó, đầu ra là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y99 Để chuyển đổi print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y44 thành một phương thức, hãy làm như sau
class Point: "Point class for storing mathematical points."1 Bây giờ chúng ta có thể gọi phương thức bằng ký hiệu dấu chấm class Point: "Point class for storing mathematical points."2 Đối tượng mà phương thức được gọi được gán cho tham số đầu tiên, vì vậy trong trường hợp này, >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7 được gán cho tham số print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y10. Theo quy ước, tham số đầu tiên của một phương thức được gọi là print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y10. Lý do cho điều này hơi phức tạp, nhưng nó dựa trên một phép ẩn dụ hữu ích Cú pháp gọi hàm, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y45, gợi ý rằng hàm là tác nhân tích cực. Nó nói đại loại như, Này print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y44. Đây là một đối tượng để bạn in Trong lập trình hướng đối tượng, các đối tượng là tác nhân tích cực. Một lời gọi như class Point: "Point class for storing mathematical points."05 nói Hey >>> p2 = Point() >>> p2.x Traceback (most recent call last): File "7. Hãy in cho mình Sự thay đổi quan điểm này có thể lịch sự hơn, nhưng không rõ ràng là nó hữu ích. Trong các ví dụ chúng ta đã thấy cho đến nay, nó có thể không. Nhưng đôi khi việc chuyển trách nhiệm từ các chức năng sang các đối tượng giúp viết các chức năng linh hoạt hơn và giúp duy trì và sử dụng lại mã dễ dàng hơn 7. 6. Các tính năng hướng đối tượng¶Không dễ để định nghĩa lập trình hướng đối tượng, nhưng chúng ta đã thấy một số đặc điểm của nó
Ví dụ, lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 tương ứng với khái niệm toán học của một điểm 7. 7. Thời gian¶Như một ví dụ khác về loại do người dùng định nghĩa, chúng tôi sẽ định nghĩa một lớp có tên là class Point: "Point class for storing mathematical points."08 ghi lại thời gian trong ngày. Vì thời gian sẽ cần các thuộc tính giờ, phút và giây, nên chúng ta sẽ bắt đầu với một phương thức khởi tạo tương tự như phương thức chúng ta đã tạo cho Điểm Định nghĩa lớp trông như thế này class Point: "Point class for storing mathematical points."3 Khi chúng tôi gọi lớp class Point: "Point class for storing mathematical points."08, các đối số mà chúng tôi cung cấp sẽ được chuyển đến lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y16 class Point: "Point class for storing mathematical points."4 Đây là một phương thức class Point: "Point class for storing mathematical points."11 cho các đối tượng class Point: "Point class for storing mathematical points."08 của chúng tôi sử dụng định dạng chuỗi để hiển thị phút và giây với hai chữ số Để tiết kiệm dung lượng, chúng tôi sẽ bỏ qua phương thức khởi tạo, nhưng bạn nên đưa nó vào class Point: "Point class for storing mathematical points."5 mà bây giờ chúng ta có thể gọi các trường hợp thời gian theo cách thông thường class Point: "Point class for storing mathematical points."6 7. 8. Đối số tùy chọn¶Chúng ta đã thấy các hàm tích hợp có số lượng đối số thay đổi. Ví dụ: class Point: "Point class for storing mathematical points."13 có thể nhận hai, ba hoặc bốn đối số Có thể viết các hàm do người dùng định nghĩa với danh sách đối số tùy chọn. Ví dụ: chúng tôi có thể nâng cấp phiên bản class Point: "Point class for storing mathematical points."14 của riêng mình để làm điều tương tự như class Point: "Point class for storing mathematical points."13 Đây là phiên bản gốc class Point: "Point class for storing mathematical points."7 Đây là phiên bản mới và cải tiến class Point: "Point class for storing mathematical points."8 Tham số thứ ba, class Point: "Point class for storing mathematical points."16, là tùy chọn vì giá trị mặc định, class Point: "Point class for storing mathematical points."17, được cung cấp. Nếu chúng ta gọi class Point: "Point class for storing mathematical points."14 chỉ với hai đối số, chúng ta sẽ sử dụng giá trị mặc định và bắt đầu từ đầu chuỗi class Point: "Point class for storing mathematical points."9 Nếu chúng tôi cung cấp tham số thứ ba, tham số này sẽ ghi đè tham số mặc định print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y40 Chúng ta có thể viết lại phương thức khởi tạo của mình cho lớp class Point: "Point class for storing mathematical points."08 sao cho mỗi đối số tùy chọn là class Point: "Point class for storing mathematical points."20, class Point: "Point class for storing mathematical points."21 và class Point: "Point class for storing mathematical points."22 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y41 Khi chúng ta khởi tạo một đối tượng class Point: "Point class for storing mathematical points."08, chúng ta có thể chuyển các giá trị cho ba tham số, như chúng ta đã làm với print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y42 Tuy nhiên, vì các tham số hiện là tùy chọn nên chúng ta có thể bỏ qua chúng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y43 Hoặc chỉ cung cấp tham số đầu tiên print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y44 Hoặc hai tham số đầu tiên print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y45 Cuối cùng, chúng ta có thể cung cấp một tập hợp con các tham số bằng cách đặt tên rõ ràng cho chúng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y46 7. 9. Phương pháp khác¶Hãy thêm một phương thức class Point: "Point class for storing mathematical points."24, phương thức này sẽ tăng một thể hiện thời gian theo một số giây nhất định. Để tiết kiệm dung lượng, chúng tôi sẽ tiếp tục loại bỏ các phương thức đã xác định trước đó, nhưng bạn phải luôn giữ chúng trong phiên bản của mình print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y47 Bây giờ chúng ta có thể gọi class Point: "Point class for storing mathematical points."24 trong một trường hợp thời gian print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y48 Một lần nữa, đối tượng mà phương thức được gọi sẽ được gán cho tham số đầu tiên, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y10. Tham số thứ hai, class Point: "Point class for storing mathematical points."22 nhận giá trị class Point: "Point class for storing mathematical points."28 7. 10. Ví dụ với hai class Point: "Point class for storing mathematical points." 08¶Hãy thêm một phương thức boolen, class Point: "Point class for storing mathematical points."30, nhận hai trường hợp thời gian và trả về class Point: "Point class for storing mathematical points."31 khi trường hợp đầu tiên theo thứ tự thời gian sau trường hợp thứ hai Chúng tôi chỉ có thể chuyển đổi một trong các tham số thành print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y10; print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y49 Chúng tôi gọi phương thức này trên một đối tượng và chuyển đối tượng kia làm đối số print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y80 Bạn gần như có thể đọc lời kêu gọi như tiếng Anh. Nếu thời gian 1 sau thời gian 2, thì… 7. 10. 1. Hàm thuần túy và công cụ sửa đổi (lại)¶Trong vài phần tiếp theo, chúng ta sẽ viết hai phiên bản của hàm có tên là class Point: "Point class for storing mathematical points."34, tính tổng của hai số class Point: "Point class for storing mathematical points."08. Họ sẽ chứng minh hai loại chức năng. các hàm thuần túy và công cụ sửa đổi mà chúng ta đã gặp lần đầu tiên trong chương Hàm . Sau đây là phiên bản thô của class Point: "Point class for storing mathematical points."34 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y81 Hàm tạo một đối tượng class Point: "Point class for storing mathematical points."08 mới, khởi tạo các thuộc tính của nó và trả về một tham chiếu đến đối tượng mới. Đây được gọi là một hàm thuần túy vì nó không sửa đổi bất kỳ đối tượng nào được truyền cho nó dưới dạng tham số và nó không có tác dụng phụ, chẳng hạn như hiển thị giá trị hoặc nhận đầu vào của người dùng Dưới đây là một ví dụ về cách sử dụng chức năng này. Chúng ta sẽ tạo hai đối tượng class Point: "Point class for storing mathematical points."08. class Point: "Point class for storing mathematical points."39, chứa thời gian hiện tại; . Sau đó, chúng tôi sẽ sử dụng class Point: "Point class for storing mathematical points."34 để biết khi nào bánh mì sẽ được làm xong. Nếu bạn chưa viết xong ________ 911, hãy xem trước Phần trước khi bạn thử điều này print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y82 Đầu ra của chương trình này là class Point: "Point class for storing mathematical points."43, đúng. Mặt khác, có trường hợp kết quả không chính xác. Bạn có thể nghĩ về một? Vấn đề là chức năng này không xử lý các trường hợp trong đó số giây hoặc phút cộng lại lớn hơn sáu mươi. Khi điều đó xảy ra, chúng ta phải chuyển số giây thừa vào cột phút hoặc số phút thừa vào cột giờ Đây là phiên bản sửa lỗi thứ hai của chức năng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y83 Mặc dù chức năng này là chính xác, nhưng nó đang bắt đầu lớn. Sau đó, chúng tôi sẽ đề xuất một cách tiếp cận thay thế mang lại mã ngắn hơn 7. 10. 2. Công cụ sửa đổi¶Đôi khi, một hàm sẽ hữu ích khi sửa đổi một hoặc nhiều đối tượng mà nó nhận làm tham số. Thông thường, người gọi giữ một tham chiếu đến các đối tượng mà nó đi qua, vì vậy bất kỳ thay đổi nào mà chức năng tạo ra đều hiển thị cho người gọi. Các chức năng hoạt động theo cách này được gọi là công cụ sửa đổi class Point: "Point class for storing mathematical points."24, thêm một số giây nhất định vào đối tượng class Point: "Point class for storing mathematical points."08, sẽ được viết một cách tự nhiên nhất dưới dạng bổ ngữ. Một bản nháp sơ bộ của chức năng trông như thế này print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y84 Dòng đầu tiên thực hiện thao tác cơ bản; Chức năng này có đúng không? . Một giải pháp là thay thế câu lệnh class Point: "Point class for storing mathematical points."48 bằng câu lệnh class Point: "Point class for storing mathematical points."49 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y85 Chức năng này hiện đã chính xác, nhưng nó không phải là giải pháp hiệu quả nhất 7. 11. Phát triển nguyên mẫu so với lập kế hoạch¶Cho đến giờ trong chương này, chúng ta đã sử dụng một cách tiếp cận để phát triển chương trình mà chúng ta sẽ gọi là phát triển nguyên mẫu. Chúng tôi đã viết một bản nháp sơ bộ (hoặc nguyên mẫu) để thực hiện tính toán cơ bản và sau đó thử nghiệm nó trên một số trường hợp, sửa các lỗi khi chúng tôi tìm thấy chúng Mặc dù cách tiếp cận này có thể hiệu quả, nhưng nó có thể dẫn đến mã phức tạp không cần thiết – vì nó xử lý nhiều trường hợp đặc biệt – và không đáng tin cậy – vì khó biết liệu chúng ta có tìm thấy tất cả các lỗi hay không Một giải pháp thay thế là phát triển theo kế hoạch, trong đó hiểu biết sâu sắc về vấn đề có thể giúp lập trình dễ dàng hơn nhiều. Trong trường hợp này, cái nhìn sâu sắc là một đối tượng class Point: "Point class for storing mathematical points."08 thực sự là một số có ba chữ số trong cơ số 60. Thành phần class Point: "Point class for storing mathematical points."51 là cột đơn vị, thành phần class Point: "Point class for storing mathematical points."52 là cột sáu mươi và thành phần class Point: "Point class for storing mathematical points."53 là cột ba mươi sáu hàng trăm Khi chúng tôi viết class Point: "Point class for storing mathematical points."34 và class Point: "Point class for storing mathematical points."24, chúng tôi đã thực hiện phép cộng trong cơ số 60 một cách hiệu quả, đó là lý do tại sao chúng tôi phải thực hiện từ cột này sang cột tiếp theo Quan sát này gợi ý một cách tiếp cận khác cho toàn bộ vấn đề – chúng ta có thể chuyển đổi một đối tượng class Point: "Point class for storing mathematical points."08 thành một số duy nhất và tận dụng thực tế là máy tính biết cách thực hiện phép tính số học với các số. Hàm sau đây chuyển đổi một đối tượng class Point: "Point class for storing mathematical points."08 thành một số nguyên print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y86 Bây giờ, tất cả những gì chúng ta cần là một cách để chuyển đổi từ một số nguyên thành một đối tượng class Point: "Point class for storing mathematical points."08 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y87 Bạn có thể phải suy nghĩ một chút để thuyết phục bản thân rằng kỹ thuật chuyển đổi từ cơ sở này sang cơ sở khác là đúng. Giả sử bạn bị thuyết phục, bạn có thể sử dụng các chức năng này để viết lại class Point: "Point class for storing mathematical points."34 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y88 Phiên bản này ngắn hơn nhiều so với phiên bản gốc và việc chứng minh rằng nó đúng sẽ dễ dàng hơn nhiều (giả sử, như thường lệ, các chức năng mà nó gọi là đúng) 7. 12. Tổng quát hóa¶Theo một số cách, việc chuyển đổi từ cơ số 60 sang cơ số 10 và ngược lại khó hơn là chỉ xử lý thời gian. Chuyển đổi cơ sở trừu tượng hơn; Nhưng nếu chúng ta có cái nhìn sâu sắc để coi thời gian là các số cơ bản 60 và đầu tư vào việc viết các hàm chuyển đổi ( class Point: "Point class for storing mathematical points."60 và class Point: "Point class for storing mathematical points."61), chúng ta sẽ có được một chương trình ngắn hơn, dễ đọc và gỡ lỗi hơn, đồng thời đáng tin cậy hơn Việc thêm các tính năng sau này cũng dễ dàng hơn. Ví dụ: hãy tưởng tượng trừ hai class Point: "Point class for storing mathematical points."08 để tìm khoảng thời gian giữa chúng. Cách tiếp cận ngây thơ sẽ là thực hiện phép trừ với việc vay. Sử dụng các chức năng chuyển đổi sẽ dễ dàng hơn và có nhiều khả năng đúng hơn Trớ trêu thay, đôi khi làm cho một vấn đề trở nên khó hơn (hoặc tổng quát hơn) lại khiến nó trở nên dễ dàng hơn (vì có ít trường hợp đặc biệt hơn và ít cơ hội mắc lỗi hơn) 7. 13. Thuật toán¶Khi bạn viết một giải pháp chung cho một loại vấn đề, trái ngược với một giải pháp cụ thể cho một vấn đề đơn lẻ, bạn đã viết một thuật toán. Trước đây chúng ta có nhắc đến từ này nhưng chưa định nghĩa kỹ. Không dễ để xác định, vì vậy chúng tôi sẽ thử một vài cách tiếp cận Đầu tiên, hãy xem xét thứ gì đó không phải là thuật toán. Khi bạn học cách nhân các số có một chữ số, có lẽ bạn đã thuộc lòng bảng cửu chương. Trên thực tế, bạn đã ghi nhớ 100 giải pháp cụ thể. Đó là loại kiến thức không phải là thuật toán Nhưng nếu bạn lười biếng, bạn có thể bị lừa bằng cách học một vài thủ thuật. Ví dụ: để tìm tích của class Point: "Point class for storing mathematical points."63 và 9, bạn có thể viết class Point: "Point class for storing mathematical points."64 là chữ số đầu tiên và class Point: "Point class for storing mathematical points."65 là chữ số thứ hai. Thủ thuật này là một giải pháp chung để nhân bất kỳ số có một chữ số nào với 9. Đó là một thuật toán Tương tự như vậy, các kỹ thuật bạn đã học để cộng có mang, trừ có mượn và chia dài đều là các thuật toán. Một trong những đặc điểm của thuật toán là chúng không yêu cầu bất kỳ trí thông minh nào để thực hiện. Chúng là các quy trình cơ học, trong đó mỗi bước nối tiếp bước trước theo một bộ quy tắc đơn giản. Theo tôi, thật đáng xấu hổ khi con người dành quá nhiều thời gian ở trường để học cách thực hiện các thuật toán mà theo đúng nghĩa đen là không cần trí thông minh Mặt khác, quá trình thiết kế thuật toán rất thú vị, thách thức trí tuệ và là phần trung tâm của cái mà chúng ta gọi là lập trình Một số điều mà mọi người làm một cách tự nhiên, không gặp khó khăn hoặc suy nghĩ có ý thức, lại là điều khó diễn đạt nhất bằng thuật toán. Hiểu ngôn ngữ tự nhiên là một ví dụ điển hình. Tất cả chúng ta đều làm điều đó, nhưng cho đến nay không ai có thể giải thích cách chúng ta làm điều đó, ít nhất là không phải dưới dạng thuật toán 7. 14. Điểm xem lại¶Hãy viết lại lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 theo phong cách hướng đối tượng hơn print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y89 Phương thức tiếp theo, class Point: "Point class for storing mathematical points."67, trả về một biểu diễn chuỗi của đối tượng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5. Nếu một lớp cung cấp một phương thức có tên là class Point: "Point class for storing mathematical points."67, thì nó sẽ ghi đè hành vi mặc định của hàm class Point: "Point class for storing mathematical points."70 tích hợp trong Python print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y20 In một đối tượng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 gọi ngầm class Point: "Point class for storing mathematical points."67 trên đối tượng, do đó, việc xác định class Point: "Point class for storing mathematical points."67 cũng thay đổi hành vi của class Point: "Point class for storing mathematical points."74 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y21 Khi chúng ta viết một lớp mới, hầu như chúng ta luôn bắt đầu bằng cách viết print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y15, giúp khởi tạo đối tượng dễ dàng hơn và class Point: "Point class for storing mathematical points."67, hầu như luôn hữu ích cho việc gỡ lỗi 7. 15. Nạp toán tử¶Một số ngôn ngữ cho phép thay đổi định nghĩa của các toán tử tích hợp khi chúng được áp dụng cho các loại do người dùng xác định. Tính năng này được gọi là quá tải toán tử. Nó đặc biệt hữu ích khi xác định các loại toán học mới Ví dụ: để ghi đè toán tử cộng class Point: "Point class for storing mathematical points."77, chúng tôi cung cấp một phương thức có tên class Point: "Point class for storing mathematical points."78 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y22 Như thường lệ, tham số đầu tiên là đối tượng mà phương thức được gọi. Tham số thứ hai được đặt tên thuận tiện là class Point: "Point class for storing mathematical points."33 để phân biệt với print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y10. Để thêm hai print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5, chúng tôi tạo và trả về một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 mới chứa tổng của tọa độ print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 và tổng của tọa độ print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y9 Bây giờ, khi chúng ta áp dụng toán tử class Point: "Point class for storing mathematical points."77 cho các đối tượng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5, Python sẽ gọi class Point: "Point class for storing mathematical points."78 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y23 Biểu thức class Point: "Point class for storing mathematical points."88 tương đương với class Point: "Point class for storing mathematical points."89, nhưng rõ ràng là tao nhã hơn. Như một bài tập, hãy thêm một phương thức class Point: "Point class for storing mathematical points."90 làm quá tải toán tử trừ và dùng thử. Có một số cách để ghi đè hành vi của toán tử nhân. bằng cách định nghĩa một phương thức có tên là class Point: "Point class for storing mathematical points."91 hoặc class Point: "Point class for storing mathematical points."92 hoặc cả hai Nếu toán hạng bên trái của class Point: "Point class for storing mathematical points."93 là một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5, Python gọi class Point: "Point class for storing mathematical points."91, giả định rằng toán hạng kia cũng là một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5. Nó tính tích vô hướng của hai điểm, được xác định theo các quy tắc của đại số tuyến tính print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y24 Nếu toán hạng bên trái của class Point: "Point class for storing mathematical points."93 là kiểu nguyên thủy và toán hạng bên phải là một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5, Python gọi class Point: "Point class for storing mathematical points."92, thực hiện phép nhân vô hướng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y25 Kết quả là một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 mới có tọa độ là bội số của tọa độ ban đầu. Nếu class Point: "Point class for storing mathematical points."33 là loại không thể nhân với số dấu phẩy động, thì class Point: "Point class for storing mathematical points."92 sẽ sinh ra lỗi Ví dụ này minh họa cả hai loại phép nhân print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y26 Điều gì xảy ra nếu chúng ta cố gắng đánh giá print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y403? . Bên trong class Point: "Point class for storing mathematical points."91, chương trình cố gắng truy cập tọa độ print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 của class Point: "Point class for storing mathematical points."33, không thành công vì một số nguyên không có thuộc tính print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y27 Thật không may, thông báo lỗi hơi mờ. Ví dụ này cho thấy một số khó khăn của lập trình hướng đối tượng. Đôi khi thật khó để tìm ra mã nào đang chạy Để có ví dụ đầy đủ hơn về nạp chồng toán tử, xem Phụ lục (nạp chồng tham chiếu) 7. 16. Đa hình¶Hầu hết các phương pháp chúng tôi đã viết chỉ hoạt động cho một loại cụ thể. Khi bạn tạo một đối tượng mới, bạn viết các phương thức hoạt động trên loại đó Nhưng có một số phép toán mà bạn sẽ muốn áp dụng cho nhiều loại, chẳng hạn như các phép toán số học trong các phần trước. Nếu nhiều loại hỗ trợ cùng một nhóm thao tác, bạn có thể viết các hàm hoạt động trên bất kỳ loại nào trong số đó Ví dụ, phép toán print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y410 (phổ biến trong đại số tuyến tính) nhận ba tham số; . Chúng ta có thể viết nó bằng Python như thế này print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y28 Phương pháp này sẽ hoạt động đối với bất kỳ giá trị nào của print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y8 và print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y9 có thể được nhân lên và đối với bất kỳ giá trị nào của print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y413 có thể được thêm vào sản phẩm Chúng ta có thể gọi nó với các giá trị số print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y29 Hoặc với print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5s print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y0 Trong trường hợp đầu tiên, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 được nhân với một số vô hướng và sau đó được cộng với một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 khác. Trong trường hợp thứ hai, tích vô hướng mang lại một giá trị số, vì vậy tham số thứ ba cũng phải là một giá trị số Một chức năng như thế này có thể nhận các tham số với các loại khác nhau được gọi là đa hình Một ví dụ khác, xem xét phương thức print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y417, in danh sách hai lần, tiến và lùi print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y1 Bởi vì phương pháp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y418 là một công cụ sửa đổi, chúng tôi tạo một bản sao của danh sách trước khi đảo ngược nó. Theo cách đó, phương thức này không sửa đổi danh sách mà nó nhận được dưới dạng tham số Đây là một ví dụ áp dụng print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y417 cho một danh sách print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y2 Tất nhiên, chúng tôi dự định áp dụng chức năng này cho các danh sách, vì vậy không có gì ngạc nhiên khi nó hoạt động. Điều đáng ngạc nhiên là nếu chúng ta có thể áp dụng nó vào một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 Để xác định xem một chức năng có thể được áp dụng cho một loại mới hay không, chúng tôi áp dụng quy tắc cơ bản của tính đa hình. Nếu tất cả các hoạt động bên trong hàm có thể được áp dụng cho loại, thì hàm có thể được áp dụng cho loại. Các hoạt động trong phương pháp bao gồm print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y421, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y418 và class Point: "Point class for storing mathematical points."74 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y421 hoạt động trên bất kỳ đối tượng nào và chúng tôi đã viết một phương thức class Point: "Point class for storing mathematical points."67 cho các print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5, vì vậy tất cả những gì chúng tôi cần là một phương thức print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y418 trong lớp print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y3 Sau đó, chúng ta có thể chuyển print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5s đến print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y417 print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y4 Loại đa hình tốt nhất là loại không cố ý, trong đó bạn phát hiện ra rằng một chức năng bạn đã viết có thể được áp dụng cho một loại mà bạn chưa bao giờ lên kế hoạch. 7. 17. Bảng thuật ngữ¶lớpLoại hợp chất do người dùng xác định. Một lớp cũng có thể được coi là khuôn mẫu cho các đối tượng là thể hiện của nó khởi tạoĐể tạo một thể hiện của một lớp ví dụMột đối tượng thuộc về một lớp sự vậtMột kiểu dữ liệu phức hợp thường được sử dụng để mô hình hóa một sự vật hoặc khái niệm trong thế giới thực thuộc tínhMột trong những mục dữ liệu được đặt tên tạo nên một thể hiện chức năng thuần túyMột hàm không sửa đổi bất kỳ đối tượng nào mà nó nhận làm tham số. Hầu hết các hàm thuần túy đều hiệu quả bổ nghĩaHàm thay đổi một hoặc nhiều đối tượng mà nó nhận làm tham số. Hầu hết các công cụ sửa đổi đều vô hiệu phong cách lập trình chức năngMột phong cách thiết kế chương trình trong đó phần lớn các chức năng là thuần túy phát triển nguyên mẫuMột cách để phát triển các chương trình bắt đầu với một nguyên mẫu và dần dần thử nghiệm và cải tiến nó kế hoạch phát triểnMột cách phát triển các chương trình liên quan đến hiểu biết sâu sắc về vấn đề và lập kế hoạch nhiều hơn so với phát triển gia tăng hoặc phát triển nguyên mẫu ngôn ngữ hướng đối tượngMột ngôn ngữ cung cấp các tính năng, chẳng hạn như lớp do người dùng định nghĩa và tính kế thừa, hỗ trợ lập trình hướng đối tượng lập trình hướng đối tượngMột phong cách lập trình trong đó dữ liệu và các hoạt động thao tác với nó được tổ chức thành các lớp và phương thức phương phápMột hàm được định nghĩa bên trong một định nghĩa lớp và được gọi trên các phiên bản của lớp đó. . ghi đè. Để thay thế một mặc định. Các ví dụ bao gồm thay thế một tham số mặc định bằng một đối số cụ thể và thay thế một phương thức mặc định bằng cách cung cấp một phương thức mới có cùng tên phương thức khởi tạoMột phương thức đặc biệt được gọi tự động khi một đối tượng mới được tạo và khởi tạo các thuộc tính của đối tượng quá tải toán tửMở rộng các toán tử tích hợp sẵn ( class Point: "Point class for storing mathematical points."77, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y432, class Point: "Point class for storing mathematical points."93, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y434, print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y435, v.v. ) để chúng hoạt động với các loại do người dùng xác địnhsản phẩm chấm Một phép toán được xác định trong đại số tuyến tính nhân hai print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 và mang lại một giá trị sốnhân bản vô tính Một phép toán được định nghĩa trong đại số tuyến tính nhân mỗi tọa độ của một print('({0}, {1})'.format(p.x, p.y)) distance_squared = p.x * p.x + p.y * p.y5 với một giá trị sốđa hình Một chức năng có thể hoạt động trên nhiều loại. Nếu tất cả các hoạt động trong một hàm có thể được áp dụng cho một loại, thì hàm đó có thể được áp dụng cho một loại Điều gì đúng về thuộc tính lớp?Thuộc tính của lớp là thuộc tính do chính lớp đó sở hữu . Chúng sẽ được chia sẻ bởi tất cả các thể hiện của lớp. Do đó, chúng có cùng giá trị cho mọi trường hợp. Chúng tôi định nghĩa các thuộc tính lớp bên ngoài tất cả các phương thức, thường chúng được đặt ở trên cùng, ngay bên dưới tiêu đề lớp.
Điều gì đúng về lớp và đối tượng?một đối tượng là một thành phần (hoặc thể hiện) của một lớp; . Đối tượng là thành phần thực sự của các chương trình, trong khi lớp chỉ định cách các thể hiện được tạo và cách chúng hoạt động. phương pháp. một phương thức là một hành động mà một đối tượng có thể thực hiện. . The object is the actual component of programs, while the class specifies how instances are created and how they behave. method: a method is an action which an object is able to perform.
Lớp trong Python là gì?Các lớp và đối tượng Python
. Hầu hết mọi thứ trong Python là một đối tượng, với các thuộc tính và phương thức của nó. Lớp giống như một hàm tạo đối tượng hoặc "bản thiết kế" để tạo đối tượng .
Điều gì đúng về phương thức __ Init__ trong Python?Phương thức __init__ tương đương với Python của hàm tạo C++ theo cách tiếp cận hướng đối tượng. Hàm __init__ được gọi mỗi khi một đối tượng được tạo từ một lớp. Phương thức __init__ cho phép lớp khởi tạo các thuộc tính của đối tượng và không phục vụ mục đích nào khác . Nó chỉ được sử dụng trong các lớp học. |