Lập trình hướng đối tượng (OOP) với Python: Chìa Khóa Để Không Chỉ Là Ngồi Code, Vững Nền Tảng Để Tạo Ra Đột Phá

Trong mớ rắc rối của các Python script, OOP giúp sắp xếp mã nguồn, phát triển tư duy thiết kế và phần mềm một cách có hệ thống.

Lập trình hướng đối tượng (OOP) với Python: Chìa Khóa Để Không Chỉ Là Ngồi Code, Vững Nền Tảng Để Tạo Ra Đột Phá


Hey, bạn đang tìm hiểu về lập trình hướng đối tượng (OOP) với Python? Tốt, bạn đã đến đúng nơi. Đầu tiên, quên đi những quyển sách dày cộm và lý thuyết mơ hồ. Hãy nhìn vào thực tế: OOP không chỉ là một môn học, nó là nền tảng bắt buộc để bạn có thể làm cái gì đó.

Hầu hết mọi người đã được dạy về OOP ở trường nhưng có vẻ mọi người không thèm chú ý đến nó, chúng ta muốn theo đuổi AI và Blockchain hơn. Ra trường, họ sẽ xin được một công việc, loay hoay với Jupyter notebook và vài script python, và công việc của họ sẽ là một mớ hỗn độn khi nó yêu cầu họ thực sự phải lập trình một cái gì đó. Đấy, tôi đã thấy nó xảy ra hàng ngàn lần.

Mọi người dễ dàng lạc lối trong mớ bòng bong của các script và snippet mà quên mất rằng một cấu trúc vững chắc là yếu tố quan trọng nhất. Đó là nơi mớ lý thuyết cũ OOP tỏa sáng. Nó không chỉ giúp bạn giữ cho mã của mình gọn gàng, mà còn giúp bạn phát triển tư duy thiết kế và phát triển phần mềm một cách hệ thống.

Trong thế giới thực, OOP rất thực dụng và đa dụng. Nó tạo ra các đoạn code linh hoạt, có thể mở rộng và bảo trì được. Hãy bắt đầu bằng cách hiểu rõ những nguyên tắc cơ bản của OOP và Python, sau đó bạn sẽ thấy mình không chỉ trở thành một lập trình viên giỏi hơn, mà còn là một nhà phát triển tốt hơn và một cuộc đời tốt hơn.

1. Cơ Sở Lý Thuyết OOP:

Vẫn phải mở sách ra một chút.

OOP không phải là cái mới, nhưng nó chưa bao giờ lỗi thời. Hãy nghĩ về OOP nó như là cách mà bạn biến cách tư duy của con người thành code. Con người tư duy mọi thứ trong cuộc sống theo dạng "object": con người, bữa cơm, ô tô, con mèo ...
Giả sử lấy việc gọi một cốc cafe làm ví dụ để so sánh:
Bạn sẽ bước vào quán, order một cốc Americano.

OOP POP
tôi.bước_vào(quán_cafe)

tôi.gọi_đồ(Americano)
bước_vào(tôi,quán_cafe)

gọi_đồ(tôi,Americano)

OOP (Object Oriented Programming): Hướng đối tượng

POP (Procedure Oriented Programming): Hướng thủ tục

Bạn thấy chứ, OOP khiến cho việc coding dẽ hiểu, dễ ngấm hơn với tư duy của Human. Sau đó OOP còn được phát triển thêm một số đặc tính để khiến cho việc xây dựng hệ thống hoàn chỉnh, có thể mở rộng và bảo trì được.

Đừng bao giờ coi thường sức mạnh của lý thuyết. Hiểu biết vững chắc về những thứ cơ sở sẽ là nền tảng cho bạn không chỉ để giải quyết vấn đề trước mắt, mà còn để giải thích, phản biện kiến trúc của các hệ thống phức tạp. Khi bạn nắm các kiến thức cơ sở một cách chặt chẽ thì nó giống như việc bạn có "nội lực", khi này các ngôn ngữ và thư viện lập trình chỉ là "chiêu thức".

2. Tại Sao Là Python?
Khi nói về OOP căn bản thì Java và C# (hai ngông ngữ thuần hướng đối tượng) sẽ là ưu tiên để học, vì với hai ngôn ngữ này việc bạn code OOP là bắt buộc. Còn với Python thì bạn có thể code theo cả OOP và POP.
Việc tôi tựa chọn Python có 3 lý do:

  1. Python rất dễ học và trào lưu về Data và AI khiến cho hầu hết các Developer đều biết sử dụng ngôn ngữ này.
  2. các tài liệu về Python và OOP không giải thích kỹ về bản chất. Nó giống như việc bạn phải biết lý thuyết về OOP rồi, và tài liệu đó sẽ hướng dẫn bạn cách code OOP với Python thôi.
  3. Ngôn ngữ Python kết hợp rất tốt với OOP, có nhiều thư viện phổ biến sử dụng phương pháp này như: Tensorflow, Pandas, Numpy, Pytorch, Airflow ... Nắm rõ OOP với Python sẽ khiến cho bạn đọc hiểu, sử dụng thư viện một cách hiệu quả hơn.

  1. Các khái niệm của OOP
Ví dụ trực quan về OOP trong python

Để bắt đầu thưc hành với OOP thì chúng ta cần nắm rõ một số khái niệm, các khái niệm này là cốt lõi và sẽ gặp lặp đi lặp lại trong suốt quá trình bạn coding. Nói tóm lại, biết về khái niệm sẽ giúp cho bạn có chung ngôn ngữ để có thể nói chuyện với các lập trình viên hàng đầu.

Và không biết nó ? Bạn bị layoff
  • Class: Đây chính là khuôn mẫu thiết kế ô tô. Mỗi Class ô tô đặc tả một dạng xe cụ thể với các đặc điểm riêng. Không có thiết kế kỹ lưỡng, bạn sẽ không thể tạo ra một chiếc xe đúng chuẩn.
  • Object: Một thể hiện cụ thể của Class. Là chiếc xe cụ thể, có thể chạy được. Chiếc xe được xây dựng/lắp ráp/ khởi tạo từ một Bản Thiết Kế/Class xe cụ thể. Trong lập trình, về mặt vật lý thì object là class đã được khởi tạo, nó chiếm một phần bộ nhớ và được gắn vào một địa chỉ ô nhớ cụ thể.
object có thể gọi là instance hoặc thực thể, các từ này có thể được nói ra bởi các lập trình viên khác nhau tùy vào tài liệu họ được đọc. Với Python thì nó thường được dùng từ là instance
  • Method: Method là các phương thức/hàm/hành động mà một chiếc xe có thể thực hiện.
Method còn có thể được gọi là function hoặc là hàm
Vì đây là hành động, nên khi đặt tên tên hàm nên được đặt là một động từ. Ví dụ:
khi muốn xe rẽ trái ta sẽ call hàm là car.left() → Sh*t ! Đây là một cái tên tệ hại.
Nhớ rằng: nó là động từ nên thế car.turn_left() → đây là cái tên tốt, nên làm như vậy.
  • Attribute: Là các đặc điểm của xe, như màu sắc, động cơ, kích thước. Mỗi thuộc tính làm nổi bật đặc thù của mỗi mẫu xe.
Attribute đôi khi còn được gọi là property hoặc thuộc tính, đặc tính. Trong Python thì nó là property
  1. Các đặc tính của OOP
    1. Kế Thừa (Inheritance): Trong ngành công nghiệp ô tô, kế thừa giống như việc phát triển một mẫu xe mới dựa trên một mẫu xe đã có. Ví dụ, một mẫu SUV mới có thể kế thừa nền tảng khung gầm hoặc động cơ từ mẫu SUV trước đó, đồng thời cải tiến thêm tính năng mới.
Khi code nhiều người quên mất ứng dụng tuyệt vời này của OOP. Khi cần sửa gì đó cho một trường hợp rất cụ thể, họ sửa thẳng vào code của class cha với một cái "if" rất thô bỉ, việc này gây ra dư thừa, giảm performance và tăng chi phí bảo trì.
Việc nên làm khi này với họ là kế thừa class cha và overwrite một method cụ thể nào đó.
    1. Đóng Gói (Encapsulation): Đóng gói trong sản xuất ô tô giống như việc giữ kín các thông tin thiết kế và công nghệ sản xuất. Các chi tiết kỹ thuật của động cơ hoặc hệ thống truyền động được giữ bí mật, ngăn chặn sự sao chép không phép. Nôm na là sẽ có những mốc bảo mật của một class OOP:
      1. private: chỉ được access/call trong class đó
      1. protect: có thể được access/call trong class con kế thừa từ class đó
      2. public: có thể được call/access từ bên ngoài.
Đặc tính này được implement trong python bằng cách đặt tên function/attribute có tiền tố là dấu "_", với một "" là protect, hai "__" là private.
VD:
def __private_function(self):
"""This is private function"""
-----------------------------
Nhưng ứng dụng của tính đóng gói không nhiều trong Python. Không giống với C# hay Java, với mặc định của Python thì tất cả method/attribute là public.
    1. Đa Hình (Polymorphism): Đa hình ứng dụng trong ô tô giống như việc một mẫu xe cơ bản có thể có nhiều phiên bản khác nhau, như phiên bản tiêu chuẩn, thể thao, hoặc sang trọng, mỗi loại đều có các tính năng và thiết kế nội thất riêng biệt nhưng vẫn giữ nguyên khung xe cơ bản.
Đây là ứng dụng của "interface", nhưng nó rất ít, gần như không có ứng dụng trong python. Với python thì bạn không tạo Interface mà bạn sẽ tạo trực tiếp Abstract class.
    1. Trừu Tượng (Abstraction): Trong lĩnh vực sản xuất ô tô, trừu tượng giống như việc tập trung vào các tính năng quan trọng của một mẫu xe mà không cần phải quan tâm đến các chi tiết phức tạp bên trong. Ví dụ, khi thiết kế một xe, các kỹ sư có thể tập trung vào hiệu suất, an toàn và tiện nghi mà không cần phải lo lắng về cách thức chi tiết của từng bộ phận như động cơ hoặc hệ thống treo. Điều này giúp đơn giản hóa quá trình thiết kế và cho phép tập trung vào những yếu tố quan trọng nhất của sản phẩm.
Đây là đặc tính rất tuyệt vời khi kết hợp với tính kế thừa. Nó sẽ để cho những developer khác biết đây là function abstract và họ sẽ cần implement cụ thể cách hoạt động của funtion đó.

5. Kinh Nghiệm và Mẹo Lập Trình:

  • Dùng kế thừa thay vì tùy tiện sửa code ở class cha
  • Khi bắt đầu dự án thì các Abstract class nên được thiết kế bởi team lead/tech lead. Và việc đảm bảo và hướng dẫn team sử dụng class này là trách nhiệm của leader.
  • OOP sẽ dễ code và dễ implement các hệ thống phức tạp, nhưng đổi lại OOP có thể gây ra performance không tốt nếu không được thiết kế tốt.
  • Nên ứng dụng OOP theo ít nhất một Design Pattern cụ thể
  • Thay vì sử dụng Json/Dict để config hoặc lưu biến, hãy tạo class để config hoặc lưu biến.
Đừng lạm dụng dict trong Python
Dict work rất tệ với việc format code, đổi key, quản lý xem biến được sử dụng ở những đâu, không tương tác với code completetion ...
Tóm lại, nếu dict của bạn được sử dụng ở trong function/class khác, thì hãy tạo một class interface như thế này.

6. Tài Nguyên và Cộng Đồng:

Có nhiều tài nguyên mà bạn có thể học được coding OOP với Python. Nhưng để hiểu gốc vấn đề và nhận thức về code một cách hệ thống. Thì tôi highly recommend cuốn "Clean Code: A Handbook of Agile Software Craftsmanship" của Robert C. Martin

Clean Code: A Handbook of Agile Software Craftsmanship


7. Thư Viện Python và OOP:

Các thư viện thông dụng trong Python nếu bạn để ý thì những thư viện sau đây đều được implement theo style OOP. Đặc biệt với Keras hoặc Tensorflow, khi bạn thực hiện custom một Model hoặc Layer, chính là khi bạn đã ứng dụng tính kế thừa trong Python OOP

Keras- ví dụ kế thừa

8. Kết Luận:
Bạn nên bắt tay vào thử và ứng dụng việc code OOP với project sắp tới. Từ đó cảm nhận thấy hiệu quả rõ ràng của nó.
Nên dừng lại việc lạm dụng Jupyter notebook và các python script nhỏ lẻ trong dự án của bạn sớm nhất có thể.

  1. Bổ sung:

Nếu bạn vẫn đang code python bằng cách tạo các function riêng lẻ như ở ví dụ Pizza. Thì có lẽ bạn đang code theo style của hướng thủ tục, sau đây là một số so sánh của POP và OOP. Có thể so sánh này sẽ giúp bạn hiểu được OOP từ nền tảng POP có sẵn.

Tiêu Chí So Sánh Lập Trình Hướng Thủ Tục (POP) Lập Trình Hướng Đối Tượng (OOP)
Hướng Tiếp Cận Theo quy trình/cấu trúc Hướng đối tượng
Phương Pháp Top-down Bottom-up
Ưu Tiên Chính "Làm thế nào để hoàn thành nhiệm vụ" "Bảo mật dữ liệu"
Chia Nhỏ Chương Trình Chia thành các hàm Chia thành các đối tượng
Truy Cập Dữ Liệu Không có quy định truy cập Có quy định truy cập: "public", "private", "protected"
Đa Hình/Overloading Không hỗ trợ overloading Hỗ trợ overloading cho hàm, constructors và operators
Kế Thừa Không hỗ trợ kế thừa Hỗ trợ kế thừa trong ba hình thức: public, private và protected
Ẩn Dữ Liệu & Bảo Mật Không có cách hiệu quả để ẩn dữ liệu, dữ liệu không an toàn Dữ liệu được ẩn trong ba hình thức, tăng cường bảo mật
Chia Sẻ Dữ Liệu Dữ liệu toàn cục được chia sẻ giữa các hàm Dữ liệu được chia sẻ giữa các đối tượng qua các hàm thành viên
Friend Functions/Classes Không có khái niệm friend function Các lớp hoặc hàm có thể trở thành bạn của lớp khác với từ khóa "friend" (chỉ áp dụng trong C++)
Lớp Ảo/Chức Năng Ảo Không có khái niệm lớp ảo Có khái niệm chức năng ảo xuất hiện trong kế thừa
Ví Dụ C, VB, FORTRAN, Pascal C++, JAVA, VB.NET, C#.NET

Dưới đây là bảng so sánh giữa hai phương pháp:

Phương Pháp Ưu Điểm Nhược Điểm
OOP - Khuyến khích thiết kế mô-đun, giúp quản lý hệ thống phức tạp dễ dàng hơn.
- Cải thiện khả năng tái sử dụng code thông qua kế thừa và đa hình.
- Tăng cường bảo mật dữ liệu với đóng gói.
- Dễ dàng bảo trì và chỉnh sửa code hiện có.
- Có thể phức tạp hơn để hiểu và triển khai so với lập trình quy trình.
- Có thể yêu cầu nhiều bộ nhớ và sức mạnh xử lý hơn.
- Trong một số trường hợp, có thể dẫn đến code không hiệu quả.
POP - Đơn giản và dễ hiểu, đặc biệt với người mới bắt đầu.
- Phù hợp hơn cho xử lý nhiệm vụ tuyến tính và tuần tự.
- Thường yêu cầu ít bộ nhớ và sức mạnh xử lý hơn.
- Hạn chế về khả năng tái sử dụng code.
- Xử lý kém hơn đối với hệ thống phức tạp và quy mô lớn.
- Thiếu bảo mật dữ liệu do không có đóng gói.