类的继承和多态

继承和多态与函数有共同的目的,都是为了减少代码的冗余,提高复用的效率;
根据“Python面向对象(一)”的笔记,我现在定义一个Cinema类:

#父类
class Cinema(object):sale_total=0 #所有影院的售票总数def __init__(self,name,address,sale):self.name=nameself.address=addressself.sale=sale #实例影院的售票数Cinema.sale_total=Cinema.sale_total+self.sale#Cinema实例的售票方式def sale_tickets(self,sale):self.sale=self.sale+saleCinema.sale_total=Cinema.sale_total+sale@classmethoddef get_sales(cls):return cls.sale_total

这是一个电影院售票的场景,假设售票情况如下:

cinema1=Cinema("影院1","万达广场",100)
cinema2=Cinema("影院2","万达广场",50)cinema1.sale_tickets(200)
cinema2.sale_tickets(100)print(Cinema.get_sales(),cinema1.sale,cinema2.sale)
# 450 300 150

假设Cinema在郊区开辟了一些小影院,虽然它们的售票情况没有Cinema中心地区的乐观(为了保持营业,sale_tickets方法会进行打折),但其他内容都不变,那我现在真的需要拷贝一下Cinema类的代码然后稍作修改吗?
为了提高复用效率,我可以选择类的继承:

#子类
class MiniCinema(Cinema):def sale_tickets(self,sale):#小影院为了保持营业,需要打折售票吸引游客if sale>100:sale=sale*0.8#super().代表会调用父类的成员super().sale_tickets(sale)

在继承这个问题上,需要注意类成员变量的层级(实例变量是互相独立的不会出现奇怪现象),改变子类的类成员变量不影响父类成员变量,改变父类的类成员变量会同步修改子类的类成员变量:


回到之前的那一段:

我个人理解,当通过super()调用父类成员,是直接性的复制了父类的代码,父类中的sale_tickets()中,类成员修改就是用Cinema访问的,因此修改了父类的类成员变量,子类的类成员sale_total也同步被修改;
创建实例时,在MiniCinema中没有__init__但也调用了,原因是继承了父类的__init__,在创建实例时自动执行,回忆一下,在初始化魔法方法中,我写过一句:Cinema.sale_total=Cinema.sale_total+self.sale
当我不调用sale_tickets(),创建子类实例时也修改了父类成员(在之前,sale_total是450):

从这可以看出一点,子类的继承就是从父类复制了代码;
对于多态,其实更好理解,比如:

minicinema.sale_tickets(200)

由于minicinema是子类的实例,调用同名方法会自动判断出应调用子类的方法,这就是多态
扩展:多继承
所谓多继承是指子类继承自多个父类,比如定义一个娱乐的类,它继承了电影院,餐厅,温泉等类:

class funny(Cinema,rest,spa):pass

关于继承,object是一切类的基类;
对于一个子类,有以下对象:
__base__:返回类的父类,用元组保存,
__mro__:返回一个元组,元素从左到右为类的继承顺序:

魔法方法__*__

魔法方法是定义在类中,有双下划线的特殊方法,如果在对应魔法方法名下进行修改,就可以进行特殊功能的定制
注意:魔法方法不能自己创建,只能修改,它是python类定义中特有的一种机制

#回顾以前说迭代器的next方法
def gen(n):for i in range(n):yield i**2#生成器一定是迭代器,必有next魔法方法
gener=gen(6)
#调用方式1
gener.__next__()
#调用方式2
next(gener)

在之前类设计中,常见__init__就是一个魔法方法,用于初始化,同样用于初始化的还有__new__方法(一般还是用init更多),实例生命周期结束时有__del__方法,现在我去其中添加我的语句,在执行时就会按照我的想法进行定制:

class myclass():def __init__(self):print("doing init")def __del__(self):print("doing del")mycls=myclass()
del mycls
"""
>doing init
>doing del
"""

想想以前说过的切片,为什么li[start: end: step]就能切片,而且step>0就是左闭右开规则,这与列表的__getitem__方法有关,而len能返回列表的元素个数与__len__方法有关,现在在我随意重写一个列表类,定制其len(返回2倍元素个数)和切片规则(左闭右闭):

#定义一个新列表类,修改魔法方法对常见方法进行定制
class FunctionList():def __init__(self,values):self.values=valuesdef __len__(self):return len(self.values)*2def __getitem__(self,key):#如果传入的key是slice类,则这是一个切片访问if type(key)==slice:start=key.startstop=key.stop+1 #不再左闭右开,而是左闭右闭return self.values[start:stop]li=FunctionList([0,1,2,3,4,5,6,7,8])
len(li)
#相当于
li.__len__()#对于以往的列表,step>0时切片是左闭右开的
li_or=[0,1,2,3,4,5,6,7,8]
print(li_or[0:3])#修改了__getitem__后,FunctionList类的实例列表切片为左闭右闭
print(li[0:3])


描述符descriptor

描述符是一种对类中属性的控制,有一点修饰的意思;
在类中,还有一种特别的装饰器:property,该装饰器(也是一个数据描述符)将类中的读写方法变成了一种属性读写的控制,property多用于私有成员的读和写控制;

class Student():def __init__(self,name):self.__name=name"""注意描述符格式"""#getter,方法名不能与实例变量重名@propertydef name(self):return self.__name#setter@name.setterdef name(self,new_name):self.__name=new_namestudent=Student('hack')
print(student.name)
student.name='baijingyi'
print(student.name)


可见,通过property修饰,方法调用被转为属性一样的读写,换句话说,属性读写得到了控制

类工厂函数和元类

类工厂函数可以通过函数调用返回一个类:

from collections import namedtuple  #返回一个类
User=namedtuple('User',['name','gender','age'])#用这个类去创建实例
user=User('baijingyi','male',20)
print(user)
print(type(user))#或者用列表去创建实例
userli=User._make(['baijingyi','male',20])
print(userli)
print(type(user))


类工厂函数是函数调用返回类,元类则是类的类,即所有类都是元类的实例,这也反映了python一切皆对象这个原则,这个metaclass出现了多次,就是type:


type()函数依次传入3个参数:
1.class的名称
2.class继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3.class的方法名称与函数绑定


看起来有些麻烦,不过可以轻松一点,因为实际创建类一般不会用type

模块和包

模块就是一个文件,包是各个文件的组合
对于包,要注意:
1.文件夹下必须有__init__.py文件
2.路径必须可以被python搜索到
3.第三方包安装后位于/Lib/site-packages
关于python搜索的路径,可以用sys查看:

import sys
print(sys.path)

当某个包不在路径下,可以强行添加进path:

sys.path.append("my-package-dir")

补充:网站pypi:python package index,可以将自己的包上传到网站,审核通过后就能pip安装了

第八课.Python面向对象(二)相关推荐

  1. Python面向对象二 封装与修饰器

    Python面向对象二 封装与修饰器 1. 特殊方法 2. 封装 2.1 封装的引入 2.2 封装实例一 2.3 封装实例二 3. property装饰器 1. 特殊方法 • 在类中可以定义一些特殊方 ...

  2. 第八课 Python Web企业门户网站-人工智能拓展

    目录 8.1 人工智能概述 8.2 搭建"人工智能"开放平台 8.2.1 人脸检测后台搭建 8.2.2 本地脚本测试 8.2.3 前端说明页面 8.3 在线人脸检测 8.1 人工智 ...

  3. 第七课.Python面向对象(一)

    面向对象编程 在面向对象的编程中,有两个重要概念:类和对象: 类class:同一事物的抽象,像一个描述实例的模板,比如汽车类包含了各种具体的现实中的汽车: 对象Object:某个类的具体实例insta ...

  4. 第五课.Python函数(二)

    函数参数的默认值修改 在函数(一)中看到,函数内部也有很多对象,现在再补充一个对象:__defaults__,该对象保存了参数的默认值,并以元组形式存在,如果手动修改其内容,函数的关键字参数赋值将被覆 ...

  5. Python 面向对象(二)

    Python 的面向对象和其他语言不一样,python的class术语与c++有一定区别,与 Modula-3更像. 1 设计面向对象 设计分成下面的两个方面,一定要先设计,找好对象,找类 1 面向对 ...

  6. Python面向对象二(第十二讲)

    文章目录 知识点 1.私有属性与私有方法 1.私有属性 2.私有方法 2.成员 3.实例属性 1.类属性(静态属性) 2.属性总结 4.实例方法 5.类方法 6.静态方法 7.封装介绍 8.继承(重点 ...

  7. python matlab大数据,Python第八课:Python数据分析基础

    今天,我们主要讲讲Python中怎么进行数据计算.简单的绘图,至于复杂的后续再讲. Python中进行数据分析及画图,用得最多的是三个库:Pandas.Numpy.Matplotlib,这三个库可以在 ...

  8. 第四十八课第十二章Managing Indexes

    第十二章Managing Indexes 本章目标 1.列出索引的不同类型和作用 2.创建不同的索引 3.重新组织索引 4.维护索引 5.监控索引的使用 6.获取索引信息 索引分类 1.逻辑分类 ①单 ...

  9. Python 面向对象(二)类的继承

    class people:#定义基本属性name = ''age = 0#定义私有属性,私有属性在类外部无法直接进行访问__weight = 0#定义构造方法def __init__(self,n,a ...

最新文章

  1. Nmap/Netcat/Hping3工具对比
  2. 面试必问:设计模式遵循的面向对象设计原则!
  3. 【知识图谱】知识存储
  4. mongoDB的副本机制
  5. Android之Android Studio 快捷键整理分享
  6. java word模板替换多行_Java动态替换word模板的最佳实践
  7. mysql索引的种类
  8. 2021年中国中性段开关检测器市场趋势报告、技术动态创新及2027年市场预测
  9. oracle触发器实例
  10. 数字供销方案、供销社数字化、信息化
  11. Bluefish 1.1.3
  12. 千万别在微社区太投入
  13. 【高质量编程指南笔记】
  14. 树上战争 HDU-2545
  15. 小程序地图定位授权取消后再次授权
  16. 修改header-隐藏身份
  17. 大数据和云计算技术周报(第182期)
  18. linux打通任督二脉百度网盘,2020-07-28-打通多平台发布的任督二脉
  19. 专业名词解析(待更新)
  20. 我的世界java版tp_我的世界原来还存在边界?Java版边界穿越方法

热门文章

  1. SpringBoot巧用 @Async 提升API接口并发能力
  2. 有钱任性!字节跳动又给员工发钱了!字节程序员:吓一跳,莫名其妙多了几万块!...
  3. 记录一次生产环境中Redis内存增长异常排查全流程!
  4. 阿里巴巴领导抱怨家里有矿的应届生不好带!聪明效率高,但从不加班,也不做职业规划!画饼谈心也没用,怎么办?...
  5. 开发Java,市值一度超过两千亿美元,造福无数程序员的Sun公司,也最终“陨落”...
  6. 如何成为顶尖管理者?
  7. 记一次有惊无险的 JVM 优化经历!
  8. 养娃时做过的蠢事,程序员必看!
  9. 管理者如何打造一个有执行力的团队?
  10. 当谷歌员工来到新公司的那一天,发现原来公司什么都没有