26、Python之面向对象:从茴香豆的写法看方法的定义及适用场景

引言

前面的文章中介绍了关于面向对象中类的定义及属性的相关使用。关于类的属性的介绍,暂时可以告一段落。今天准备聊一下类封装中另外的一个构成部分,也就是方法。

关于类中的方法,可以理解为函数在特定类中的封装,会函数的定义,基本就会了类中方法的定义。

除了满足基本函数的使用外,类中根据不同的场景,将封装其中的方法分为三种类型:实例方法、类方法,以及静态方法。

需要注意的是,当我们说到函数时,一定是在模块中独立定义的函数;而我们提到方法时,一定是特指在类中定义的“函数”。

本文主要就这三种方法依次展开介绍。

茴香豆的“茴”有四种写法

鲁迅先生刻画的孔乙己一个典型的情节是,孔乙己以“茴香豆的茴字有四种写法”来安慰和支撑那少的可怜的读书人的自尊,这种掉书袋之嫌,似乎讽刺了一些自欺欺人的无用之学。

但是,在笔者看来,没有绝对意义上的无用之学。所谓的有用、无用,其实是混淆了主客体的相互作用的关系。任何知识、技能,只要找到了其适用的场景,都可以是可能有用的。以宣称客体的无价值、无用来掩饰主体的无能,其实是很没有道理的。

面向对象中的方法,也存在这样的问题。类中的不同方法的定义及使用,有时也不免被抨击有无用之嫌。类中的方法有三种写法,分别是:实例方法、类方法、静态方法。实例方法当然是最常用的,但是类方法和静态方法也有其存在的意义及适用的场景。

类似于类属性和实例属性的使用,方法的定义与使用,其实也依赖于对需求的分析与理解,以及面向对象的设计。有用与无用的问题,其实转变为当前需求中有无使用的场景。抛开场景谈有用无用,其实都是不负责任的耍流氓。

实例方法

实例方法的定义非常简单,只要把函数定义放到类定义中即可。但是,需要注意的是传参的一个规则:第一个参数必须是对象的引用,而且这个参数的传参由Python解释器自动完成,我们自己进行调用时,只需要传入除第一个参数之外的参数即可。

还是以打工人的代码为例:

class DaGongRen:
    # 类属性,打工人计数
    num = 0

    def __init__(self, name, gender):
        # 实例属性
        self.name = name
        self.gender = gender
        DaGongRen.num += 1


def work(self):
    print(f"打工人【{self.name}】[{'男' if self.gender == 1 else '女'}]】在努力工作")


if __name__ == '__main__':
    dgr = DaGongRen('张三', 1)
    dgr.work()

代码中:__init()、work()都是实例方法,直接在类中定义,方法的首个参数:self表示的是实例对象的引用,该参数无需手动传递,Python解释器自动完成。此外,self形参名也是习惯约定,可以是其他名字,但是会让阅读代码的人觉得比较奇怪。在PyCharm等IDE中定义实例方法时,会自动补全self的形参定义。

实例方法的调用,如同实例属性一样,通过对象名.方法名()进行调用。

实例方法是类中最常用的方法类型,主要用于访问或者修改实例属性,或者调用其他实例方法间接访问或者修改实例属性。

类方法

类似于类属性的定位,类方法也是在类中直接定义,但是,如果只是这样定义,无法与实例方法区分。Python中的解决思路是,通过给函数添加classmethod装饰器来标识一个方法为类方法,同样以代码举例说明:

class DaGongRen:
    # 类属性,打工人计数
    num = 0
    # 类属性,team
    team = '打工人俱乐部'

    def __init__(self, name, gender):
        # 实例属性
        self.name = name
        self.gender = gender
        DaGongRen.num += 1

    def work(self):
        print(f"打工人【{self.name}[{'男' if self.gender == 1 else '女'}]】在[{DaGongRen.team}]中努力工作")

    @classmethod
    # 类方法,用于清除实例对象的计数
    def clear_num(cls):
        cls.num = 0

    @classmethod
    # 统一更新实例对象的组织信息
    def change_team(cls, new_team):
        print(f"组织更名: {cls.team} -> {new_team}")
        cls.team = new_team


if __name__ == '__main__':
    zs = DaGongRen('张三', 1)
    zs.work()
    ls = DaGongRen('李四', 2)
    ls.work()
    # 组织更名
    DaGongRen.change_team('打工人协会')
    zs.work()
    ls.work()

执行结果:

d359edc32c391fda8ec4cebd9822d21b.jpeg

类方法的定义需要注意两点:

1、需要通过@classmethod装饰器来标识一个方法为实例方法

2、如同实例方法第一个参数为实例对象的引用,类方法也有类似的规定,类方法的第一个参数为类对象的引用,该参数也由Python解释器自动完成参数的传递,无需手动传参。

类方法的适用场景主要有:

1、由于实例对象只能访问类属性,无法修改类属性,所以,当修改类属性时,则需要选择类方法。

2、当我们需要支持通过不同的方式进行实例对象的构造时,可以通过定义类方法来实现,常见于设计模式中的工厂方法等。

3、当有些行为是与类整体有关,而不是跟特定实例相关时,也应该选择使用类方法。(当然,涉及到类属性时,很多时候都是跟第1点是相关的)

静态方法

静态方法是相对少见的一类方法,但也有其适用的场景。当我们需要实现一些与类和实例对象本身业务逻辑无关的功能时,通常是一些工具方法,又不涉及到类属性或者实例属性的访问修改时,可以考虑静态方法。静态方法需要通过staticmethod装饰器来标识,参数定义上无特殊规则。抛开装饰器不说,其实就是一个普通的函数,只是定义在类中。比如,我们希望有一个工具方法能够实现打工人性别从数字到文字的转换:

class DaGongRen:
    # 类属性,打工人计数
    num = 0
    # 类属性,team
    team = '打工人俱乐部'

    def __init__(self, name, gender):
        # 实例属性
        self.name = name
        self.gender = gender
        DaGongRen.num += 1

    @staticmethod
    # 静态方法,主要实现字符串的映射转换
    def gender_map(gender):
        if gender == 1:
            return '男'
        elif gender == 2:
            return '女'
        return '未知'

    def work(self):
        print(f"打工人【{self.name}[{self.gender_map(self.gender)}]】在[{DaGongRen.team}]中努力工作")

    @classmethod
    # 类方法,用于清除实例对象的计数
    def clear_num(cls):
        cls.num = 0

    @classmethod
    # 统一更新实例对象的组织信息
    def change_team(cls, new_team):
        print(f"组织更名: {cls.team} -> {new_team}")
        cls.team = new_team


从实现方式上,可以把静态方法单独拿出来,作为模块中的一个工具函数的定义。之所以,放在类中定义,一方面是代码的封装的考虑;另一方面虽说不如类方法、实例方法跟业务需求比较紧密,静态方法还是有些弱的关联的。

总结

本文以孔乙己的情节为例,简单论述了笔者关于有用无用的问题的看法,在笔者看来,没有无用的知识,只是必要性以及适用场景的发现与匹配的问题。

然后,介绍了面向对象中三种方法的定义及适用场景。

关于编程的自学的方法,其中很关键的一块就是首先知道有这个东西,然后在遇到实际的需求时,才会知道有这种方案的存在,然后才是通过实践进一步真正掌握这些用法。

感谢您的阅读,如果对您能稍微有一点点帮助,那是再好不好了。

a8f3cbcb49fee900c3838d902120be52.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南宫理的日知录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值