第10章 面向对象(上)

10.1 对象与类

在现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体,如学生、汽车等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,即静态部分与动态部分。顾名思义,静态部分就是不能动的部分,这个部分被称为“属性”,任何对象都会具备其自身属性,如一个人,其属性包括高矮、胖瘦、年龄、性别等。然而具有这些属性的人会执行哪些动作也是一个值得探讨的部分,这个人可以转身、微笑、说话、奔跑,这些是这个人具备的行为(动态部分),人类通过探讨对象的属性和观察对象的行为来了解对象。
在计算机世界中,面向对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。例如,现在面临一名足球运动员想要将球射进对方球门这个实际问题,试着以面向对象的思想来解决它。步骤如下:
首先可以从这一问题中抽象出对象,这里抽象出的对象为一名足球运动员。
然后识别这个对象的属性。对象具备的属性都是静态属性,如足球运动员有一个鼻子、两条腿等,这些属性如图所示。
在这里插入图片描述
接着识别这个对象的动态行为,即足球运动员的动作,如跳跃、转身等,这些行为都是这个对象基于其属性而具有的动作,这些行为如图所示。
在这里插入图片描述
识别出这个对象的属性和行为后,这个对象就被定义完成了,然后根据足球运动员具有的特性制定要射进对方球门的具体方案以解决问题。
究其本质,所有的足球运动员都具有以上的属性和行为,可以将这些属性和行为封装起来以描述足球运动员这类人。由此可见,类实质上就是封装对象属性和行为的载体,而对象则是类抽象出来的一个实例。这也是进行面向对象程序设计的核心思想,即把具体事物的共同特征抽象成实体概念,有了这些抽象出来的实体概念,就可以在编程语言的支持下创建类。因此,类是那些实体的一种模型,具体如图所示。
在这里插入图片描述
在图中,通过面向对象程序设计的思想可以建立现实世界中具体事物、实体概念与编程语言中类、对象之间的一一对应关系。

10.2 类的定义

Python使用class关键字来定义类,其语法格式如下:
在这里插入图片描述
其中,类名的首字母一般需要大写,具体示例如下:
在这里插入图片描述
其中,实例方法与前面学习的函数格式类似,区别在于类的所有实例方法都必须至少有一个名为self的参数,并且必须是方法的第一个形参(如果有多个形参),self参数代表将来要创建的对象本身。另外,self.name称为实例属性,在类的实例方法中访问实例属性时需要以self为前缀。
在类中定义实例方法时,第一个参数指定为“self”只是一个习惯。实际上,该参数的名字是可以变化的,具体如下所示:
在这里插入图片描述
尽管如此,本书建议大家编写代码时仍以self作为实例方法的第一个参数名字,这样便于他人阅读代码。

10.3 对象的创建

在Python中,有两种对象:类对象与实例对象。类对象只有一个,而实例对象可以有多个。

10.3.1 类对象

类对象是在执行class语句时创建的,如例所示。
在这里插入图片描述
在例中,Python执行class语句时创建一个类对象和一个变量(名称就是类名称),变量引用类对象。通过type()函数可以测试对象的类型。
在定义类时,还可以定义类属性,如例所示。
在这里插入图片描述
在例中,第6行通过“类名.类属性名”方式访问类属性。

10.3.2 实例对象

实例对象通过调用类对象来创建(就像调用函数一样来调用类对象),每个实例对象继承类对象的属性,并获得自己的命名空间。实例方法的第一个参数默认为self,表示引用实例对象。在实例方法中对self的属性赋值才会创建属于实例对象的属性,如例所示。
在这里插入图片描述
如果类中存在相同名称的类属性与实例属性,则通过实例对象只能访问实例属性,如例所示。
在这里插入图片描述
此外,还可以通过赋值运算符修改或增加类对象与实例对象的属性,如例所示。
在这里插入图片描述

10.4 构造方法

Python中构造方法一般用来为实例属性设置初值或进行其他必要的初始化操作,在创建实例对象时被自动调用和执行,如例所示。
在这里插入图片描述
上例中创建实例对象时,默认给school属性赋值为’千锋教育’。如果在创建实例对象时,由用户指定school属性的值,则可以在构造方法中添加额外参数,如例所示。
在这里插入图片描述

10.5 析构方法

析构方法一般用来释放对象占用的资源,在删除对象和收回对象空间时被自动调用和执行,如例所示。
在这里插入图片描述
在例中,第5行定义一个析构方法,该方法名称(del)是固定不变的,如果用户没有定义它,Python将提供一个默认的析构方法。第9行使用del语句删除一个对象,此时会自动调用析构方法。当程序结束时,Python解释器会自动检测当前是否存在未释放的对象,如果存在,则自动使用del语句释放其占用的内存,如本例中的s1对象。

10.6 类方法

类方法是类所拥有的方法,通过修饰器@classmethod在类中定义,其语法格式如下:
在这里插入图片描述
其中,cls表示类本身,通过它可以访问类的相关属性,但不可以访问实例属性,如例所示。
在这里插入图片描述

10.7 静态方法

类方法可以通过类名或实例对象名调用,静态方法也可以通过两者调用,其语法格式如下:
在这里插入图片描述
其中,@staticmethod为装饰器,参数列表中可以没有参数。静态方法可以访问类属性,但不可以访问实例属性,如例所示。
在这里插入图片描述

10.8 运算符重载

在Python中可通过运算符重载来实现对象之间的运算,如字符串可以进行如下运算:
在这里插入图片描述
字符串可以通过“+”运算符实现字符串连接操作,其本质是通过__add__方法重载了运算符“+”,因此上述代码还可以写成如下代码:
在这里插入图片描述
Python把运算符与类的实例方法关联起来,每个运算符都对应一个方法。运算符重载就是让类的实例对象可以参与内置类型的运算。

10.8.1 算术运算符重载

定义一个复数类并对其进行算术运算符重载,如例所示。
在这里插入图片描述

10.8.2 比较运算符重载

定义一个复数类并对其进行比较运算符重载,如例所示。
在这里插入图片描述
在例中,定义一个MyComplex类,通过__eq__ ()方法重载==运算符。

10.8.3 字符串表示重载

当对象作为print()、str()函数的参数时,该对象会调用重载的__str__()方法,如例所示。
在这里插入图片描述
在例中,定义一个MyComplex类,通过__str__ ()方法重载字符串表示。

10.8.4 索引或切片重载

当对实例对象执行索引、分片或for迭代时,该对象会调用重载的__getitem__()方法,如例所示。
在这里插入图片描述
在例中,定义一个Data类,通过__getitem__()方法重载索引与分片。
此外,在通过赋值语句给索引或分片赋值时,实例对象将调用__setitem__()方法实现对序列对象的修改,如例所示。
在这里插入图片描述
在例中,定义一个Data类,通过__ setitem__()方法重载索引或分片赋值。

10.8.5 检查成员重载

当对实例对象执行检查成员时,该对象会调用重载的__contains__()方法,如例所示。
在这里插入图片描述
在例中,定义一个Data类,通过__contains__()方法重载检测成员运算符。

10.9 小案例

通过扑克牌类与玩家类设计扑克牌发牌程序,要求程序随机将52张牌(不含大小王)发给4位玩家,最终在屏幕上显示每位玩家的牌,具体实现如例所示。

#定义牌类
class Card:
    #牌面数字:1-13
    RANKS = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]
    #牌面图标:红心、方块、梅花、黑桃
    SUITS = ["♥","♦","♣","♠"]
    #构造方法
    def __init__(self):
        self.cards = []
    #生成牌
    def create(self):
        for suit in Card.SUITS:
            for rank in Card.RANKS:
                self.cards.append((suit,rank))
        self.shuffle()
    #洗牌
    def shuffle(self):
        import random
        random.shuffle(self.cards)
    #发牌,每位玩家默认13张牌
    def deal(self,players,perCards = 13):
        for rounds in range(perCards):
            for player in players:
                topCard = self.cards[0]
                self.cards.remove(topCard)
                player.add(topCard)
#定义玩家类
class Player:
    #构造方法
    def __init__(self,name):
        self.name = name
        self.cards = []
    #重载字符串表示方法
    def __str__(self):
        if self.cards:
            rep = ""
            for card in self.cards:
                rep += str(card[0]) + str(card[1]) + " "
        else:
            rep = "无牌"
        return rep
    #添加牌
    def add(self,card):
        self.cards.append(card)
#测试
if __name__ == "__main__":
    #四位玩家
    players = [Player("小千"),Player("小锋"),Player("小扣"),Player("小丁")]
    #生成一副牌
    card = Card()
    card.create()
    #发给每位玩家13张牌
    card.deal(players,13)
    #显示4位玩家的牌
    for player in players:
        print(player.name,"玩家:",player)

本章小结

本章主要介绍了Python中面向对象的基本概念,包括类的定义、对象的创建、构造方法与析构方法、类方法与静态方法、运算符重载。大家在编写大型应用程序时,应考虑使用面向对象的思想进行编程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值