Một điều không thể tránh khỏi khi học Python là vấn đề về classmethods và staticmethods, đặc biệt là đối với những sinh viên đến từ nền tảng Java, nơi không có classmethods
Trong Python, chúng ta có thể định nghĩa chúng bằng cách sử dụng các bộ trang trí tương ứng của chúng. Dưới đây là một ví dụ không hữu ích lắm, tuy nhiên minh họa chúng trông như thế nào
class Number[]:
def __init__[self, value]:
self.value = value @classmethod
def sum[cls, value1, value2]:
return cls[value1+value2] def print[self]:
print[str[self.value]]
Sự khác biệt duy nhất giữa @classmethod và @staticmethod là trong @classmethod, lớp được liên kết với phương thức làm đối số đầu tiên [cls]. Điều này có nghĩa là có thể dễ dàng truy cập vào lớp, trong phương thức, thông qua đối số cls, thay vì phải sử dụng tên đầy đủ của lớp
Vì vậy, trong trường hợp phương thức sum[cls, value1, value2] của chúng ta, đối số cls sẽ là lớp Number, là lớp mà phương thức tồn tại trong đó
Nhưng bạn có thể nói. "Nó có lý, nhưng thêm một chút phức tạp khác không cần thiết, vì chúng ta chỉ có thể sử dụng tên lớp?"
Thay vào đó, hãy làm điều đó và không sử dụng @classmethod và xem điều gì sẽ xảy ra…
class Number[]:
def __init__[self, value]:
self.value = value @staticmethod
def sum[value1, value2]:
return Number[value1+value2] def print[self]:
print[str[self.value]]
Và điều này hoạt động, ngoại trừ khi chúng ta sử dụng thừa kế. Trong kế thừa, một lớp con [còn gọi là lớp con] kế thừa các phương thức của lớp cha
Nếu chúng ta tạo một lớp con của Số, nó sẽ chứa tất cả các phương thức Số và nó cũng có thể định nghĩa nhiều phương thức hơn của riêng mình
class Float[Number]:
# Skip defining an __init__ method, and it uses the same as Number # Skip defining the sum[] method, and it uses the same as Number # Skip defining the print method, and it uses the same as Number
# Or we could define our own print method for this class.
def print[self]:
# Prints the number with 2 decimal places
print["{:.2f}".format[self.value]]
Vì vậy, bây giờ chúng ta có thể gọi các phương thức như vậy
>>> n = Number[0.15647]
>>> n.print[]
0.15647
>>> f = Float[0.15647]
>>> f.print[]
0.15
Tuy nhiên, nếu chúng ta gọi Float. sum[], những điều tồi tệ bắt đầu xảy ra…
>>> f = Float.sum[0.11, 0.1593]
>>> f.print[] # This should only print 2 decimal places!
0.2693
phao. phương thức sum[value1, value2] đang thực sự trả về một thể hiện Number chứ không phải một thể hiện Float
Vì vậy, biến f của chúng tôi thực sự không phải là Số nổi, nó là Số. Khi chúng ta gọi f. print[] chúng ta đang gọi phương thức print[] từ lớp Number chứ không phải phương thức chúng ta đã ghi đè trong lớp Float của mình
Giải pháp là quay lại sử dụng @classmethod. Theo cách đó, chúng tôi sử dụng cls thay vì Số và cls luôn đề cập đến lớp mà chúng tôi đang gọi từ. Nếu chúng ta sử dụng Số. sum[10, 15], chúng ta sẽ lấy lại một thể hiện Number. Nếu chúng ta sử dụng Float. tổng [15. 474, 19. 232], chúng tôi sẽ lấy lại một phiên bản Float
Chỉ sử dụng @staticmethod khi bạn muốn đặt một phương thức bên trong một lớp có liên quan logic với lớp đó, nhưng không nhất thiết phải tương tác với bất kỳ trường hợp cụ thể nào
Ví dụ: tôi sẽ sử dụng các phương thức tĩnh khi xác định lớp cơ sở dữ liệu. Tôi sẽ định nghĩa một lớp Cơ sở dữ liệu có một vài phương thức tĩnh để chèn hoặc tìm dữ liệu từ cơ sở dữ liệu. Tôi không tạo các phiên bản Cơ sở dữ liệu chứa dữ liệu đó, nhưng các phương thức tìm và chèn có liên quan đến Cơ sở dữ liệu
Trong bài viết này, tôi sẽ chỉ cho bạn biết @staticmethod
và
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
0 là gì, tại sao và khi nào bạn nên sử dụng chúng. Bắt đầu nàoSự định nghĩaNếu bạn chưa biết trang trí là gì và nó hoạt động như thế nào, thì trước hết hãy đọc bài viết này
@staticmethod
@staticmethod
là một trình trang trí tích hợp xác định một phương thức tĩnh trong lớp trong Python. Một phương thức tĩnh không nhận lớp, cũng không phải đối tượng, các đối số cho dù nó được gọi bởi một thể hiện của một lớp hay bởi chính lớp đó
Đặc trưng
- Khai báo một phương thức tĩnh trong lớp
- Nó không thể có tham số
>>> norm_product = Supermarket.normalize_product_name["milk "]
2 hoặc
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'>>> norm_product = Supermarket.normalize_product_name["milk "]
3
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk' - Phương thức tĩnh không thể truy cập các thuộc tính lớp hoặc thuộc tính thể hiện
- Phương thức tĩnh có thể được gọi bằng cách sử dụng
>>> norm_product = Supermarket.normalize_product_name["milk "]
4 và cũng có thể sử dụng
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'>>> norm_product = Supermarket.normalize_product_name["milk "]
5
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk' - Nó có thể trả về một đối tượng của lớp
Ví dụ sau khai báo một phương thức tĩnh
class Supermarket:
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @staticmethod
def normalize_product_name[product]:
product = product.capitalize[].strip[]
return product
Ở trên, lớp
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
6 khai báo phương thức >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
7 là một phương thức tĩnh sử dụng trình trang trí @staticmethod
. Lưu ý rằng nó không thể có tham số >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
3 hoặc >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
2Phương thức tĩnh có thể được gọi bằng cách sử dụng
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
4 hoặc >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
5>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
@classmethod
class Supermarket:3 là một trình trang trí tích hợp xác định một phương thức lớp trong lớp trong Python. Một phương thức lớp chỉ nhận các đối số lớp. Phương thức lớp có thể được gọi bằng cách sử dụng
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print["product=" + cls.product]
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
4 hoặc >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
5Hàm
class Supermarket:3 là một thay thế của hàm
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print["product=" + cls.product]
class Supermarket:7. Nên sử dụng trình trang trí
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print["product=" + cls.product]
class Supermarket:3 thay vì chức năng vì nó chỉ là đường cú pháp
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print["product=" + cls.product]
Đặc trưng
- Khai báo một phương thức lớp
- Tham số đầu tiên phải là
>>> norm_product = Supermarket.normalize_product_name["milk "]
2, có thể được sử dụng để truy cập các thuộc tính của lớp
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk' - Phương thức lớp chỉ có thể truy cập các thuộc tính lớp chứ không thể truy cập các thuộc tính thể hiện
- Phương thức lớp có thể được gọi bằng cách sử dụng
>>> norm_product = Supermarket.normalize_product_name["milk "]
4 và cũng có thể sử dụng
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'>>> norm_product = Supermarket.normalize_product_name["milk "]
5
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk' - Nó có thể trả về một đối tượng của lớp
Ví dụ sau khai báo một phương thức lớp
class Supermarket:
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print["product=" + cls.product]
Ở trên, lớp
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
6 chứa thuộc tính lớp >>> Supermarket.get_product[]
'product=Milk'
>>> obj = Supermarket[]
>>> obj.get_product[]
'product=Milk'
3 và thuộc tính thể hiện >>> Supermarket.get_product[]
'product=Milk'
>>> obj = Supermarket[]
>>> obj.get_product[]
'product=Milk'
4. Phương thức >>> Supermarket.get_product[]
'product=Milk'
>>> obj = Supermarket[]
>>> obj.get_product[]
'product=Milk'
5 được trang trí bằng trình trang trí class Supermarket:3 làm cho nó trở thành một phương thức lớp, có thể được gọi bằng cách sử dụng
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print["product=" + cls.product]
>>> Supermarket.get_product[]
'product=Milk'
>>> obj = Supermarket[]
>>> obj.get_product[]
'product=Milk'
7. Lưu ý rằng tham số đầu tiên của bất kỳ phương thức lớp nào phải là >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
2 có thể được sử dụng để truy cập các thuộc tính của lớp. Bạn có thể đặt bất kỳ tên nào cho tham số đầu tiên thay vì >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
2Phương thức lớp có thể được gọi bằng cách sử dụng
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
4 hoặc >>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
5>>> Supermarket.get_product[]
'product=Milk'
>>> obj = Supermarket[]
>>> obj.get_product[]
'product=Milk'
Nhưng trong phương thức lớp, bạn không thể sử dụng thuộc tính thể hiện
class Supermarket:
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print[f"product={cls.product}, age={cls.best_before}"]
>>> Supermarket.get_product[]
AttributeError: type object 'Supermarket' has no attribute 'best_before'
Khi nào bạn nên sử dụng các phương thức tĩnh?
1. Nhóm chức năng tiện ích cho một lớp
Các phương thức tĩnh có trường hợp sử dụng hạn chế bởi vì, giống như các phương thức lớp hoặc bất kỳ phương thức nào khác trong một lớp, chúng không thể truy cập các thuộc tính của chính lớp đó
Tuy nhiên, khi bạn cần một hàm tiện ích không truy cập bất kỳ thuộc tính nào của một lớp, nhưng có nghĩa là nó thuộc về lớp, chúng ta sử dụng các hàm tĩnh
Ví dụ: bạn đã thêm chức năng thay đổi định dạng tốt nhất trước ngày
from datetime import datetime
class Supermarket:
def __init__[self, product, best_before]:
self.best_before = "2022-05-18"
self.product = "Milk"
@staticmethod
def change_date_format[best_before]:
best_before = datetime.strptime[best_before, "%Y-%m-%d"]
best_before = best_before.strftime["%d-%m-%Y"]
return best_before
>>> Supermarket.change_date_format["2022-08-06"]
'06-08-2022'
Đây là một phương thức tĩnh vì nó không cần truy cập bất kỳ thuộc tính nào của chính
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
6 và chỉ yêu cầu các tham số2. Có một triển khai duy nhất
from datetime import datetime
class Supermarket:
def __init__[self, product, best_before]:
self.best_before = best_before
self.product = product
def get_best_before_date[self]:
return self.best_before
@staticmethod
def change_date_format[best_before]:
best_before = datetime.strptime[best_before, "%Y-%m-%d"]
best_before = best_before.strftime["%d-%m-%Y"]
return best_before
class GroceryStore[Supermarket]:
def get_best_before_date[self]:
return Supermarket.change_date_format[self.best_before]
>>> supermarket = Supermarket["Milk", "2022-05-18"]
>>> grocery = GroceryStore["Milk", "2022-05-18"]
>>> supermarket.get_best_before_date[]
'2022-05-18'
>>> grocery.get_best_before_date[]
'18-05-2022'
Khi nào bạn nên sử dụng phương thức lớp?
Bạn có thể sử dụng các phương thức lớp cho bất kỳ phương thức nào không bị ràng buộc với một thể hiện cụ thể nhưng lớp. Trong thực tế, bạn thường sử dụng các phương thức của lớp cho các phương thức tạo một thể hiện của lớp
1. phương pháp xuất xưởng
Các phương thức xuất xưởng là những phương thức trả về một đối tượng lớp cho các trường hợp sử dụng khác nhau. Ví dụ
class Supermarket:
def __init__[self, product, best_before]:
self.best_before = "2022-05-18"
self.product = "Milk"
@classmethod
def add_product[cls]:
return cls["Bread", "2022-05-29"]>>> obj = Supermarket.add_product[]
>>> obj.product
'Milk'
>>> obj.best_before
'2022-05-18'
Trong trường hợp này, hàm add_product[] chỉ tạo một đối tượng lớp mới [một sản phẩm mới và tốt nhất trước ngày]
2. Tạo phiên bản chính xác trong kế thừa
Bất cứ khi nào bạn dẫn xuất một lớp từ việc triển khai một phương thức xuất xưởng làm phương thức lớp, nó đảm bảo việc tạo thể hiện chính xác của lớp dẫn xuất
Bạn có thể tạo một phương thức tĩnh, nhưng đối tượng mà nó tạo ra sẽ luôn được mã hóa cứng dưới dạng Lớp cơ sở
Tuy nhiên, khi bạn sử dụng một phương thức của lớp, nó sẽ tạo ra thể hiện đúng của lớp dẫn xuất
class Supermarket:
product_price = {"Milk": 1} def __init__[self, product, best_before]:
self.best_before = "2022-05-18"
self.product = "Milk" @staticmethod
def add_import_product[product, best_before]:
return Supermarket[product, best_before] @classmethod
def add_product[cls, product, best_before]:
return cls[product, best_before]
class GroceryStore[Supermarket]:
product_price = {"Milk": 2}grocery1 = GroceryStore.add_import_product["Bread", "2022-06-05"]
isinstance[grocery1, GroceryStore]
>>> False
grocery2 = GroceryStore.add_product["Apple", "2022-06-10"]
isinstance[grocery2, GroceryStore]
>>> True
Ở đây, sử dụng một phương thức tĩnh để tạo một thể hiện của lớp, muốn chúng tôi mã hóa cứng loại thể hiện trong quá trình tạo
Điều này rõ ràng gây ra vấn đề khi kế thừa
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
6 thành class Supermarket:4
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print[f"product={cls.product}, age={cls.best_before}"]
>>> Supermarket.get_product[]
AttributeError: type object 'Supermarket' has no attribute 'best_before'
Phương thức
class Supermarket:5 không trả về đối tượng
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print[f"product={cls.product}, age={cls.best_before}"]
>>> Supermarket.get_product[]
AttributeError: type object 'Supermarket' has no attribute 'best_before'
class Supermarket:6, mà là đối tượng của lớp cơ sở
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print[f"product={cls.product}, age={cls.best_before}"]
>>> Supermarket.get_product[]
AttributeError: type object 'Supermarket' has no attribute 'best_before'
class Supermarket:7
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print[f"product={cls.product}, age={cls.best_before}"]
>>> Supermarket.get_product[]
AttributeError: type object 'Supermarket' has no attribute 'best_before'
Điều này vi phạm mô hình OOP. Sử dụng một phương thức lớp như
class Supermarket:8 có thể đảm bảo tính OOP của mã vì nó lấy tham số đầu tiên làm chính lớp đó và gọi phương thức xuất xưởng của nó
product = "Milk" # class attribute
def __init__[self, product, best_before]:
self.best_before = best_before # instance attribute
self.product = product @classmethod
def get_product[cls]:
print[f"product={cls.product}, age={cls.best_before}"]
>>> Supermarket.get_product[]
AttributeError: type object 'Supermarket' has no attribute 'best_before'
Phần kết luận
Trong bài viết này, chúng tôi đã phân tích @staticmethod
và
>>> norm_product = Supermarket.normalize_product_name["milk "]
'Milk'
>>> obj = Supermarket["Bread", "2022-05-18"]
>>> obj.normalize_product_name["milk "]
'Milk'
0 là gì và tìm hiểu cách thức, địa điểm và lý do sử dụng chúng- Chúng tôi thường sử dụng @classmethod để tạo các phương thức xuất xưởng. Các phương thức xuất xưởng trả về các đối tượng lớp cho các trường hợp sử dụng khác nhau
- Chúng tôi thường sử dụng các phương thức tĩnh để tạo và nhóm các hàm tiện ích
Chia sẻ suy nghĩ và ý kiến của bạn trong phần bình luận, nhấp vào “Vỗ tay” nếu bài viết hữu ích và thú vị đối với bạn. Click “Theo dõi” để luôn nhận được những bài viết hữu ích