认识Python中的对象和方法、类、类的继承、类的组合

认识Python中的对象和方法

  • 在Python中,一个对象的类型由创建该对象的类决定。
  • 操作是用方法定义的。

类的定义

  • 用类来抽象、描述待求解问题所涉及的事物,具体包括两个方面的抽象:数据抽象和行为抽象。数据抽象描述某类对象共有的属性或状态;行为抽象描述某类对象共有的行为或功能特征。
  • 使用类来定义同一种类型的对象。
  • 类(class)是广义的数据类型,能够定义复杂数据的特性,包括静态特性(即数据抽象)和动态特性(即行为抽象,也就是对数据的操作方法)。
  • 一个Python类使用变量存储数据域,称为类中的属性;定义方法来完成动作。对象是类的一个实例,一个类可以创建多个对象。创建类的一个实例的过程被称为实例化。
  • 在术语中,对象实例经常是可以互换的。对象就是实例,实例就是对象。类和对象的关系相当于普通数据类型和它的变量之间的关系。
  • 类和对象的关系
  1. 类是对象的抽象,而对象是类的具体实例;
  2. 类是抽象的,而对象是具体的;
  3. 每一个对象都是某一个类的实例;
  4. 每一个类在某一时刻都有零或更多的实例;
  5. 类是静态的,它们的存在、语义和关系在程序执行前就已经定义好了,对象是动态的,它们在程序执行时可以被创建和删除;
  6. 类是生成对象的模板。
  • Python中使用class保留字来定义类,类名的首字母一般要大写
  • 如果用户未设计__init__()方法,Python将提供一个默认的__init__()方法。每个方法其实都是一个函数定义,与普通函数略有差别:
    • 每个实例方法的第一个参数都是self,self代表将来要创建的对象实例本身。在访问类的实例属性时需要以self为前缀;
    • 实例方法只能通过对象来调用,即向对象发消息请求对象执行某个方法。

类的属性

类属性和实例属性

在这里插入图片描述

  • 类的属性有两种:类属性和实例属性(对象属性)。类属性是在类中方法之外定义的,如上图中定义的age、sex均属于类属性;实例属性是在初始化方法__init__()中定义的,定义时以self为前缀,只能通过对象名访问。
  • 案例
    在这里插入图片描述
  • Rectangle类对象t1的创建与初始化过程。
    在这里插入图片描述
  • 当使用t1=Rectangle(15,6)创建t1对象时,Python自动调用__init__()方法,传递给该方法的实参是t1、15、6,相当于函数调用__init__(t1,15,6),这样就为对象t1进行了初始化操作,变量width赋值15,变量height赋值6,width和height均属于实例属性。也就是说创建了一个Rectangle类的宽为15,高为6的矩形对象t1。

在这里插入图片描述

  • 假设再使用t2=Rectangle(25,16)创建对象t2,则跟创建t1对象一样,自动调用__init__()方法,这时只不过传递给该方法的实参分别是t2、25、16,则对对象t2进行初始化时,就为变量width赋值25,变量height赋值16,而这时为width和height所赋的值25、16是专属于新的对象t2的,跟前面创建的对象t1没有关系。图8.3表示Rectangle类的多个对象创建与初始化过程。
属性的访问权限
  • 类中的属性根据外部对其访问的权限,分为公有属性、保护属性和私有属性。
  • “单下画线” 开始的属性叫做保护属性,只有其本身和子类能访问到这些属性。
  • “双下画线” 开始的是私有属性,只有该类本身能访问,即使子类也不能访问到这个属性。
  • 在Python中,私有属性通过“对象名._类名__私有属性名”的方式直接访问私有属性。没有以任何下画线开头的属性是公有属性,在任何地方均可以访问该属性。
    在这里插入图片描述
    在这里插入图片描述
  • 类中定义的实例方法都必须以self作为第一个参数,这个参数表示当前是哪一个实例对象要执行类的方法,这个实参由Python隐含地传递给self。上图表示创建Person类对象以及对象的old()方法调用的过程。

类中的方法

实例的构造与初始化
  • 一个类中有一个特殊的方法:__ init__(),这个方法用来初始化一个对象,为属性设置初值,在创建对象时自动执行。如果一个类中没有提供__init__()方法,Python将提供一个默认的__init__()方法。子类如果想调用父类(基类)的__init__()方法,必须显式调用,否则子类的__init__()方法不会自动调用父类的__init__()方法。
    在这里插入图片描述
实例方法的访问权限
  • 实例方法根据外部对其访问的权限,可分为3种:私有方法、保护方法和公有方法。
    • 以单下画线开头的方法是 protected 类型的,只允许其本身与子类进行访问,也不能用于 from module import *。
    • 双下画线开头的是私有方法, 只允许这个类本身进行访问。
    • 开头既没有单下画线,也没有双下画线的方法是公有方法,允许任何对象进行访问。公有方法就可以通过对象名调用。其调用形式为:“对象名.公有方法(<实参>)” 。
  • 公有方法和私有方法示例
    在这里插入图片描述
  • 程序运行结果:
    在这里插入图片描述
静态方法与类方法
  • 静态方法的定义之前需要添“@staticmethod”。静态方法定义时,不需要表示访问对象的self参数,形式上与普通函数的定义类似。

  • 静态方法只能访问属于类的成员,不能访问属于对象的成员。

  • 一个类的所有实例对象共享静态方法。

  • 使用静态方法时,既可以通过“对象名.静态方法名”来访问,也可以通过“类名.静态方法名”来访问。
    在这里插入图片描述
    在这里插入图片描述

  • 静态方法使用示例:
    在这里插入图片描述

  • 类方法定义之前由“@classmethod”语句引导,第一个形参通常被命名为 cls。类方法既可以通过类名,也可以通过对象名来调用。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

析构方法
  • Python中类的析构方法是__del__()方法,用来删除对象以释放对象的内存空间。如果用户未提供析构方法,Python将提供一个默认的析构方法。
    在这里插入图片描述
  • 注意:如果多个变量对应同一片内存空间,则只有这些变量都删除后才会销毁这片内存空间中所保存的对象,也才会自动执行析构方法。
    在这里插入图片描述

可变对象与不可变对象

  • Python中所有数据都是对象,对象的变量通常都是指向对象的引用。调用函数时,实参的值被传递给形参,这个值通常就是对象的引用值。当一个可变对象传给函数时,函数可能会改变这个对象的内容。当将一个不可变对象传递给函数时,对象不会被改变。
  • 在Python的内建标准类型中,列表、字典和集合为可变类型。用户自定义类的对象是可变对象。
    在这里插入图片描述
    在这里插入图片描述

get和set方法

  • get方法返回值,set方法设置新值。通常get方法被称为获取器或访问器,set方法被称为设置器或修改器。
    在这里插入图片描述
  • 程序解释:
  • 在上面代码Rectangle类中,通过getWidth和getHeight方法获取对象的私有width和height属性值,通过setWidth和setHeight方法设置对象的私有width和height属性值,如果设置的值不符合要求,则打印有误信息。在主程序中,创建了一个width为25,height为16的Rectangle类对象t2,然后通过调用getWidth和getHeight方法获得width和height的值,调用getArea 和getPerimeter方法计算出面积和周长,随后通过setWidth方法将width设置成8,并将新的width打印出来,最后还是通过setWidth方法将width设置成-8,由于数据不符合要求,打印出错误信息,width还是原来的8没有改变。由于类中两个对象属性是私有的,无法在主程序中通过对象名直接访问私有属性。

类的继承与类的组合

  • 类的继承是指在现有类的基础上创建新类,在新类中添加代码,以扩展原有类的属性(数据成员)和方法(成员函数)。
  • 类的组合是指在新创建的类中包含有已有类的对象作为其属性。

类的继承

  • 继承是在一个被作为父类(或称为基类)的基础上扩展新的属性和方法来实现的。子类自动具备父类中的非私有属性和非私有方法,并且可以增加新的属性和方法。
  • 在Python语言中,object类是所有类的最终父类,所有类最顶层的根都是object类。在程序中创建一个类时,除非明确指定父类,否则默认从Python的根类object继承。
  • Python中的一个类可以有多个父类,同时从多个父类中继承所有特性。
父类与子类
  • 父类是指被直接或间接继承的类。Python中类object是所有类的直接或间接父类。
  • 在继承关系中,继承者是被继承者的子类。子类继承所有祖先的非私有属性和非私有方法,子类也可以增加新的属性和方法,子类也可以通过重定义来覆盖从父类继承而来的方法。

  • 如图所示的继承关系,类Product是一个父类,具备Computer、MobilePhone、TFCard等类的共同特征。Computer、MobilePhone、TFCard三个类都是类Product的子类,它们继承了Product的共同特征。
  • Python支持多重继承,一个子类可以有多个父类。在图中,类SmartMobilePhone有两个父类,同时具备Computer和MobilePhone的特征。
  • 在继承关系中,子类和父类是一种“is-a”的关系,作为判断继承关系的一个基准
    在这里插入图片描述
继承的语法
  • 类的继承关系体现在类定义的语法中:
    class ChildClassName(ParentClassName1[, ParentClassName2[,ParentClassName3, …]]):
    #类体或pass语句

  • 子类ChildClassName从圆括号中的父类派生,继承父类的非私有属性和非私有方法。如果圆括号中没有内容,则表示从object类派生。如果只是给出一个定义,尚没有定义类体时,使用pass语句代替类体。
    在这里插入图片描述
    在这里插入图片描述

子类继承父类的属性
  • 子类继承父类中的非私有属性,但不能继承父类的私有属性,也无法在子类中访问父类的私有属性。
  • 子类只能通过父类中的公有方法访问父类中的私有属性。
    在这里插入图片描述
  • 父类与子类如果定义了名称相同的属性,父类中的属性在子类中将被覆盖。
    在这里插入图片描述
  • 子类继承父类中的非私有方法,不能继承私有方法。
    在这里插入图片描述
    在这里插入图片描述
  • 当子类中定义了与父类中同名的方法时,子类中的方法将覆盖父类中的同名方法,也就是重写了父类中的同名方法。
super方法
  • super方法用于获取父类的代理对象,以执行已在子类中被重写的父类方法,其语法格式为:
    super([类名[, 对象名或类名]])

  • super方法有两个参数:

  • 第一个参数是要获取父类代理对象的类名。

  • 第二个参数如果传入对象名,则该对象所属的类必须是第一个参数指定的类或该类的子类,找到的父类对象的self会绑定到这个对象上;

  • 如果传入类名,则该类必须是第一个参数指定的类的子类。

  • 在一个类A的定义中调用super方法时,可以将两个参数都省略,此时,super()等价于super(A, self),即获取A的父类代理对象,且获取到的父类代理对象中的self绑定到当前A类对象的self上。
    在这里插入图片描述
    将 “super().__ init __ (sno, name)”改为
    “super(Postgraduate,self). __ init __(sno, name) ”,程序运行结果完全相同

继承关系下的初始化方法
  • 在Python的继承关系中,如果子类的初始化方法没有覆盖父类的初始化方法__init__(),则在创建子类对象时,默认执行父类的初始化方法。
    在这里插入图片描述
  • 父类Product有一个初始化方法 __ init __ (self),子类MobilePhone继承父类Product且没有重写初始化方法,因此在创建Product对象时,调用父类的默认初始化方__init __(self)。
  • 当子类中的初始化方法__init__()覆盖了父类中的初始化方法时,创建子类对象时,执行子类中的初始化方法,不会自动调用父类中的初始化方法。
    在这里插入图片描述
  • 子类的初始化方法可以调用父类的初始化方法。(借助super)
    在这里插入图片描述
  • 有两种方法调用父类的初始化方法:
  1. 父类名.__ init __(self, 其他参数);
  2. super(本子类名, self)__ init __(其他参数)。
  • 注意,这里的其他参数是指初始化方法定义时列出的除self外的参数。
多重继承
  • 在多重继承的情况下,经典类采用从左到右的深度优先搜索算法寻找相应的属性或方法。而在新式类中采用C3算法(类似于广度优先搜索算法)进行匹配。
    在这里插入图片描述

  • 在Python 2.7中的程序运行结果为:

  • 执行Product类中的testClassicalClass()方法

    • 在Python 2.7环境下,代码作为经典类来处理,主程序创建了一个SmartMobilePhone类的对象,然后该对象调用testClassicalClass()方法。然而该类中没有直接定义的testClassicalClass()方法。
    • 根据经典类多重继承关系中的从左到右深度优先搜索算法原则,首先到类SmartMobilePhone的第一个父类Computer中搜索testClassicalClass()方法。然而类Computer中没有直接定义的方法testClassicalClass()。因此继续搜索类Computer的父类Product。在Product类中找到了方法testClassicalClass()的定义。因此执行类Product中的方法testClassicalClass()。而SmartMobilePhone的直接父类MobilePhone中所定义的方法testClassicalClass()被跳过了,不会得到执行。
  • 在Python 3.7中的程序运行结果为:

  • 执行MobilePhone类中的testClassicalClass()方法

    • 在Python 3.7环境下,例9-11和例9-12均作为新式类来处理。SmartMobilePhone的对象s调用testClassicalClass()方法,然而类SmartMobilePhone中没有直接定义的方法testClassicalClass(),因此在类SmartMobilePhone的所有父类Computer和MobilePhone中从左到右搜索testClassicalClass()方法,结果在类MobilePhone中找到了该方法的定义,然后执行该方法。

类的组合

  • 类的组合(composition)是类的另一种重用方式。如果程序中的类需要使用其他类的对象,就可以使用类的组合方式。组合关系可以用“has-a”关系来表达,就是一个主类中包含其他对象。

  • 在组合关系下有两种方法可以实现对象属性初始化。

  • 第一种方法是通过组合类初始化方法传递被组合对象所属类的初始化方法中的参数;
    在这里插入图片描述

    • 在第一种方法中,在Computer类的初始化方法中分别传递显示器尺寸displaySize和内存大小memorySize给两个组合对象所属类的初始化方法,在组合类Computer中创建被组合的对象。
  • 第二种方法是在主程序中创建被组合类的对象,然后将这些对象传递给组合类。
    在这里插入图片描述

    • 在第二种方法中,组合类的初始化方法参数由两个被组合类的对象组成。因此,在主程序中需要预先创建被组合对象,然后将这些对象作为参数传递给组合类的初始化方法,最终赋值给组合类的对象属性。
  • 继承与组合的结合
    在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇宙超级无敌霸王龙捏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值