Python学习
一、学前花絮
我们之前学习了python的面向对象,针对类/对象、init方法及操作动态属性等进行了探讨。后来也学习了装饰器,装饰器是干什么的?简单说就如同装修房子,没有破坏房子但让房子更好用更美观。装饰器也是一样,让不破坏函数让函数更好用更美观。
今天结合python内置装饰器@staticmethod和@classmethod深入了解一下类内部方法的定义和使用。
二、Python面向对象:详解@staticmethod和@classmethod
2.1 静态方法(@staitcmethod)
在 Python 中,@staticmethod 是一个装饰器,用于将类中的某个方法定义为静态方法。简单来说,它的核心作用是:将一个普通函数“塞”进类里面,让它成为类的一部分,但这个函数既不操作类本身,也不操作具体的实例对象。
① 核心特点:
不需要 self 和 cls:
普通方法需要 self(代表实例),类方法需要 cls(代表类),但静态方法不需要这两个参数。它就像一个独立的普通函数,只是恰好放在了类的命名空间里。
② 无需实例化即可调用:
你可以直接通过 类名.方法名() 来调用它,不需要先创建对象(obj = MyClass())。
不能访问实例或类的状态:
因为它拿不到 self 或 cls,所以它无法读取或修改实例的属性(self.attr)或类的属性(cls.attr)。
③ 什么时候使用它?
当你发现某个功能逻辑上与这个类相关,但代码实现上不依赖于类的属性或实例的属性时,就非常适合使用 @staticmethod。
常见的场景包括:
工具函数:比如数据验证、格式转换、数学计算等。我们之前有篇文章探讨“operator”的使用,就是把加减乘除封装成工具函数。
逻辑分组:为了代码结构清晰,把相关的函数都放在同一个类里管理。
④ 代码示例:
以上程序中,instance_method是典型的实例方法,也是大多数类中所规定的方法,第一个参数必须是self。它的好处是可以很方便获取实例属性。而被装饰器的add、validate_positive方法就是静态方法,有了@staticmethod告诉使用者,直接使用此函数,无需传入类或者实例参数。
以下是调用方法:
结果如下:
这里需要说明的是,尽管@staticmethod装饰器就是为了让add等函数使用起来简单,无需实例化。但实例化后的对象是否能调用它呢?答案是可以!
输出结果:
但这种调用方法只能说是为了满足好奇心。毕竟这与@staticmethod的初衷相违背。
2.2 类方法 (@classmethod)
类方法的特点:
l必须接收类本身作为第一个隐式参数(通常命名为 cls)。
lPython 解释器会自动把调用该方法的那个类(或子类)传给 cls。
l如果把 add 改为类方法,它的定义必须是 add(cls, x, y)。
类方法与静态方法对比:
① 静态方法:
孤岛模式:它完全不知道外面的类长什么样。它不能访问类的属性(如 PI),也不能调用类的其他方法。
它就像一个被借住在类家里的“客人”。
② 类方法:
内部通达:它可以通过 cls 参数访问类的所有属性和其它类方法。
如果你的 add 运算需要用到类里的某个常量(比如税率、圆周率等),或者需要记录一下“这个方法被调用了多少次”,那就必须用类方法。
代码实战对比:
我们看到,以上的两个函数都是实现加法,但传入的参数不同。静态方法最简洁,而类方法必须传入类本身作为参数。
调用方法:
输出结果:
既然二者调用方法和输出结果看上去一样,那么选哪个呢?如果函数体内部用不到 cls(类方法)或 self(实例方法),那就坚决使用 @staticmethod。这符合“简单就是美”的编程哲学。
或者说如果只是实现类似operator的工具类,那么就用静态方法。
2.3 基本无意义(可以看做是畸形)的类方法
其实,为了透彻理解类/对象及其方法,还有一种初学者容易错误定义的类方法。可以认为是畸形的类方法,因为来源于从函数转型过来,还没有实例的概念。比如
这种函数如果不在类的内部是OK的,就是一个加法函数。但如果在类的内部,就很奇葩了。因为前面说过,类的方法基本上都能实例化调用,而这个畸形函数是无法实例化调用的,只能通过类调用。
输出结果:
尽管这种方法也确实能够使用,但它存在的意义是什么呢?结合前面学习的内容,我们会发现此类函数几乎无意义,只是为了挑战我们对于python基础知识的掌握是否稳固。
2.4 结论
虽然你可以定义一个没有 self 的普通函数放在类里,但为了代码的健壮性和可读性,只要是不需要 self 的函数,请务必加上 @staticmethod 装饰器。
三、小结
通过学习python面向对象及内置装饰器@staticmethod、@classmethod,我们对于类/对象及其方法的使用又有了新的认识。
让我们保持学习热情,多做练习。我们下期再见!