当前位置:   article > 正文

python知识:@classmethod和@staticmethod的异同_classmethod和staticmethod区别

classmethod和staticmethod区别

一、说明

        在本文中,我将向您展示它们是什么@staticmethod@classcmethod是什么、为什么以及何时应该使用它们!让我们开始吧。如果您还不知道装饰器是什么以及它是如何工作的,那么首先阅读这篇文章

二、定义:

2.1 定义静态方法@staticmethod

        这@staticmethod是一个内置的装饰器,它在 Python 的类中定义了静态方法。静态方法不接收类或实例参数,无论它是由类的实例还是由类本身调用。

静态方法特征

  • 在类中声明静态方法。
  • 它不能有cls或者self范围。
  • 静态方法不能访问类属性或实例属性。
  • 静态方法可以通过 using 来调用ClassName.MethodName(),也可以通过 using 来调用object.MethodName()
  • 它可以返回该类的一个对象。

以下示例声明一个静态方法:

  1. class Supermarket:
  2. product = "Milk" # class attribute
  3. def __init__(self, product, best_before):
  4. self.best_before = best_before # instance attribute
  5. self.product = product
  6. @staticmethod
  7. def normalize_product_name(product):
  8. product = product.capitalize().strip()
  9. return product

上面,该类使用装饰器将该方法Supermarket声明normalize_product_name()为静态方法@staticmethod。请注意,它不能有selfcls参数。

可以使用ClassName.MethodName()或来调用静态方法object.MethodName()

  1. >>> norm_product = Supermarket.normalize_product_name("milk ")
  2. 'Milk'
  3. >>> obj = Supermarket("Bread", "2022-05-18")
  4. >>> obj.normalize_product_name("milk ")
  5. 'Milk'

2.2 定义类方法@classmethod

@classmethod一个内置的装饰器,它在Python的类中定义了类方法。类方法仅接收类参数。可以使用ClassName.MethodName()或来调用类方法object.MethodName()

@classmethod是该功能的替代方案classmethod()。建议使用@classmethod装饰器而不是函数,因为它只是语法糖。

类方法特征

  • 声明一个类方法。
  • 第一个参数必须是cls,它可用于访问类属性。
  • 类方法只能访问类属性,不能访问实例属性。
  • 类方法可以使用 using 来调用ClassName.MethodName(),也可以使用 来调用object.MethodName()
  • 它可以返回该类的一个对象。

以下示例声明一个类方法:

  1. class Supermarket:
  2. product = "Milk" # class attribute
  3. def __init__(self, product, best_before):
  4. self.best_before = best_before # instance attribute
  5. self.product = product
  6. @classmethod
  7. def get_product(cls):
  8. print("product=" + cls.product)

上面,Supermarket类包含一个类属性product和一个实例属性best_before。该get_product()方法用装饰器装饰@classmethod,使其成为类方法,可以使用Supermarket.get_product(). 请注意,任何类方法的第一个参数都必须cls可用于访问类的属性。您可以为第一个参数指定任何名称,而不是cls

ClassName.MethodName()可以使用或来调用类方法object.MethodName()

  1. >>> Supermarket.get_product()
  2. 'product=Milk'
  3. >>> obj = Supermarket()
  4. >>> obj.get_product()
  5. 'product=Milk'

但在类方法中你不能使用实例属性:

  1. class Supermarket:
  2. product = "Milk" # class attribute
  3. def __init__(self, product, best_before):
  4. self.best_before = best_before # instance attribute
  5. self.product = product
  6. @classmethod
  7. def get_product(cls):
  8. print(f"product={cls.product}, age={cls.best_before}")
  9. >>> Supermarket.get_product()
  10. AttributeError: type object 'Supermarket' has no attribute 'best_before'

2.3 @classmethod的对照

2.3.1 类生成例

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. class A(object):
  4. bar = 1
  5. def func1(self):
  6. print ('foo')
  7. @classmethod
  8. def func2(cls):
  9. print ('func2')
  10. print (cls.bar)
  11. cls().func1() # 调用 foo 方法
  12. A.func2() # 不需要实例化

 2.3.2 @classmethod类工厂

  1. from datetime import date
  2. # random Person
  3. class Person:
  4. def __init__(self, name, age):
  5. self.name = name
  6. self.age = age
  7. @classmethod
  8. def fromBirthYear(cls, name, birthYear):
  9. return cls(name, date.today().year - birthYear)
  10. def display(self):
  11. print(self.name + "'s age is: " + str(self.age))
  12. person = Person('Adam', 19)
  13. person.display()
  14. person1 = Person.fromBirthYear('John', 1985)
  15. person1.display()

 2.3.3  @classmethod和@staticmethod的区别

        假设您创建了 Foo 的子类并在子类上调用了 create_new 方法

  1. class Bar(Foo):
  2. pass
  3. obj = Bar.create_new()

        然后这个基类将导致一个新的 Bar 对象被创建......

  1. class Foo:
  2. @classmethod
  3. def create_new(cls):
  4. return cls()

        而这个基类会导致创建一个新的 Foo 对象

  1. class Foo:
  2. @staticmethod
  3. def create_new():
  4. return Foo()

        采取哪一个?取决于你想要的行为。

三、什么时候应该使用静态方法?

3.1. 将实用函数分组到一个类中

静态方法的用例有限,因为与类方法或类中的任何其他方法一样,它们无法访问类本身的属性。

但是,当您需要一个不访问类的任何属性但有意义它属于该类的实用函数时,我们使用静态函数。

例如,您添加了更改最佳食用日期格式的函数:

  1. from datetime import datetime
  2. class Supermarket:
  3. def __init__(self, product, best_before):
  4. self.best_before = "2022-05-18"
  5. self.product = "Milk"
  6. @staticmethod
  7. def change_date_format(best_before):
  8. best_before = datetime.strptime(best_before, "%Y-%m-%d")
  9. best_before = best_before.strftime("%d-%m-%Y")
  10. return best_before
  11. >>> Supermarket.change_date_format("2022-08-06")
  12. '06-08-2022'

        它是一个静态方法,因为它不需要访问Supermarket自身的任何属性,只需要参数。

3.2  单一实现

  1. from datetime import datetime
  2. class Supermarket:
  3. def __init__(self, product, best_before):
  4. self.best_before = best_before
  5. self.product = product
  6. def get_best_before_date(self):
  7. return self.best_before
  8. @staticmethod
  9. def change_date_format(best_before):
  10. best_before = datetime.strptime(best_before, "%Y-%m-%d")
  11. best_before = best_before.strftime("%d-%m-%Y")
  12. return best_before
  13. class GroceryStore(Supermarket):
  14. def get_best_before_date(self):
  15. return Supermarket.change_date_format(self.best_before)
  16. >>> supermarket = Supermarket("Milk", "2022-05-18")
  17. >>> grocery = GroceryStore("Milk", "2022-05-18")
  18. >>> supermarket.get_best_before_date()
  19. '2022-05-18'
  20. >>> grocery.get_best_before_date()
  21. '18-05-2022'

四、什么时候应该使用类方法?

        您可以将类方法用于任何未绑定到特定实例但绑定到类的方法。在实践中,您经常使用类方法来创建类的实例。

4.1.工厂方法

工厂方法是为不同用例返回类对象的方法。例如:

  1. class Supermarket:
  2. def __init__(self, product, best_before):
  3. self.best_before = "2022-05-18"
  4. self.product = "Milk"
  5. @classmethod
  6. def add_product(cls):
  7. return cls("Bread", "2022-05-29")
  8. >>> obj = Supermarket.add_product()
  9. >>> obj.product
  10. 'Milk'
  11. >>> obj.best_before
  12. '2022-05-18'

在这种情况下,add_product() 函数只是创建一个新的类对象(一个新产品及其最佳食用日期)。

4.2.继承中正确的实例创建

每当您通过将工厂方法实现为类方法来派生类时,它都会确保派生类的正确实例创建。

您可以创建静态方法,但它创建的对象将始终被硬编码为基类。

但是,当您使用类方法时,它会创建派生类的正确实例。

  1. class Supermarket:
  2. product_price = {"Milk": 1}
  3. def __init__(self, product, best_before):
  4. self.best_before = "2022-05-18"
  5. self.product = "Milk"
  6. @staticmethod
  7. def add_import_product(product, best_before):
  8. return Supermarket(product, best_before)
  9. @classmethod
  10. def add_product(cls, product, best_before):
  11. return cls(product, best_before)
  12. class GroceryStore(Supermarket):
  13. product_price = {"Milk": 2}
  14. grocery1 = GroceryStore.add_import_product("Bread", "2022-06-05")
  15. isinstance(grocery1, GroceryStore)
  16. >>> False
  17. grocery2 = GroceryStore.add_product("Apple", "2022-06-10")
  18. isinstance(grocery2, GroceryStore)
  19. >>> True

这里,使用静态方法创建类实例,希望我们在创建过程中对实例类型进行硬编码。

Supermarket这显然会在继承时引起问题GroceryStore

add_import_product方法不返回Grocerystore对象,而是返回其基类Supermarkets的对象。

这违反了 OOP 范式。使用类方法 asadd_product()可以确保代码的 OOP 性,因为它将第一个参数作为类本身并调用其工厂方法。

五、结论:

        在本文中,我们分析了它们是什么@staticmethod以及@classcmethod如何、在何处以及为何使用它们:

  • 我们一般使用@classmethod来创建工厂方法。工厂方法返回不同用例的类对象。
  • 我们通常使用静态方法来创建和分组实用函数。

     @staticmethod的意思就是将后面的函数转化成静态函数。

        大多数情况,@classmethod和@staticmethod效果一样。但是那不是正题,正式作用是类工厂,如果有类继承关系,更加明显。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/716534
推荐阅读
相关标签
  

闽ICP备14008679号