《手把手陪您学Python》41——类方法与实例方法

在上一篇《手把手陪您学Python》40——类的定义、属性与实例化中,我们学习了面向对象编程的基础知识,了解了类的属性以及实例化属性等,今天我们将会主要介绍类的方法以及实例方法。

1、类的方法:

类的方法其实也可以认为是类具有的某种特征,与类的属性不同的是,这种特征除了可以用变量进行描述以外,还可以做更多的“事情”,而这些事情是通过定义函数的方式来实现的。

也就是说,如果类的属性是可以通过实例访问的变量,那么类的方法就是可以通过实例访问的函数。

类中的函数就称为方法,我们之前学习的有关函数的一切都适用于方法。

虽然我们之前也尝试过对函数和方法的区别进行过描述,但也只是为了让初学的我们更好地理解和使用函数与方法,其实两者的界限并不是那么地清晰,而且从英文上的表示来看,两者也都是function。所以,后面我们会逐渐淡化这两者的区别,无论是说函数还是方法,其实指的是一回事。

让我们通过实例看一看,类的方法是如何通过定义函数的方式来实现的,又可以做哪些事情。

我们选取马里奥的三个技能作为马里奥类的方法,包括可以跳跃、可以攻击,还可以吃东西,作为对马里奥类的补充。这时,对于马里奥类的描述就比较完整了:

In [1]: class Mario:
    life = 3
    cap = "red"
    def jump():   # 没有参数
        print("Jumping!")
    def attack(name):   # 一个参数
        print("{} attacked an anomy!".format(name))
    def eat(name, food):   # 多个参数
        print("{} ate a {}!".format(name, food))
        print("{} became bigger!".format(name))

运行程序我们就完成了马里奥类的完整的定义。

由于函数是可以自定义参数的,所以类的方法也同样可以不需要参数、一个参数或者多个参数。

函数内的语句既是对函数的定义,也是对类方法的定义,也就是这个类可以做的“事情”。

在上面的实例中,每个类方法执行的内容都是打印一段字符串,但是在真正的游戏中,就不仅仅是这么简单的一句指令了,而是一系列更为复杂的程序来实现画面的变化、背景音乐的配合,甚至还要触发墙被顶破以及敌人被压死的效果等等。

如果更进一步地,不是在控制一个动画效果,而是控制一个真实的机器人马里奥,那么这里就是控制各类设备和传感器的指令,进而控制机器人马里奥的行为。

所以说,在类的方法中,通过定义函数的方式,可以做很多的事情,远比类的属性要复杂和强大得多。

2、类方法的引用

引用类方法和我们之前学过的各种方法的引用方式一样,只要把对象名称改为类名称或者实例名称就好了,如果方法中需要参数,就在括号中加上参数。

类名称.类方法(参数1, 参数2, 参数3...)

我们可以引用一下刚刚定义的马里奥的三个方法,如果在定义方法的时候要求输入参数,我们也相应地输入参数即可。

In [2]: Mario.jump()
Out[2]: Jumping!
​
In [3]: Mario.attack("Mario")
Out[3]: Mario attacked an anomy!
​
In [4]: Mario.eat("Mario", "red mushroom")
Out[4]: Mario ate a red mushroom!
        Mario became bigger!

如果我们还想给马里奥赋予更多的方法,或者希望在现有的方法中扩展新的内容,就像我们之前自定义函数一样,自行添加相应语句就可以了,这里就不继续演示了。

这时,可以回看一下《手把手陪您学Python》39——面向对象中的内容,我们在讲解的过程中使用到了很多的括号,当时说大家可以先不用理会其中的内容,等讲到后面的时候自然就会了解了。包括括号里标记的“对象”、“属性”、“方法”,现在看起来就会对其中的概念非常清晰了。

像洗衣服过程中括号里的内容,实际上就是我们刚刚讲的对洗衣机类和人类的方法的引用。

1、人打开洗衣机门(人.打开洗衣机门)

2、人把衣服放进去(人.把衣服放进去)

3、人关上洗衣机门(人.关上洗衣机门)

4、人启动电源(人.启动电源)

5、洗衣机清洗衣服(洗衣机.清洗衣服)

6、洗衣机甩干衣服(洗衣机.甩干衣服)

7、洗衣机烘干衣服(洗衣机.烘干衣服)

既然已经定义好了类的方法,那么就像实例可以引用类属性一样,实例应该也可以引用同样的类方法,让我们看一下是不是这样:

In [5]: small_mario = Mario()
        small_mario.jump()
Out[5]: ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-23-11dbe964307a> in <module>
              1 small_mario = Mario()
        ----> 2 small_mario.jump()
        
        TypeError: jump() takes 0 positional arguments but 1 was given
In [6]: small_mario.attack("Small mario")
Out[6]: ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-24-8478b32ee2d8> in <module>
        ----> 1 small_mario.attack("Small mario")
        
        TypeError: attack() takes 1 positional argument but 2 were given
In [7]: small_mario.eat("Small mario", "red mushroom")
Out[7]: ---------------------------------------------------------------------------
        TypeError                                 Traceback (most recent call last)
        <ipython-input-25-4b4a74507a8b> in <module>
        ----> 1 small_mario.eat("Small mario", "red mushroom")
        
        TypeError: eat() takes 2 positional arguments but 3 were given

可以看到,虽然我们将马里奥类实例化成了小马里奥,但是在引用类方法的时候都出现了错误,而且错误类型都提示“只有n个位置参数但应该有n+1个位置参数”。

那么为什么会报错,这多出来的1个位置参数又是什么呢?

这是因为实例引用类方法与实例引用类属性有一些不同,虽然实例可以直接引用“类属性”,但是实例是不能够直接“类方法”的,而只能引用“实例方法”。

3、实例方法

实例方法的定义与类方法有所不同。

类方法的定义与我们自定义函数时参数的设置是一样的,可以没有参数,也可以有一个或者多个参数。而在定义实例方法时,每一个方法都默认要有一个“self”参数,而且必须是要作为第一个参数的。这个“self”参数就是报错提示中多出来的那个参数。

这个self代表的就是实例本身。

也就是说,当我们定义实例方法时,实例本身就是实例方法的一个参数,而且默认是第一个参数。当实例调用这个方法时,会自动将实例传入这个self参数中。每个实例方法都会自动将实例传入self参数中,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。

self并不是Python的关键字,把他换成其他名称也是可以的,只不过在Python中约定俗成地使用self代表实例本身,所以我们也照常使用就可以了。

让我们用实例方法的定义方式将上面的类方法进行修改,也就是在每一个方法中都在第一个参数的位置增加self参数,就可以得到下面的实例方法。同时,为了验证不使用self名称也不影响调用,在其中一个参数的设置中使用了其他名称加以验证,但仅此一次。

In [8]: class Mario:
    life = 3
    cap = "red"
    def jump(self):
        print("Mario is jumping!")
    def attack(good, name):   # 使用非self名称进行验证
        print("Mario attacked an anomy!")
    def eat(self, name, food):
        print("Mario ate a {}!".format(food))
        print("{} became bigger!".format(name))

这时再让实例去引用这些方法,就能得到我们预期的结果了。

In [9]: small_mario = Mario()
Out[9]: small_mario.jump()
        Mario is jumping!
​
In [10]: small_mario.attack("Small mario")
Out[10]: Mario attacked an anomy!
​
In [11]: small_mario.eat("Small mario", "red mushroom")
Out[11]: Mario ate a red mushroom!
         Small mario became bigger!

所以说,一旦一个类被实例化,就可以像使用函数一样使用这个类,函数的参数就是实例。如果用公式和例子描述的话可能会更清晰一些。

实例.实例方法() == 类.实例方法(实例)

In [12]: print(small_mario.jump() == Mario.jump(small_mario))
Out[12]: Mario is jumping!
         Mario is jumping!
         True

相应地,因为现在定义的是实例方法,如果此时调用类方法的话就会报错了。

In [13]: Mario.jump()
Out[13]: ---------------------------------------------------------------------------
         TypeError                                 Traceback (most recent call last)
         <ipython-input-38-d2cb2ba47b0e> in <module>
         ----> 1 Mario.jump()
                 
         TypeError: jump() missing 1 required positional argument: 'self'

以上就是我们对于类方法以及实例方法的介绍,正是因为有强大的类方法的加持,才让面向对象编程能够精准地模拟现实生活中的情况,并变得无比强大。

下一篇,我们将会继续对类方法的其他内容进行介绍,包括实例属性、魔法方法等,敬请关注。

 

图片

 


感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^

要阅读《手把手陪您学Python》系列文章的其他篇目,请关注公众号点击菜单选择,或点击下方链接直达。

《手把手陪您学Python》1——为什么要学Python?

《手把手陪您学Python》2——Python的安装

《手把手陪您学Python》3——PyCharm的安装和配置

《手把手陪您学Python》4——Hello World!

《手把手陪您学Python》5——Jupyter Notebook

《手把手陪您学Python》6——字符串的标识

《手把手陪您学Python》7——字符串的索引

《手把手陪您学Python》8——字符串的切片

《手把手陪您学Python》9——字符串的运算

《手把手陪您学Python》10——字符串的函数

《手把手陪您学Python》11——字符串的格式化输出

《手把手陪您学Python》12——数字

《手把手陪您学Python》13——运算

《手把手陪您学Python》14——交互式输入

《手把手陪您学Python》15——判断语句if

《手把手陪您学Python》16——循环语句while

《手把手陪您学Python》17——循环的终止

《手把手陪您学Python》18——循环语句for

《手把手陪您学Python》19——第一阶段小结

《手把手陪您学Python》20——列表

《手把手陪您学Python》21——元组

《手把手陪您学Python》22——字典

《手把手陪您学Python》23——内置序列函数

《手把手陪您学Python》24——集合

《手把手陪您学Python》25——列表推导式

《手把手陪您学Python》26——自定义函数

《手把手陪您学Python》27——自定义函数的参数

《手把手陪您学Python》28——自定义函数的返回值

《手把手陪您学Python》29——匿名函数

《手把手陪您学Python》30——模块

《手把手陪您学Python》31——文件的打开

《手把手陪您学Python》32——文件的读取

《手把手陪您学Python》33——文件的关闭

《手把手陪您学Python》34——文件的写入

《手把手陪您学Python》35——数据的存储

《手把手陪您学Python》36——错误和异常处理

《手把手陪您学Python》37——程序的重构

《手把手陪您学Python》38——第二阶段小结

《手把手陪您学Python》39——面向对象

《手把手陪您学Python》40——类的定义、属性与实例化

For Fans:关注“亦说Python”公众号,回复“手41”,即可免费下载本篇文章所用示例语句。

亦说Python——Python爱好者的学习分享园地
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值