Phương thức tĩnh và phương thức lớp trong Python

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

Vậy khi nào bạn nên sử dụng @staticmethod?

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

>>> 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ào

Nế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

Sự định nghĩa

@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  "]
    'Milk'
    >>> obj = Supermarket["Bread", "2022-05-18"]
    >>> obj.normalize_product_name["milk "]
    'Milk'
    2 hoặc
    >>> norm_product = Supermarket.normalize_product_name["milk  "]
    'Milk'
    >>> obj = Supermarket["Bread", "2022-05-18"]
    >>> obj.normalize_product_name["milk "]
    'Milk'
    3
  • 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  "]
    'Milk'
    >>> obj = Supermarket["Bread", "2022-05-18"]
    >>> obj.normalize_product_name["milk "]
    'Milk'
    4 và cũng có thể sử dụng
    >>> norm_product = Supermarket.normalize_product_name["milk  "]
    'Milk'
    >>> obj = Supermarket["Bread", "2022-05-18"]
    >>> obj.normalize_product_name["milk "]
    'Milk'
    5
  • 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'
2

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  "]
'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:
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]
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
>>> 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

Hàm

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]
3 là một thay thế của hàm
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]
7. Nên sử dụng trình trang trí
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]
3 thay vì chức năng vì nó chỉ là đường cú pháp

Đặ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  "]
    '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
  • 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  "]
    'Milk'
    >>> obj = Supermarket["Bread", "2022-05-18"]
    >>> obj.normalize_product_name["milk "]
    'Milk'
    4 và cũng có thể sử dụng
    >>> norm_product = Supermarket.normalize_product_name["milk  "]
    'Milk'
    >>> obj = Supermarket["Bread", "2022-05-18"]
    >>> obj.normalize_product_name["milk "]
    'Milk'
    5
  • 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:
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]
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
>>> 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'
2

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  "]
'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:
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'
4

Phương thức

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'
5 không trả về đối tượng
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'
6, mà là đối tượng của lớp cơ sở
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'
7

Đ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:
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'
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ó

Phần kết luận

Trong bài viết này, chúng tôi đã phân tích @staticmethod

>>> 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

Mục đích của Classmethod và Staticmethod trong Python là gì?

Phương thức lớp so với Phương thức tĩnh . Một phương thức lớp có thể truy cập hoặc sửa đổi trạng thái lớp trong khi một phương thức tĩnh không thể truy cập hoặc sửa đổi nó. Nói chung, các phương thức tĩnh không biết gì về trạng thái lớp. A class method takes cls as the first parameter while a static method needs no specific parameters. A class method can access or modify the class state while a static method can't access or modify it. In general, static methods know nothing about the class state.

Tôi nên sử dụng Classmethod hay Staticmethod?

Để quyết định nên sử dụng @staticmethod hay @classmethod, bạn phải xem bên trong phương thức của mình. Nếu phương thức của bạn truy cập các biến/phương thức khác trong lớp thì hãy sử dụng @classmethod . Mặt khác, nếu phương thức của bạn không chạm vào bất kỳ phần nào khác của lớp thì hãy sử dụng @staticmethod.

Khi nào tôi nên sử dụng Staticmethod Python?

các phương thức tĩnh có thể được sử dụng khi mã thuộc về một lớp hoàn toàn không sử dụng chính đối tượng đó . Python không phải khởi tạo một phương thức ràng buộc cho từng đối tượng mà chúng ta khởi tạo. Các phương thức ràng buộc cũng là các đối tượng và việc tạo chúng có chi phí. Có một phương pháp tĩnh tránh điều đó.

Classmethod trong Python là gì?

Phương thức lớp trong Python là gì. Các phương thức của lớp là các phương thức được gọi trên chính lớp đó, không phải trên một thể hiện đối tượng cụ thể . Do đó, nó thuộc về một cấp độ lớp và tất cả các thể hiện của lớp đều chia sẻ một phương thức lớp. Một phương thức lớp được liên kết với lớp chứ không phải đối tượng của lớp. Nó chỉ có thể truy cập các biến lớp.

Chủ Đề