python学习笔记day6(递归、二分法,面向对象初始)
一.递归函数(人能理解函数,神能理解递归)
什么是递归?递归就是自己调用自己本身,一般循环100多次不能解决的问题,就放弃使用递归,下面给出简单示例一看便知:
类似这样函数在不断调用自己本身,就是递归,但大家也会发现,当执行到一定次数之后,函数就会报错退出,这是因为python内部有一个机制
当达到一定次数之后,程序就会自动退出,下面我们简单测试下:
从这里可以看出,当调用达到998次之后,程序就自动报错退出,但是真正开发,如果调用100多次还没解决问题,就要放弃使用递归,否则影响效率。
案例一:看这样一个需求:
# 郭靖比黄蓉大三岁 4
# 黄蓉比欧阳锋大三岁 3
# 欧阳锋比黄老邪大三岁 2
# 黄老邪今年23岁 1
*** 用递归实现郭靖今年多少岁??
定义几个参数,假设分别为1,2,3,4,然后用递归写一个函数来实现这个需求:
上述函数就简单实现了递归,从上面可以看出,这里先分为四层,也就是age(4)里面传递的4,然后进入函数,执行else条件,此时函 数返回age(3)+3,接下来执行age(3)函数,这时返回age(2)+3+3,然后执行age(2)函数,这时返回age(1)+3+3+3,此时执行age(1)函数,执行if条件语句,返回23+3+3+3 = 32,结果就是32.另外说一下,递归函数都是带有返回值,必须有return
案例二:实现这一一个需求,1 1 2 3 5 8 13 21 。。。。也就是说后一个数是前两个数的和,然后利用递归函数求第十个数是?
分析:这个需求的规律就是前两个数之和是后一个数 fun(n) = fun(n-1) = fun(n-1),接下来我们试着用函数实现它:
如上就简单实现了这个需求,这里我们拿fun(5)为例简单分析,当调用fun(5)函数时:
二.二分法查找
二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。
此方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。接下来给出示例说明下:
案例一:利用递归函数,通过二分查找方法去寻找目标值的索引
三.面向对象编程(上帝的思维)
1.面向对象编程介绍:
请用程序描述如下事情:
- A同学报道登记信息
- B同学报道登记信息
- C同学报道登记信息
- A同学做自我介绍
- B同学做自我介绍
- C同学做自我介绍
考虑现实生活中,我们的思维方式是放在学生这个个人上,是学生做了自我介绍。而不是像我们刚刚写出的代码,先有了介绍的行为,再去看介绍了谁。
用我们的现实思维方式该怎么用程序表达呢?
- 面向过程:根据业务逻辑从上到下写代码
- 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程
面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程的思路是将数据与函数按照执行的逻辑顺序组织在一起,数据与函数分开考虑。
今天我们来学习一种新的编程方式:面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)
-
1)解决菜鸟买电脑的故事
第一种方式:
1)在网上查找资料
2)根据自己预算和需求定电脑的型号 MacBook 15 顶配 1W8
3)去市场找到苹果店各种店无法甄别真假 随便找了一家
4)找到业务员,业务员推荐了另外一款 配置更高价格便宜,也是苹果系统的 1W
5)砍价30分钟 付款9999
6)成交
回去之后发现各种问题
第二种方式 :
1)找一个靠谱的电脑高手
2)给钱交易
-
面向对象和面向过程都是解决问题的一种思路而已
-
买电脑的第一种方式:
- 强调的是步骤、过程、每一步都是自己亲自去实现的
- 这种解决问题的思路我们就叫做面向过程
-
买电脑的第二种方式:
- 强调的是电脑高手, 电脑高手是处理这件事的主角,对我们而言,我们并不必亲自实现整个步骤只需要调用电脑高手就可以解决问题
- 这种解决问题的思路就 是面向对象
-
用面向对象的思维解决问题的重点
- 当遇到一个需求的时候不用自己去实现,如果自己一步步实现那就是面向过程
- 应该找一个专门做这个事的人来做
- 面向对象是基于面向过程的
-
需要了解的定义性文字:
面向对象(object-oriented ;简称: OO) 至今还没有统一的概念 我这里把它定义为: 按人们 认识客观世界的系统思维方式,采用基于对象(实体) 的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。
面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。
2.类和对象
面向对象编程的2个非常重要的概念:类和对象
对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类
类就相当于制作飞机时的图纸,用他来进行创建的飞机就相当于对象
类:人以类聚 物以群分。 具有相似内部状态和运动规律的实体的集合(或统称为抽象)。 具有相同属性和行为事物的统称
类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象
对象:某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。 可以是直接使用的
类和对象之间的关系:
小练习:区分类和对象:
奔驰汽车 类 奔驰smart 类
张三的那辆奔驰smart 对象
狗 类 大黄狗 类
李四家那只大黄狗 对象
水果 类 苹果 类 红苹果 类 红富士苹果 类
我嘴里吃了一半的苹果 对象
3.类的构成
类有三部分构成:
类的名称:类名
类的属性:一组数据
类的方法:允许对类进行操作的方法,也就是行为
<1> 举例:
1)人类设计,只关心3样东西:
- 事物名称(类名):人(Person)
- 属性:身高(height)、年龄(age)
- 方法(行为/功能):跑(run)、打架(fight)
2)狗类的设计
- 类名:狗(Dog)
- 属性:品种 、毛色、性别、名字、 腿儿的数量
- 方法(行为/功能):叫 、跑、咬人、吃、摇尾巴
4.类的抽象
如何把日常生活中的事物抽象成程序中的类?
拥有相同或者类似的属性和行为的对象都可以抽象成一个类
方法:一般名词都是类(名词提炼法)
<1> 坦克发射3颗炮弹轰掉了2架飞机
- 坦克--》可以抽象成 类
- 炮弹--》可以抽象成类
- 飞机-》可以抽象成类
<2> 小明在公车上牵着一条叼着热狗的狗
- 小明--》 人类
- 公车--》 交通工具类
- 热狗--》 食物类
- 狗--》 狗类
<3>【想一想】如下图中,有哪些类呢?
说明:人、枪、子弹、手榴弹、刀子、箱子
<4>【想一想】如下图中,有哪些类呢?
说明:
- 向日葵
- 类名: xrk
- 属性:
- 行为: 放阳光
- 豌豆
- 类名: wd
- 属性: 颜色 、发型,血量
- 行为:发炮, 摇头
- 坚果:
- 类名:jg
- 属性:血量 类型
- 行为:阻挡;
- 僵尸:
- 类名:js
- 属性:颜色、血量、 类型、速度
- 行为:走 跑跳 吃 死
5.定义类:
这里的class就是定义类的关键字,用来定义一个类,Person是我们自定义的类的名称,animal和soup是我们定义在类里面的静态变量,work是我们定义的动态方法。
接下来再看这样一段代码:
可以看出这段程序比上述程序多了一个__init__方法,这里要记住python中凡是带有双下划线的方法都统称为魔法方法,它们都有特殊作用,这里的__init__方法就是py中的构造方法,他的作用就是在实例化对象的时候,就传递相应的参数然后调用这个方法。
类如何调用查看静态变量动态变量方法:
1.类名.__dict__方法 只能查看,不能增删改。
2.类名.变量名 可增删改查
3.一般你想查询全部的静态变量时,用__dict__ 其他全部都用类名.变量名
类操作方法有两种方式:
(1).类名.__dict__["方法名"]
(2).通过类名.方法名来调用
如果类名操作方法:类名.方法名()
只要创建一个类,里面的内容就已经自动加载到内存中了
4.对象
实例化一个对象:类名()
例如: p1 = Person()
p2 = Person()
p1 对象,实例化对象,类名()过程就叫做实例化。
` 只要实例化对象,就自动触发__init__方法,内部有三部:
(1).实例化一个对象,在内存中产生一个对象空间
(2).自动执行__init__方法,并将这个对象空间传给self
(3).通过构造方法里面的代码给空间对象添加一些属性方法,并返回给对象
5.对象如何查看调用静态变量,动态变量
对象操作属性变量有两种方法:
(1).对象.__dict (只能查看)
(2).对象.变量名 (可以增删改查)
(3).可以访问类的静态变量:
一般你想查询全部的静态变量时,用__dict__ 其他全部都用类名.变量名。
对象操作方法有两种方式:
(1).对象.方法名()
(2).类名.方法名(对象)
6.小知识:上述的self约定俗成就叫self,也可以改,但最好不要更改
通过实例化对象查找属性,先从对象空间找,没有则通过类对象指针从 类空间找。
练习一:在终端输出如下信息:
小明,10岁,男,上山去砍柴
小明,10岁,男,开车去东北
小明,10岁,男,最爱大保健
老李,90岁,男,上山去砍柴
老李,90岁,男,开车去东北
老李,90岁,男,最爱大保健
7.组合
组合:给一个类对象的属性 封装 另一个类的对象,接下来我们一步步引入:
(1)创建一个游戏类,分别实例化一个奥特曼和一个怪兽对象,输出奥特曼攻击了怪兽,怪兽还剩多少血量
(2)在上述基础上添加一个武器类,实例化一个激光灯类,输出奥特曼用激光灯攻击了怪兽,怪兽还剩多少血量
上述程序就实现这样的需求,但仔细一想,奥特曼拿激光灯攻击怪兽,主题应该是人,而不像程序中写的那样,主题是激光灯,因此这里就用到了组合,再次改版将上述的主体改为人:
8.面向对象(oop)三大特点,封装、继承、多态。
(1).什么是继承:
在现实生活中,继承指的是子女继承父辈的财产:
在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够,如下所示:
继承可以有效的节省代码,如下示例就是一个简单的继承案例:
如上就是继承,Anima就是父类,也叫基类,而Cat 和 Dog 叫子类,也可以叫派生类。
python3x 中,所有的类都默认继承object类,继承object类的类称为新式类。
python中类分为两种:新式类,经典类。但是python3x中只有新式类。
新式类 :遵循的广度优先。
经典类 :遵循的深度优先。
继承又分为:单继承,多继承。
(2)问题一:看下述代码,猜测哪个方法先执行:
这里是执行顺序的问题,当实例化一个对象调用的时候,会先从自己对象空间也就是子类里面寻找方法,如果找到就停止查找,如果找不到就一直往上查找,直到找到为止。
问题二:假设子类的属性和方法与父类的一致,如何使用父类的属性和方法呢,这里用到了super关键字:
(3).新式类:遵循的广度优先:
单继承示例:
多继承:钻石继承
经典类:深度优先
Python2 中默认是经典类,如果改成新式类 就让 类继承(object)
多继承: