一日一技:什么情况使用静态方法和类方法?

开发 前端
最近有同学在知识星球上问,什么情况下使用静态方法,什么情况下使用类方法。今天我们就来捋一下这两个方法的应用场景。

[[427633]]

最近有同学在知识星球上问,什么情况下使用静态方法,什么情况下使用类方法。今天我们就来捋一下这两个方法的应用场景。

首先,我们来定义一个普通的类,里面都是普通的方法,普通方法又叫实例方法。

class People: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
 
    def introduce_myself(self): 
        print(f'大家好,我叫: {self.name}'
 
    def add_two_string_num(self, a, b): 
        a_int = int(a) 
        b_int = int(b) 
        return a_int + b_int 
 
    def calc_age_after_n_year(self, n): 
        age = self.add_two_string_num(self.age, n) 
        print(f'{n}年以后,我{age}岁'
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

这个类运行起来的效果如下图所示:

大家注意在这个类里面的方法add_two_string_num,它接受两个参数,并将他们转换为int类型,然后相加并返回结果。这个过程非常简单,但是,它跟People这个类有什么直接关系吗?

其实这个方法跟这个类没有什么直接关系,我们甚至把它改成函数都可以:

def add_two_string_num(a, b): 
    a_int = int(a) 
    b_int = int(b) 
    return a_int + b_int 
 
class People: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
 
    def introduce_myself(self): 
        print(f'大家好,我叫: {self.name}'
 
    def calc_age_after_n_year(self, n): 
        age = add_two_string_num(self.age, n) 
        print(f'{n}年以后,我{age}岁'
 
         
kingname = People('kingname', 20) 
kingname.introduce_myself() 
kingname.calc_age_after_n_year(10) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

运行结果跟之前完全一样:

我们可以说,add_two_string_num函数就是一个工具函数。工具函数接收参数,输出结果,完全不关心谁在调用他,也不关心在哪里调用他。

但现在有一个比较尴尬的事情,这个函数,只有 People在调用,其它地方都没有调用。单独把它放到其它地方又显得多余,弄成实例方法又浪费了self参数,这个时候,我们就可以用静态方法:

class People: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
 
    def introduce_myself(self): 
        print(f'大家好,我叫: {self.name}'
 
    @staticmethod 
    def add_two_string_num(a, b): 
        a_int = int(a) 
        b_int = int(b) 
        return a_int + b_int 
 
    def calc_age_after_n_year(self, n): 
        age = People.add_two_string_num(self.age, n) 
        print(f'{n}年以后,我{age}岁'
 
 
kingname = People('kingname', 20) 
kingname.introduce_myself() 
kingname.calc_age_after_n_year(10) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

一句话总结:静态方法就是某个类专用的工具函数。

说完了静态方法,我们再说说类方法。什么情况下应该使用类方法呢?回答这个问题前,我先反问你一个问题,怎么把People类初始化成一个实例?

你说这还不简单吗,一行代码就行了啊:

xxx = People('xxx', 10) 
  • 1.

注意,这里你在初始化这个类的时候,你是一个一个参数传入进去的。如果你用过顺丰寄送快递,你就会发现,填写收件人的时候,有两种方式,一种方式就像上面这样,一个一个参数填进去。另一种方式,它给你一个输入框,你把一段包含姓名,地址,手机号的文字粘贴进去,它自动解析。

那么,如果我现在给你一个字符串:我的名字:青南,我的年龄:20,把它提取出来。你怎么基于这个字符串生成People类的实例?

这个时候,你可能会这样写:

import re 
content = '我的名字:青南,我的年龄:20,把它提取出来' 
name = re.search('名字:(.*?),', content).group(1) 
age = re.search('年龄:(\d+)', content).group(1) 
kingname = People(name, age) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

这样做确实可以,但我能不能让People这个类自动识别呢?其实是可以的,有两种方法,一种方法是在__init__里面多加几个参数,然后在初始化的时候,从这几个参数里面解析,这个方法大家都知道,我就不多讲了。我们来讲讲第二个方法,就是使用类方法。

我们只需要再定义一个类方法:

import re 
 
 
class People: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
 
    def introduce_myself(self): 
        print(f'大家好,我叫: {self.name}'
 
    @staticmethod 
    def add_two_string_num(a, b): 
        a_int = int(a) 
        b_int = int(b) 
        return a_int + b_int 
 
    @classmethod 
    def from_chinese_string(cls, sentence): 
        name = re.search('名字:(.*?),', content).group(1) 
        age = re.search('年龄:(\d+)', content).group(1) 
        return cls(name, age) 
 
 
    def calc_age_after_n_year(self, n): 
        age = People.add_two_string_num(self.age, n) 
        print(f'{n}年以后,我{age}岁'
 
         
content = '我的名字:青南,我的年龄:20,把它提取出来' 
kingname = People.from_chinese_string(content) 
kingname.introduce_myself() 
kingname.calc_age_after_n_year(10) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

运行效果如下图所示:

类方法使用装饰器@classmethod来装饰,并且它的第一个参数是隐式参数cls。这个参数其实就是People这个类本身。这个隐式参数在我们调用类方法的时候,是不需要传入的。在这个类方法里面,相当于使用People初始化了一个实例,然后把这个实例返回了出去。

这样做有什么好处呢?好处就在于我们完全不需要修改__init__,那么,也就不需要修改代码里面其它调用了People类的地方。例如现在我又想增加从英文句子里面提取名字和年龄的功能,那么只需要再添加一个类方法就可以了:

import re 
 
 
class People: 
    def __init__(self, name, age): 
        self.name = name 
        self.age = age 
 
    def introduce_myself(self): 
        print(f'大家好,我叫: {self.name}'
 
    @staticmethod 
    def add_two_string_num(a, b): 
        a_int = int(a) 
        b_int = int(b) 
        return a_int + b_int 
 
    @classmethod 
    def from_chinese_string(cls, sentence): 
        name = re.search('名字:(.*?),', content).group(1) 
        age = re.search('年龄:(\d+)', content).group(1) 
        return cls(name, age) 
 
    @classmethod 
    def from_english_string(cls, sentence): 
        name = re.search('name: (.*?),', content).group(1) 
        age = re.search('age: (\d+)', content).group(1) 
        return cls(name, age) 
 
 
    def calc_age_after_n_year(self, n): 
        age = People.add_two_string_num(self.age, n) 
        print(f'{n}年以后,我{age}岁'
 
         
content = 'my name: kinganme, my age: 15 please extract them' 
kingname = People.from_english_string(content) 
kingname.introduce_myself() 
kingname.calc_age_after_n_year(10) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

运行效果如下图所示:

一句话总结:当你想使用工厂模式,根据不同的参数生成同一个类的不同对象的时候,就可以使用类方法。

其实如果大家使用过Python自带的datetime模块,你就会发现类方法无处不在:

import datetime 
 
now = datetime.datetime.now() 
dt = datetime.datetime.fromtimestamp(1633691412) 
dt2 = datetime.datetime.fromisoformat('2021-10-08 19:10:05'
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

 这段代码里面的.now()、.fromtimestamp()和 .fromisoformat(),都是类方法。他们最终返回的都是datetime.datetime对象,区别在于他们是根据不同类型的输入参数生成的。

本文转载自微信公众号「未闻Code」,可以通过以下二维码关注。转载本文请联系未闻Code公众号。

 

责任编辑:武晓燕 来源: 未闻Code
相关推荐

2024-07-19 18:23:17

2021-10-11 20:02:49

Python父类方法

2024-05-24 09:07:06

JSONprint字符串

2021-10-15 21:08:31

PandasExcel对象

2021-04-27 22:15:02

Selenium浏览器爬虫

2024-12-27 00:44:44

MarkdownPrompt大模型

2021-11-12 05:00:43

装饰器代码功能

2024-08-27 22:08:13

2024-10-16 21:47:15

2021-04-12 21:19:01

PythonMakefile项目

2021-06-01 21:24:44

多线程代码搜索

2021-02-27 10:49:13

可视化分析资源

2022-05-02 16:27:01

JavaScriptHTMLPython

2021-04-05 14:47:55

Python多线程事件监控

2023-10-28 12:14:35

爬虫JavaScriptObject

2024-11-13 09:18:09

2021-09-13 20:38:47

Python链式调用

2021-03-12 21:19:15

Python链式调用

2022-06-28 09:31:44

LinuxmacOS系统

2021-04-19 23:29:44

MakefilemacOSLinux
点赞
收藏

51CTO技术栈公众号