@classmethod与@staticmethod区别
在Python中有3种方式定义类方法分别是常规方式、@classmethod修饰方式、@staticmethod修饰方式。
接下来分别对3种不同方式的定义举例说明。
普通方法: 其实就是需要操作一些实例独有的属性,是实例而不是类。第一个参数一般是隐式地将实例传递给self参数。
class People():
def __init__(self, name, gender):
self.name = name
self.gender = gender
def greeting(self):
return f'Hello, {self.name}'
p = People('Anders', 'Male')
p.greeting()
# 输出内容:
# 'Hello, Anders'
@staticmethod: 静态方法其实就是一个普通的函数(静态方法无法调用任何非静态成员,所以也不需要self参数),可以使用类名直接调用,很多人不太明白的是为什么不直接把静态方法放在类外调用呢,毕竟效果一样,但是从代码逻辑从属来说,静态方法是一种组织或风格特征。如果这个方法实现的功能与类比较相关的话,放到了类里面更合适,这代表是某个类专用的工具函数。
class People():
def __init__(self, name, gender):
self.name = name
self.gender = gender
@staticmethod
def greeting(name, gender):
return f'Hello, {name}!'
print(People.greeting('Anders', 'Male'))
# 输出内容:
# Hello, Anders!
静态方法调用另一个静态方法直接用「类名.静态方法()」调用即可。如果想在静态方法中调用类中的其它非静态方法,或者非静态属性必须要通过生成实例对象的方式去访问。
class Web(object):
def __init__(self):
self.desc = "实例属性,不共享"
def norm_method(self):
"""普通方法"""
print('普通方法被调用!')
# 另外一个静态方法
@staticmethod
def foo_staticmethod_other():
print('另外一个静态方法被调用!')
@staticmethod
def foo_staticmethod():
# 调用非静态方法和属性
instance = Web()
instance.norm_method()
print(instance.desc)
# 调用另一个静态方法
print(Web.foo_staticmethod_other())
@classmethod: 类方法可以通过类或者实例对象调用。一般情况下是作用于类相关的操作。第一个参数不是类的实例对象,而必须是类对象,在Python中这个参数常被写作cls,因为全称class是保留字。而被@classmethod修饰的函数内可调用类属性,但不能调用实例属性。
注意:对类作出的任何改变会对它的所有实例对象产生影响。
我们看到下面创建了3次实例对象,当最后去访问类方法person时,count值累积为数值3,并没有还原。
class People():
count = 0
def __init__(self, name, gender):
self.name = name
self.gender = gender
People.count += 1
@classmethod
def person(cls):
return cls.count
p1 = People('Anders', 'Male')
p2 = People('Mary', 'Female')
p3 = People('James', 'Male')
print(f'People has {People.person()} little person objects.')
# 输出内容:
# People has 3 little person objects.
那么类方法一般用在什么场景呢,举个如下例子,如果用户输入的时间日期格式和我们预期的纯数字不一致,比如'2019-03-03',那可以先使用get_date
类方法对日期字符串进行处理,然后在使用时date = cls(year, month, day)
做构造函数初始化并创建了一个date实例,最后我们把它return返回出来,然后赋值给result变量后就可以直接调用类实例方法了。
class Time_Data:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def get_date(cls, data_as_string):
year, month, day = map(int, data_as_string.split('-'))
date = cls(year, month, day)
return date
def out_date(self):
print(f'The date is: {self.year}/{self.month}/{self.day}')
result = Time_Data.get_date('2019-03-03')
result.out_date()
# 输出内容:
# The date is: 2019/3/3
总结起来就是,class method可以用来为一个类创建一些预处理的实例。