赞
踩
在本文中,我将向您展示它们是什么@staticmethod
、@classcmethod
是什么、为什么以及何时应该使用它们!让我们开始吧。如果您还不知道装饰器是什么以及它是如何工作的,那么首先阅读这篇文章。
@staticmethod
这@staticmethod
是一个内置的装饰器,它在 Python 的类中定义了静态方法。静态方法不接收类或实例参数,无论它是由类的实例还是由类本身调用。
静态方法特征
cls
或者self
范围。ClassName.MethodName()
,也可以通过 using 来调用object.MethodName()
。以下示例声明一个静态方法:
- 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
上面,该类使用装饰器将该方法Supermarket
声明normalize_product_name()
为静态方法@staticmethod
。请注意,它不能有self
或cls
参数。
可以使用ClassName.MethodName()
或来调用静态方法object.MethodName()
。
- >>> norm_product = Supermarket.normalize_product_name("milk ")
- 'Milk'
- >>> obj = Supermarket("Bread", "2022-05-18")
- >>> obj.normalize_product_name("milk ")
- 'Milk'
@classmethod
是@classmethod
一个内置的装饰器,它在Python的类中定义了类方法。类方法仅接收类参数。可以使用ClassName.MethodName()
或来调用类方法object.MethodName()
。
这@classmethod
是该功能的替代方案classmethod()
。建议使用@classmethod
装饰器而不是函数,因为它只是语法糖。
类方法特征
cls
,它可用于访问类属性。ClassName.MethodName()
,也可以使用 来调用object.MethodName()
。以下示例声明一个类方法:
- 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)
上面,Supermarket
类包含一个类属性product
和一个实例属性best_before
。该get_product()
方法用装饰器装饰@classmethod
,使其成为类方法,可以使用Supermarket.get_product()
. 请注意,任何类方法的第一个参数都必须cls
可用于访问类的属性。您可以为第一个参数指定任何名称,而不是cls
。
ClassName.MethodName()
可以使用或来调用类方法object.MethodName()
。
- >>> Supermarket.get_product()
- 'product=Milk'
- >>> obj = Supermarket()
- >>> obj.get_product()
- 'product=Milk'
但在类方法中你不能使用实例属性:
- 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'
- #!/usr/bin/python
- # -*- coding: UTF-8 -*-
-
- class A(object):
- bar = 1
- def func1(self):
- print ('foo')
- @classmethod
- def func2(cls):
- print ('func2')
- print (cls.bar)
- cls().func1() # 调用 foo 方法
-
- A.func2() # 不需要实例化
- from datetime import date
-
- # random Person
- class Person:
- def __init__(self, name, age):
- self.name = name
- self.age = age
-
- @classmethod
- def fromBirthYear(cls, name, birthYear):
- return cls(name, date.today().year - birthYear)
-
- def display(self):
- print(self.name + "'s age is: " + str(self.age))
-
- person = Person('Adam', 19)
- person.display()
-
- person1 = Person.fromBirthYear('John', 1985)
- person1.display()
假设您创建了 Foo 的子类并在子类上调用了 create_new 方法
- class Bar(Foo):
- pass
-
- obj = Bar.create_new()
然后这个基类将导致一个新的 Bar 对象被创建......
- class Foo:
- @classmethod
- def create_new(cls):
- return cls()
而这个基类会导致创建一个新的 Foo 对象
- class Foo:
- @staticmethod
- def create_new():
- return Foo()
采取哪一个?取决于你想要的行为。
静态方法的用例有限,因为与类方法或类中的任何其他方法一样,它们无法访问类本身的属性。
但是,当您需要一个不访问类的任何属性但有意义它属于该类的实用函数时,我们使用静态函数。
例如,您添加了更改最佳食用日期格式的函数:
- 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'
它是一个静态方法,因为它不需要访问Supermarket
自身的任何属性,只需要参数。
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'
您可以将类方法用于任何未绑定到特定实例但绑定到类的方法。在实践中,您经常使用类方法来创建类的实例。
工厂方法是为不同用例返回类对象的方法。例如:
- 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'
在这种情况下,add_product() 函数只是创建一个新的类对象(一个新产品及其最佳食用日期)。
每当您通过将工厂方法实现为类方法来派生类时,它都会确保派生类的正确实例创建。
您可以创建静态方法,但它创建的对象将始终被硬编码为基类。
但是,当您使用类方法时,它会创建派生类的正确实例。
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
这里,使用静态方法创建类实例,希望我们在创建过程中对实例类型进行硬编码。
Supermarket
这显然会在继承时引起问题GroceryStore
。
add_import_product
方法不返回Grocerystore
对象,而是返回其基类Supermarkets
的对象。
这违反了 OOP 范式。使用类方法 asadd_product()
可以确保代码的 OOP 性,因为它将第一个参数作为类本身并调用其工厂方法。
大多数情况,@classmethod和@staticmethod效果一样。但是那不是正题,正式作用是类工厂,如果有类继承关系,更加明显。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。