thatnghiepcogivui
Junior Member
Em đã viết lại bài này gần đây, chỉnh sửa 1 số dễ hiểu hơn. Link ở đây ạ: https://viblo.asia/p/lap-trinh-huong-doi-tuong-trong-python-cho-nguoi-moi-3RlL5GYm4bB
Series JavaScript: https://viblo.asia/s/modern-javascript-PwlVmR8g45Z
Hay khi đi làm, mỗi người trong công ty đều có tên (name), tuổi (age), mức lương (salary) và phòng ban (department) khác nhau nhưng họ đều là nhân viên (employee).
Vậy để dễ quản lý, chúng ta coi employee là 1 class - tập hợp các employee có đặc điểm chung về properties (đều có name, age, salary, department) nhưng khác giá trị. Ví dụ employee A, employee B là hai objects thuộc class employee.
Method có thể được coi là các hành vi (behaviors) của object. Method thể truy cập vào các đặc tính (properties), và các methods khác của class mà nó thuộc về. Methods có thể nhận và trả về giá trị, hoặc chỉ thực hiện các hành động nào đó trên object của class.
Ví dụ object
Một Instance là một biến (variable) mà giữ địa chỉ bộ nhớ (memory address) của object đó. Ví dụ cho dễ hiểu thì:
Initializer được gọi tự động khi một object của class được tạo. Đây là một method đặc biệt giúp chúng ta xác định và gán giá trị cho các variables của instance. Tương tự các method khác, initializer cũng có thể có optional parameters (tham số mặc định).
Dưới đây là ví dụ khi objects của
Output
Chúng ta phải sử dụng class variable đúng cách vì như đã nói, chúng được chia sẻ cho tất cả các objects thuộc class và có thể thay đổi giá trị của class variable bằng cách sử dụng bất kỳ objects nào.
Dưới đây là ví dụ về sử dụng class variable
Output
Ở ví dụ trên, trong khi instance variable
Chúng ta đang lưu trữ tất cả các cầu thủ hiện đang chơi cho cùng một đội, nhưng mỗi cầu thủ trong đội phần lớn sẽ không cùng đội bóng cũ. Để tránh vấn đề này, triển khai chính xác cho ví dụ trên sẽ như sau:
Output
Bây giờ,
Output
Ở ví dụ trên, chúng ta đã khai báo class variable
Có 3 loại
1. Instance methods
2. Class methods
3. Static methods
Ở những phần code ở trên, chúng ta thấy từ khóa
Khi chúng ta tạo object employee1
Thì Python sẽ convert giúp chúng ta thành:
Và bên trong
Nó không nhất thiết phải được đặt tên là self, nó không phải là Python keyword, bạn có thể đặt nó là gì tùy thích, nhưng nó phải là parameter đầu tiên của initializer và method. Nếu không sẽ xảy ra lỗi:
Output
Output
Output
Output
Vì sự đặc biệt của static method, nó được dùng rất hạn chế, khi cần sử dụng utility function mà không cần tham chiếu tới object hay class thì chúng ta có thể tạo ra chúng, việc gọi chúng thông qua
Ví dụ về public attributes
Ouput
Ở phần code trên, properties
Nhưng trong Python, không có sự tồn tại của "private". Tuy nhiên, một quy ước đang được hầu hết các developer sử dụng là chúng ta có thể tạo private attributes bằng cách sử dụng tiền tố (prefix)
Phân biệt giữa single leading underscore
Hãy xem đoạn code dưới đây:
Single leading underscore
Double leading underscores
Tại sao ở trên mình nói trong Python, không có private, đoạn dưới sẽ giải thích.
Private properties trong Python
Đầu tiên chúng ta xem khi truy cập vào một private property bằng cách thông thường sẽ như thế nào nhé:
Output
Private methods trong Python
Truy cập vào private properties một cách thông thường sẽ gây lỗi, vậy với private methods thì sao?
Output
Tương tự như trên,
Vậy làm sao để truy cập private attributes trong main code
Vậy tại sao ở trên nói trong Python không có sự tồn tại của "private"?
Nếu cảm thấy thật sự cần thiết sử dụng
Output
Không có lỗi gì, chúng ta đã truy cập được
Series JavaScript: https://viblo.asia/s/modern-javascript-PwlVmR8g45Z
Object-oriented Programming trong Python
Object-oriented Programming (hay OOP) là một mô hình lập trình phụ thuộc vào kiến trúc của object và class.Các khái niệm cơ bản trong OOP
Dưới đây là những khái niệm cơ bản trong lập trình hướng đối tượng:- Đặc tính (properties)
- Phương thức (method)
- Lớp (class)
- Đối tượng (object)
- Thực thể (instance)
Hay khi đi làm, mỗi người trong công ty đều có tên (name), tuổi (age), mức lương (salary) và phòng ban (department) khác nhau nhưng họ đều là nhân viên (employee).
Vậy để dễ quản lý, chúng ta coi employee là 1 class - tập hợp các employee có đặc điểm chung về properties (đều có name, age, salary, department) nhưng khác giá trị. Ví dụ employee A, employee B là hai objects thuộc class employee.
Method có thể được coi là các hành vi (behaviors) của object. Method thể truy cập vào các đặc tính (properties), và các methods khác của class mà nó thuộc về. Methods có thể nhận và trả về giá trị, hoặc chỉ thực hiện các hành động nào đó trên object của class.
Ví dụ object
Employee
sẽ có methods như tính thuế thu nhập dựa trên lương (tax()
), hay cung cấp thông tin của employee (employee_info()
).Một Instance là một biến (variable) mà giữ địa chỉ bộ nhớ (memory address) của object đó. Ví dụ cho dễ hiểu thì:
- Class là một bản thiết kế chi tiết cho ngôi nhà
- Object là tất cả những ngôi nhà được xây dựng dựa trên bản thiết kế đó
- Instance là một căn nhà cụ thể (nhà của ông A, của ông B)
Khởi tạo object trong Python
Trong Python, ta có initializer, như tên gọi của nó, là một method được dùng để khởi tạo một object của một class. Method này cũng tương tự các method khác nhưng khác ở chỗ initializer thì đã được đặt tên là:__init__
.Initializer được gọi tự động khi một object của class được tạo. Đây là một method đặc biệt giúp chúng ta xác định và gán giá trị cho các variables của instance. Tương tự các method khác, initializer cũng có thể có optional parameters (tham số mặc định).
Dưới đây là ví dụ khi objects của
Employee
class được tạo, một với tham số mặc định, một với tham số của chúng ta truyền vào.
Python:
class Employee:
# Khai báo properties và gán giá trị cho chúng
def __init__(self, ID = None, salary = 0, department = None):
self.ID = ID
self.salary = salary
self.department = department
# Tạo một object của class Employee với các tham số mặc định
steve = Employee()
# Tạo một object của class Employee với tham số của chúng ta
mark = Employee("3789", 2500, "Human Resources")
# In ra properties của mark và steve
print("steve")
print("ID :", steve.ID)
print("Salary :", steve.salary)
print("Department :", steve.department)
print("mark")
print("ID :", mark.ID)
print("Salary :", mark.salary)
print("Department :", mark.department)
Code:
steve
ID : None
Salary : 0
Department : None
mark
ID : 3789
Salary : 2500
Department : Human Resources
Class variables và instance variables
Trong Python, properties được chia làm 2 loại:- Class variables
- Instance variables
Class variables trong Python
Tất cả các objects của class đều được phép truy cập và thay đổi giá trị của class variable. Khi thay đổi giá trị của class variable thì giá trị của property này sẽ thay đổi trong tất cả các object của class.Instance variables
Instance variables là của riêng với mỗi objects. Sự thay đổi ở instance variables của object nào thì chỉ ảnh hưởng đến object đó.Khai báo class variable và instance variable
Class variables được khai báo ngoàiinitializer
và instance variables được khai báo trong scope của initializer
Python:
class Player:
team_name = 'Manchester City' # class variable
def __init__(self, name):
self.name = name # instance variable
Dưới đây là ví dụ về sử dụng class variable
sai
.
Python:
class Player:
team_name = 'Manchester City' # class variables
former_teams = [] # class variables
def __init__(self, name):
self.name = name # instance variables
# Tạo 2 objects thuộc class Player
p1 = Player("David Silva")
p2 = Player("Yaya Toure")
# Dùng built-in method `append` để thêm giá trị vào variable `former_teams`
p1.former_teams.append('Celta Vigo') # dùng sai class variable
p2.former_teams.append('Barcelona') # dùng sai class variable
# In properties của các objects
print("Name:", p1.name)
print("Team Name:", p1.team_name)
print(p1.former_teams)
print("Name:", p2.name)
print("Team Name:", p2.team_name)
print(p2.former_teams)
Code:
Name: David Silva
Team Name: Manchester City
['Celta Vigo', 'Barcelona']
Name: Yaya Toure
Team Name: Manchester City
['Celta Vigo', 'Barcelona']
name
là riêng biệt cho mỗi object thuộc Player
class. Thì class variable former_teams
, có thể truy cập bởi tất cả các object thuộc class nên nó đã được cập nhật giá trị 2 lần.Chúng ta đang lưu trữ tất cả các cầu thủ hiện đang chơi cho cùng một đội, nhưng mỗi cầu thủ trong đội phần lớn sẽ không cùng đội bóng cũ. Để tránh vấn đề này, triển khai chính xác cho ví dụ trên sẽ như sau:
Python:
class Player:
team_name = 'Manchester City' # class variables
def __init__(self, name):
self.name = name # instance variables
self.former_teams = [] # instance variables
# Tạo 2 objects thuộc class Player
p1 = Player("David Silva")
p2 = Player("Yaya Toure")
# Dùng built-in method `append` để thêm giá trị vào variable `former_teams`
p1.former_teams.append('Celta Vigo') # dùng sai class variable
p2.former_teams.append('Barcelona') # dùng sai class variable
# In properties của các objects
print("Name:", p1.name)
print("Team Name:", p1.team_name)
print(p1.former_teams)
print("Name:", p2.name)
print("Team Name:", p2.team_name)
print(p2.former_teams)
Code:
Name: David Silva
Team Name: Manchester City
['Celta Vigo']
Name: Yaya Toure
Team Name: Manchester City
['Barcelona']
former_teams
đã là của riêng của mỗi object Player
, và sẽ được truy cập bởi object đó mà thôi.Một ví dụ khác về sử dụng class variables
Python:
class Player:
team_name = 'Manchester City' # class variables
team_members = [] # class variables
def __init__(self, name):
self.name = name # instance variables
self.former_teams = [] # instance variables
# sử dụng method append để mỗi lần tạo ra object Player
# thì sẽ tự thêm `name` của player đó vào class variable team_members
self.team_members.append(self.name)
p1 = Player('David Silva')
p2 = Player('Yaya Toure')
print("Team Name:", p1.team_name)
print("Team Members:")
print(p1.team_members)
print("")
print("Name:", p2.name)
print("Team Members:")
print(p2.team_members)
Code:
Team Name: Manchester City
Team Members:
['David Silva', 'Yaya Toure']
Name: Yaya Toure
Team Members:
['David Silva', 'Yaya Toure']
team_members
, một list được chia sẻ với tất cả các object thuộc Player
class. Mỗi object Player
được tạo ra, name
của object sẽ được thêm vào list team_members
, chúng ta có thể thấy p1
và p2
đều có thể truy cập vào team_members
.Methods trong Python
Trong phần này, chúng ta sẽ xem về chuyện tương tác giữaproperties
và các objects
. Đây là lúc methods
xuất hiện, methods
là một nhóm các statements (câu lệnh) thực hiện một số hoạt động (operations) và có thể trả về (return) hoặc không trả về một kết quả.Có 3 loại
method
trong Python:1. Instance methods
2. Class methods
3. Static methods
Chúng ta sẽ gọi method cho instance method vì nó thường được sử dụng nhất.
Instance Method
self
Ở những phần code ở trên, chúng ta thấy từ khóa self
hay được xuất hiện, đây là lúc giải thích về nó. Đầu tiên, chúng ta cùng xem cách self
argument hoạt động thông qua phần code bên dưới. Chúng ta có một class Employee
như sau:
Python:
class Employee:
def __init__(self, ID=None, department=None):
self.ID = ID
self.department = department
Python:
employee1 = Employee("Furaudorin", "FAA")
Python:
Employee.__init__(employee1, "Furaudorin", "FAA")
initializer
sẽ thực thi như sau:
Code:
employee1.ID = "Furaudorin"
employee1.department = "FAA"
self
parameter là một tham chiếu đến object hiện tại của class, và được sử dụng để truy cập các variables và methods thuộc về class.Nó không nhất thiết phải được đặt tên là self, nó không phải là Python keyword, bạn có thể đặt nó là gì tùy thích, nhưng nó phải là parameter đầu tiên của initializer và method. Nếu không sẽ xảy ra lỗi:
Python:
class Employee:
def __init__(ID=None, department=None):
ID = ID
department = department
steve = Employee(3789, "Human Resources")
print(steve.ID)
print(steve.department)
Code:
Traceback (most recent call last):
File "/Users/abre/Desktop/object-oriented-trong-python/test.py", line 7, in <module>
steve = Employee(3789, "Human Resources")
TypeError: __init__() takes from 0 to 2 positional arguments but 3 were given
Class Method trong Python
Class methods làm việc với class variables và có thể truy cập bằng cách sử dụngClass name
thay vì object. Class method có thể được truy cập bằng cách sử dụng tên class mà không cần tạo class object.Syntax của class method
Để khai báo một class method, chúng ta sử dụng@classmethod
decorator. cls
parameter được sử để refer tới class cũng như chúng ta sử dụng self
để refer tới object của class. Bạn cũng có thể sử dụng bất cứ tên nào để thay thế cls
, nhưng vì convention, chúng ta sẽ sử dụng cls
.Tất cả class methods phải có ít nhất 1 parameter, làcls
.
Ví dụ class method
Python:
class Player:
team_name = 'Manchester City' # class variable
def __init__(self, name):
self.name = name # instance variable
# define class method get_team_name sử dụng @classmethod decorator
@classmethod
def get_team_name(cls):
return cls.team_name
print(Player.get_team_name())
Code:
Manchester City
Static methods trong Python
Static method là method được dùng chỉ giới hạn ở phạm vi class. Chúng không tương tác với class variable hay instance variable. Chúng được sử dụng như các utility functions bên trong class.Static methods có thể được truy cập bằng cách sử dụng class name hoặc object name
Syntax của static method
Để khai báo static method, chúng ta sử dụng@staticmethod
decorator. Vì nó không được sử dụng để tham chiếu đến object hay class nên chúng ta không sử dụng self
hay cls
argument. Static methods không biết bất cứ thứ gì về state của class.
Python:
class Player:
team_name = 'Manchester City' # class variable
def __init__(self, name):
self.name = name # instance variable
@staticmethod
def demo():
print("I am a static method.")
p1 = Player('lol')
p1.demo()
Player.demo()
Code:
I am a static method.
I am a static method.
Ví dụ static method
Giả sử chúng ta có 1 classBodyInfo
chứa thông tin về cân nặng và chiều cao của một người. Chúng ta có thể tạo một static method để tính BMI cho bất kỳ cân nặng
và chiều cao
nào được truyền vào, ví dụ:
Python:
class BodyInfo:
@staticmethod
def bmi(weight, height):
return weight / (height**2)
weight = 75
height = 1.8
print(BodyInfo.bmi(weight, height))
Code:
23.148148148148145
class name
hay class object
giúp chúng ta hiểu rõ về bối cảnh sử dụng cũng như chức năng của chúng.Access Modifiers trong Python
Chúng ta cùng tìm hiểu vềprivate
, public
attributes trong PythonPublic attributes trong Python
Trong Python, tất cả attributes mặc định là public. Nếu chúng ta muốn chỉ định một method hay variables nào đó không nên được coi làpublic
, chúng ta phải khai báo nó là private
.Ví dụ về public attributes
Python:
class Employee:
def __init__(self, ID, salary):
# các properties này đều là public
self.ID = ID
self.salary = salary
# method này là public
def display_id(self):
print("ID:", self.ID)
steve = Employee(3789, 2500)
steve.display_id()
print(steve.salary)
Code:
ID: 3789
2500
ID
, salary
và method display_id()
là public nên chúng ta có thể truy cập ở trong cũng như ở ngoài class.Private attributes trong Python
Mục đích sử dụng private attributes là để ẩn nó khỏi người dùng và các class khác.Nhưng trong Python, không có sự tồn tại của "private". Tuy nhiên, một quy ước đang được hầu hết các developer sử dụng là chúng ta có thể tạo private attributes bằng cách sử dụng tiền tố (prefix)
__
.Phân biệt giữa single leading underscore
_
và double leading underscores __
trong PythonHãy xem đoạn code dưới đây:
Python:
class MyClass():
def __init__(self):
self.__superprivate = "Hello"
self._semiprivate = ", world!"
mc = MyClass()
Python:
print(mc._semiprivate)
Code:
, world!
Python:
print(mc.__superprivate)
Code:
Traceback (most recent call last):
File "/Users/abre/Desktop/object-oriented-trong-python/test.py", line 10, in <module>
print(mc.__superprivate)
AttributeError: 'MyClass' object has no attribute '__superprivate'
_
đơn giản chỉ là quy ước, một cách để lập trình viên chỉ ra rằng attributes này là private, không nên truy cập ngoài class này.Double leading underscores
__
thì có ý nghĩa thật sự, trình thông dịch Python sẽ thay thế __
bằng tên class mà gọi nó để đảm bảo attributes này sẽ không trùng với attributes khác có cùng tên trong class khác.Tại sao ở trên mình nói trong Python, không có private, đoạn dưới sẽ giải thích.
Private properties trong Python
Đầu tiên chúng ta xem khi truy cập vào một private property bằng cách thông thường sẽ như thế nào nhé:
Python:
class Employee:
def __init__(self, ID, salary):
self.ID = ID
self.__salary = salary # salary là một private property
steve = Employee(3789, 2500)
print("ID:", steve.ID)
print("Salary:", steve.__salary) # dòng này sẽ gây lỗi
Code:
ID: 3789
Traceback (most recent call last):
File "main.py", line 9, in <module>
print("Salary:", steve.__salary) # this will cause an error
AttributeError: 'Employee' object has no attribute '__salary'
ID
là public property nhưng __salary
là private property nên không thể truy cập bên ngoài class.Private methods trong Python
Truy cập vào private properties một cách thông thường sẽ gây lỗi, vậy với private methods thì sao?
Python:
class Employee:
def __init__(self, ID, salary):
self.ID = ID
self.__salary = salary # salary là một private property
def display_salary(self): # display_salary là một public method
print("Salary:", self.__salary)
def __display_id(self): # display_id là một private method
print("ID:", self.ID)
steve = Employee(3789, 2500)
steve.display_salary()
steve.__display_id() # dòng này sẽ gây lỗi
Code:
Salary: 2500
Traceback (most recent call last):
File "main.py", line 15, in <module>
steve.__display_id() # this will generate an error
AttributeError: 'Employee' object has no attribute '__display_id'
__display_id
là private method, không thể truy cập được từ bên ngoài class.Vậy làm sao để truy cập private attributes trong main code
Vậy tại sao ở trên nói trong Python không có sự tồn tại của "private"?
Nếu cảm thấy thật sự cần thiết sử dụng
private
property hoặc method, chúng ta... vẫn có thể. Ta sử dụng prefix _<ClassName>
để truy cập, ví dụ như:
Python:
class Employee:
def __init__(self, ID, salary):
self.ID = ID
self.__salary = salary # salary là một private property
steve = Employee(3789, 2500)
print(steve._Employee__salary) # truy cập private property
Code:
2500
salary
của steve
và in giá trị của nó ra, tương tự ta có thể dùng cách trên để truy cập private methods.
Last edited: