Hướng dẫn python class attributes
Mỗi class thường chứa hai loại thành viên quan trọng: thành phần chứa dữ liệu và thành phần xử lý dữ liệu. Trong Python, thành phần chứa dữ liệu được gọi là attribute. Có thể xem attribute của Python tương tự như biến của class trong các ngôn ngữ như C++/Java hay C#. Show Python phân biệt hai loại attribute: instance attribute gắn với object và class attribute gắn với chính class. Ví dụ về sử dụng attribute trong PythonChúng ta bắt đầu với một ví dụ. Tạo module book.py và viết code như sau: class Book: """A class for e-book""" b = Book() b.title = 'Python programming' b.authors = 'Donald Trump' b.year = 2020 print(b.title, b.authors, b.year) # kết quả là 'Python programming Donald Trumo 2020' b2 = Book() print(b2.title) # lỗi, không có attribute title trong object b2 Bạn có thể thấy rất nhiều điều lạ ở đây. Dễ thấy nhất là class Book hoàn toàn trống trơn. Trong class này chỉ có mỗi docstring. Tuy nhiên sau khi tạo object b, bạn lại có thể dùng phép toán truy xuất phần tử (dot notation) Khi bạn tạo object b2 và thử truy xuất giá trị title (b2.title) thì lại gặp lỗi “không tìm thấy attribute title trong object b2”. title, authors, year được gọi là những attribute của object b (nhưng không phải là attribute của b2). Như vậy, trong Python, attribute là những biến có thể chứa giá trị đặc trưng cho một object. Nó được tạo hoàn toàn độc lập với khai báo class (không cần chỉ định trong khai báo class). Một cách chính xác hơn, biến này được gọi là instance attribute (do liên quan đến object). Giờ hãy cập nhật class class Book: """A class for e-book""" def __init__(self, title: str, authors: str = '', publisher: str = '', year: int = 2020, edition: int = 1): """Hàm tạo của class""" self.title = title self.authors = authors self.publisher = publisher self.year = year self.edition = edition def to_string(self, brief = True): """Get the infor and make a formated string""" if brief: return f"{self.title} by {self.authors}" else: return f"{self.title} by {self.authors}, {self.edition} edition, {self.publisher}, {self.year}" def print(this, brief = False): """Print the book infor""" print(this.to_string(brief)) # sử dụng class Book b1 = Book('Tự học lập trình Python') b1.authors = 'Nhật Linh' b1.publisher = 'Tự học ICT' b1.year = 2021 b1.print() b2 = Book('Python programming', 'Trump D.', 'The White house', 2020) print(b2.title, b2.authors) Trong trường hợp này chúng ta tạo attribute bên trong hàm tạo của class. Bạn có thể thấy rằng giờ cả b1 và b2 đều có chung tổ hợp attribute title, authors, publisher, year và edition. Giờ những biến này được gọi là những instance attribute của class book. Instance attributeTrong Python, biến thành viên của class được gọi là instance attribute. Đây là các giá trị đặc trưng cho từng object. Ví dụ, class book xác định rằng, tất cả sách được đặc trưng bởi tổ hợp giá trị của tiêu đề, tác giả, nhà xuất bản, năm xuất bản và lần tái bản. Vậy, cuốn sách thứ nhất có giá trị tổ hợp là ‘Tự học lập trình Python’ của tác giả ‘Nhật Linh’, do ‘Tự học ICT’ xuất bản năm 2020 và là lần xuất bản đầu tiên. Tổ hợp giá trị này đặc trưng cho riêng 1 cuốn sách (object). Cuốn sách khác sẽ có tổ hợp giá trị khác. Khai báo instance attributeTrong class book, các lệnh tạo (và gán giá trị) biến thành viên của class phải viết trong hàm tạo như sau: def __init__(self, title: str, authors: str = '', publisher: str = '', year: int = 2020, edition: int = 1): """Hàm tạo của class""" self.title = title self.authors = authors self.publisher = publisher self.year = year self.edition = edition Nếu bạn xuất phát từ C++, Java hay C# sẽ thấy cách tạo biến thành viên trong Python hơi khác biệt:
Trong Python, biến self (hay bất kỳ tên tham số nào) đứng đầu trong danh sách tham số của __init__ sẽ trỏ tới object vừa tạo (bởi magic method __new__()). Phép toán truy xuất thành viên (dấu chấm) trên object sử dụng một định danh mới và phép gán sẽ tự động tạo ra một biến thành viên. Tên biến thành viên được đặt theo quy tắc đặt định danh chung của Python, cũng như theo quy ước đặt tên của biến (cục bộ và toàn cục). Như vậy, Tất cả các tham số còn lại của __init__() chính là để cung cấp giá trị ban đầu cho các biến thành viên. Như trong ví dụ 1 bạn đã thấy, attribute không nhất thiết phải khai báo trong hàm tạo. Bạn có thể khai báo attribute sau khi tạo object. Chỉ có điều, khi này attribute đó chỉ tồn tại
trên object cụ thể đó. Nếu bạn tạo ra object mới, nó sẽ không có attribute như object trước đó. Truy xuất instance attributeVới các instance attribute tạo ra như trên, bạn có thể truy xuất nó qua tên object trong code ở ngoài class như sau: b3 = Book('') b3.title = 'Tự học lập trình Python' b3.authors = 'Nhật Linh' b3.publisher = 'Tự học ICT' b3.year = 2021 b3.edition = 2 Việc truy xuất này là hai chiều, nghĩa là có thể gán giá trị hoặc đọc giá trị. Đối với code ở bên trong class, cách truy cập là tương tự. Hãy xem phương thức to_string(): def to_string(self, brief = True): """Get the infor and make a formated string""" if brief: return f"{self.title} by {self.authors}" else: return f"{self.title} by {self.authors}, {self.edition} edition, {self.publisher}, {self.year}" Tạm thời chúng ta chưa trình bày kỹ về phương thức này. Hãy nhìn cách sử dụng biến title, authors, edtion, publisher và year thông qua tham số self: Bạn không được viết
trực tiếp tên attribute mà bắt buộc phải thông qua biến self. Nó không có gì khác biệt so với khi truy xuất từ tên object bên ngoài class, cả về hình thức và bản chất. Tham số Class attributeHãy hình dung yêu cầu sau: khi xây dựng class Book, làm thế nào để theo dõi số lượng object đã được tạo ra? Logic đơn giản nhất là tạo ra một biến đếm. Mỗi khi tạo một object mới thì tăng giá trị của biến đếm. Nếu biến đếm và việc tăng giá trị của biến đếm nằm ngoài class thì rất đơn giản. Nhưng nếu chúng ta cần tích hợp logic này vào chính class thì làm như thế nào? Để ý thấy rằng, một biến đếm cho mục đích trên không thể phụ thuộc vào từng object. Nói cách khác, tất cả các object đều phải sử dụng chung một biến đếm. Để tăng giá trị khi tạo object, phép cộng phải được thực hiện trong constructor. Python cung cấp một công cụ cho những mục đích tương tự: class attribute. Hãy thay đổi class Book như sau: class Book: """A class for e-book""" count = 0 def __init__(self, title: str, authors: str = '', publisher: str = '', year: int = 2020, edition: int = 1): """Hàm tạo của class""" self.title = title self.authors = authors self.publisher = publisher self.year = year self.edition = edition self.__private = True Book.count += 1 Để ý dòng 4 có lệnh khởi tạo biến Class attribute là một biến gắn liền với chính class, có thể được truy xuất từ các object và có giá trị chung cho tất cả các object. Sự khác biệt giữa class attribute và instance attribute nằm ở chỗ: instance attribute gắn với từng object cụ thể và thể hiện trạng thái riêng của từng object; class attribute gắn với chính class và đặc trưng cho class, hoặc đặc trưng chung cho mọi object. Với biến count xây dựng như trên bạn có thể sử dụng nó thông qua tên class: b1 = Book('Lập trình hướng đối tượng với Python', 'Nhật Linh', 'Tự học ict', 2022, 2) print(Book.count) b2 = Book(title = 'Nhập môn lập trình Python', authors= 'Nhật linh', publisher= 'Tự học ICT') print(Book.count) b3 = Book('') print(b3.count) Do đặc điểm của class attribute là sử dụng chung trong các object khác nhau, bạn cũng có thể truy xuất giá trị của count thông qua tên object: Public, protected, private trong PythonTrong các ngôn ngữ hướng đối tượng truyền thống như C++, Java hay C#, mỗi thành viên thuộc về một trong các mức truy cập: Trong Python không có khái niệm về kiểm soát truy cập các thành viên như vậy. Hoặc cũng có thể nói rằng mặc định mọi thành viên của class trong Python đều là public. Nghĩa là code ngoài class có thể tự do truy cập các thành viên này. Để mô phỏng lại hiệu quả của việc kiểm soát truy cập, Python sử dụng loại kỹ thuật có tên gọi là xáo trộn tên (name mangling). Kỹ thuật này quy ước rằng:
Ví dụ, bạn có thể khai báo biến protected và private trong constructor của lớp Book như sau: self.__private = True # private instance attribute self._protected = False # protected instance attribute Thực ra, loại kỹ thuật này không làm thay đổi được việc truy cập thành viên của class. Nó đơn thuần là chỉ báo để lập trình viên và IDE biết ý định sử dụng của thành viên đó. Ví dụ, trong class Book như trên, thực tế biến Kết luậnTrong bài học này chúng ta đã xem xét cách sử dụng attribute – thành phần lưu trữ dữ liệu trong class Python. Python phân biệt hai loại attribute: instance attribute gắn với object, class attribute gắn với chính class. Instance attribute tương tự như biến thành viên của C++/Java/C#, còn class attribut tương tự như biến static của các ngôn ngữ này. Điểm khác biệt lớn trong Python là instance attribute khai báo trong hàm tạo, còn class attribute khai báo trực tiếp trong class. Đồng thời, các attribute trong Python không phân biệt mức truy cập (public, protected, private) mà sử dụng kỹ thuật name mangling với vai trò chỉ báo. + Nếu bạn thấy site hữu
ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để site có thể phát triển và phục vụ bạn tốt hơn. |