class方法和静态方法有什么区别?
说实话,@classmethod 和 @staticmethod 这俩货,在 Python 里一直是让人容易混淆的存在。尤其是当年我刚从 Java 转 Python 的时候,看到 classmethod 的第一反应是:“这不就是 Java 里的 static 方法嘛!”后来真香了,被打脸了好几次……
兄弟们,今天我们就来扒一扒这俩 Python 里常见的装饰器到底是干啥的,有啥区别,什么时候该用谁,还有最重要的:别被面试官问懵了。
先放结论:
@staticmethod是个彻底脱离类和实例的野孩子,它不关心你是谁。@classmethod是个能看到类是谁的半路出家的老二,它知道“我现在是哪个类在调我”。
听着有点玄是吧?咱们上代码来聊。
classDemo:
class_name = "DemoClass"
@staticmethod
defstatic_hello():
print("Hi,我是不知道你是哪个类的静态方法 😎")
@classmethod
defclass_hello(cls):
print(f"Hi,我是类方法,我知道你是 {cls.__name__} 👀")
试着调用一下:
Demo.static_hello()
Demo.class_hello()
输出结果:
Hi,我是不知道你是哪个类的静态方法 😎
Hi,我是类方法,我知道你是 Demo 👀
是不是感觉 staticmethod 有点像一根筋的程序员,什么都自己干,不求别人;而 classmethod 更像那种会考虑上下文的老油条,知道自己在哪儿,啥情况。
接下来讲点实战经验。我在写工具类的时候特别喜欢用 @staticmethod,比如各种处理字符串、格式化时间戳的玩意儿,完全用不到类或对象的上下文,那就别扯什么 cls、self,干脆点,直接 staticmethod。
比如:
classUtils:
@staticmethod
deftime_format(ts):
from datetime import datetime
return datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
这个方法纯粹就是功能性的,和你是哪个类有毛关系?这时候用 staticmethod,干净利索。
但如果你有继承需求,那就得老老实实用 classmethod。
举个典型场景:工厂方法。
classAnimal:
def__init__(self, name):
self.name = name
@classmethod
deffrom_string(cls, data):
name = data.split(',')[0]
return cls(name)
classDog(Animal):
pass
classCat(Animal):
pass
现在你可以干这个:
dog = Dog.from_string("旺财,2岁,公")
cat = Cat.from_string("咪咪,1岁,母")
print(type(dog), dog.name) # <class '__main__.Dog'> 旺财
print(type(cat), cat.name) # <class '__main__.Cat'> 咪咪
你看到没?from_string 明明定义在 Animal 里,但在子类里用的时候,cls 自动变成了 Dog 或 Cat,这就是 classmethod 的强大之处:动态感知调用者是谁。
而如果你把 from_string 改成 @staticmethod,然后调 Dog.from_string(...),对不起,返回的就是个 Animal,不是 Dog,也不是 Cat,直接给你整懵。
再来一个段子,某次代码 review,我一个小兄弟写了个类似的工具类,但里头全是 staticmethod,我一看就觉得不对劲,因为他还写了个 get_class_name() 的方法,非要搞个类名打印。我说兄弟你干嘛不用 classmethod 啊?他说 staticmethod 轻量……轻量你个头啊!你自己在 static 里还手动写类名,这不就是脱裤子放屁嘛?
这事儿在一些 Python 框架里也特别常见,比如 Django 的 ORM 就大量用 classmethod。
看看人家:
classBook(models.Model):
title = models.CharField(max_length=100)
@classmethod
deftop_books(cls):
return cls.objects.order_by('-rating')[:5]
你看,cls 就是 Book,所以 cls.objects 才成立。换 staticmethod 就彻底跪了。
哦对了,如果你实在懒,不想写 staticmethod,不加装饰器其实也能用(反正 Python 也不强制),但你别忘了没加装饰器的函数,是会默认把 self 传进去的。所以你不加任何装饰器写一个“假装 static”的方法,还拿 self 参数干嘛?想让读代码的人崩溃?
-END-
我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领