zoukankan      html  css  js  c++  java
  • 〖Python〗-- 递归、面向对象初识及编程思想

    【递归、面向对象初识及编程思想】

    一、递归

    1、定义:

      在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

      (1)递归就是在过程或函数里调用自身;
      (2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。

     
    1 def age(n):
    2     if n ==1:   #条件判定
    3         return 10  #返回一个结果
    4     else:
    5         return age(n-1)+2  #重复调用函数本身,系统会将运算的结果存放到栈,然后再依次的进行取值调用。
    6 print(age(5))   #打印结果
     

     执行结果:18

    2、优缺点:  

      递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

      递归的缺点:递归算法解题的运行效率较低。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。

     
    def func():
        print("*******")
        func()
    func()
    
    #执行结果
     [Previous line repeated 993 more times]
    *******
      File "F:/py_fullstack_s4/day26/递归.py", line 8, in func
    *******
        print("*******")
    *******
    RecursionError: maximum recursion depth exceeded while calling a Python object
     

    3、递归编程的注意点:

      1. 必须有一个明确的结束条件。

      2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少。

      3.递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)。

    4、此处引出一个新的知识点:二分法

      二分法,是一种快速查找的方法,时间复杂度低,逻辑简单易懂,总的来说就是不断的除以2除以2...

      他主要应用于有序序列中,原理是每次查找都将原序列折半,逐渐缩小查找范围的一种算法。应用于递归,循环之中,直到找到结果。

     
    #运用 递归 和 二分法 的运算方式,查找列表中的某个值
    data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
    num = int(input("please input your want to find number:"))
    def search(num,data):
        if len(data) > 1:      #排除列表分割,仅剩一个元素的情况
             #二分法#
            a = int(len(data)//2)   #将计算列表的长度,除以2  取整数
            mid_value = data[a]     #取当前中间的值
            if num > mid_value:     #要找的值 大于 中间的值
                data = data[a:]     #将原列表从中间值往后,取出来,构建一个新列表
                search(num,data)    #递归判断
            elif num < mid_value:   #要找的值 小于 中间的值
                data = data[:a]     #将原列表开始到中间值,取出来,构建一个新列表
                search(num,data)    #递归判断
            else:                   #正好是这个值
                print("find it!!",num)
                return          #打印
        else:                         #判断列表分割,仅剩一个元素的情况
            if data[0] == num:
                print('find it!! %s'%data[0])
            else:                     #列表中没有这个值
                print('not this num %s'%num)
    
    search(num,data)
    
    #执行结果:
    please input your want to find number:18
    find it!! 18
     

     

    二、面向对象的程序设计

    1、前提铺垫:

      python中一切皆为对象,python 3统一了类与类型的概念,类型即是类。例如:int,str,list,等等……

      编程语言中,是先有了类,然后再产生一个个对象。而现实生活中正好相反。

      明确一点:面向对象编程是一种编程方式,此编程方式的功能需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用

      类就是一个模板,模板里可以包含创建多个函数,函数里实现自定义的功能

      对象则是根据模板创建的实例,通过实例(对象)可以执行类中定义的函数

    2、语法:

      1)创建类:class是关键字,表示类 class *** #创建类
      2)创建对象:类名称后加括号 将结果赋给一个变量 即可 x = ***() #创建对象

     

     
     1 class hello:  #任意定义一个类
     2     camp = 'hello world'
     3     def f(self):
     4         print("f")
     5 h = hello() # 类实例化
     6 print(h) #打印
     7 
     8 #执行结果:
     9 
    10 <__main__.hello object at 0x00000000026C9630>
     

    3、类与对象

    1)什么是对象:
      以游戏举例:英雄联盟,每个玩家选一个英雄,每个英雄都有自己的特征和和技能,特征即数据属性,技能即方法属性,特征与技能的结合体就一个对象。

    2)什么是类:
      从一组对象中提取对象共同的 特征,技能,构成一个类。类也是特征与技能的结合体,特征即数据并且是所有对象共享的数据,技能即函数属性并且是所有对象共享的函数属性。 

      ①优点:解决了程序的扩展性,对某个对象进行修改,会立刻反映到整个体系中
      ②缺点:可控性差,无法预测最终的结果。
      面向对象的程序设计并不是程序全部。对于软件质量来说,面向对象的程序设计只是用来解决扩展性的问题。

    def 或是 class 都是在定义一个函数名。class 定义 类    camp 阵营    attack(self) 技能    nickname昵称    init 开始,初始

    3)如何使用类:
     一、实例化

      类的实例化就会产生一个实例(对象)。 可以理解为类加()把虚拟的东西实例化,得到具体存在的值,叫做类的实例化。

     
        camp = 'Demacia'
    def attack(self):
        print('attack')
    g1 = Garen() #类的实例化,产生一个对象,可以调用类内包括的所有特征(共性)。
    print(g1)  #打印
    
    #执行结果:
    <__main__.Garen object at 0x00000000028C9CC0>
     

     二、类通过.(点)的方式引用特征(类的变量)和技能(类的函数(类内部还是定义的函数,调用的话还是需要传入参数))

     
    class Garen:
        camp='Demacia'
        def attack(self):
            print('attack')
    print(Garen.camp)  #查看camp
    print(Garen.attack)   #打印数据类型
    Garen.attack('nihao') #由于是调用有参函数,需要传值
    
    #执行结果:
    Demacia
    <function Garen.attack at 0x000000000229C950>
    attack
     

    2、对象之间也有不同,及除了同性也有特性。例如昵称!

     
    class Garen:
        camp='Demacia'
    
        def __init__(self,nickname):
            self.nick=nickname  #给实例自己定义一个别名,由外部传入 #g1.nick = '草丛伦'
        def attack(self,enemy):
            # print('---------->',self.nick) #g1.nick
            print('%s attack %s' %(self.nick,enemy))
    
    
    g1=Garen('草丛伦') #类实例化,类Garen触发调用_init_ #Garen._init_(self,'NB')
    g2=Garen('刘下')
    print(g1.nick)
    g1.attack('alex')
    
    #执行结果:
    草丛伦
    草丛伦 attack alex
     

    self 指自己。

    注意:类的实例化就会自动触发类内_init_函数的执行。

    3、怎么调用类的特征与技能

    注意:类与对象之间的绑定方法。调用绑定方法,python 会自动传值,会将调用者本身当作参数传给self,第一值。
    print(gi.attack) #调用绑定方法,类绑定给g1
    print(Garen.attack) #函数

     
    class Garen:
        camp='Demacia'
    
        def __init__(self,nickname):
            self.nick=nickname  #给实例自己定义一个别名,由外部传入 #g1.nick = '草丛伦'
        def attack(self,enemy):
            # print('---------->',self.nick) #g1.nick
            print('%s attack %s' %(self.nick,enemy))
    
    
    g1=Garen('草丛伦') #类实例化,类Garen触发调用_init_ #Garen._init_(self,'NB')
    g2=Garen('刘下')
    
    print(g1.nick)  #昵称
    print(g1.camp)  #阵营
    print(g1.attack)  #打印 查看绑定方法
    print(Garen.attack)  # 打印 函数
    
    #执行结果:
    草丛伦
    Demacia
    <bound method Garen.attack of <__main__.Garen object at 0x0000000002299D68>>
    <function Garen.attack at 0x000000000229C9D8>
     

    Garen.attack(参数)# 调用的是函数,需要传参
    g1.attack('alex') #self = g1;enemy = 'alex'若是函数有多个值,就在赋值的时候,传入其他的参数。

    print(g1.nick)

    只要是对象触发的,调用的时候就会自动给调用的函数传值,将自身传到第一个参数self。若是函数有多个值,就在赋值的时候,对应的传入其他的参数。

     
    class Garen:
        camp='Demacia'
    
        def __init__(self,nickname):
            self.nick=nickname  #给实例自己定义一个别名,由外部传入 #g1.nick = '草丛伦'
        def attack(self,enemy):
            # print('---------->',self.nick) #g1.nick
            print('%s attack %s' %(self.nick,enemy))
    
    
    g1=Garen('草丛伦') #类实例化,类Garen触发调用_init_ #Garen._init_(self,'NB')
    g2=Garen('刘下')
    print(g2.nick)
    print(g2.camp)
    
    #执行结果:
    刘下
    Demacia
     

    三、总结:
    1、类:一:实例化,二:引用名字(类名.变量名,类名.函数名) 得到一个内存地址,加()就能运行。

    2、实例(对象):引用名字(实例名.类的变量,实例名.绑定方法,实例名.实例自己的变量名)

    3、类:
     优点:解决了程序的扩展性,对某个对象进行修改,会立刻反映到整个体系中
     缺点:可控性差,无法预测最终的结果。
      面向对象的程序设计并不是全部。对于软件质量来说,面向对象的程序设计只是用来解决扩展性的问题。

    在python中,用变量表示特征,用函数表示方法,因而类是变量与函数的结合体,对象是变量与方法(指向类的函数)的结合体

    4、类属性:特征(变量)和方法(函数)

    5、类有两种方法:1.类的实例化;2.属性引用
      1.实例化:
        类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
      2.属性引用:
        类名.方法

    6、对象也称为实例

      对象的属性:对象本身就自有特征(变量)

      对象的只有一种用法:属性引用

    7、类的名称空间和对象的名称空间

    创建一个类,就会创建一个类的名称空间,存放类中定义的属性:特征(数据)和方法(函数)
    创建一个对象,及类的实例化,就会创建一个类的名称空间,存放对象的属性。

    注意:对象就是类的实例化,类完成实例化的操作就已经将类的方法绑定到对象上,对象调用方法会现在自己的名称空间去找,找不到会去类的名称空间去找,再找不到会抛异常。它不会去找全局的定义。

    查看类的名称空间 类名._dict_
    查看对象的名称空间 对象名._dict_

    绑定方法的核心在于‘绑定’,唯一绑定到一个确定的对象

    可以调用:查
    print(Garen.camp) #查

    可以更改:改
    Garen.camp='aaaaaa' #改
    print(Garen.camp)

    可以删除: 删
    del Garen.camp #删除
    print(Garen.camp)

    可以添加: 增
    Garen.x=1 #增加特征
    print(Garen.x)

    关于对象(实例)

    可以调用: 查
    g1=Garen('alex')
    print(g1.nick) #查

    可以更改: 改
    g1.nick='asb' #改
    print(g1.nick)

    可以删除: 删
    del g1.nick
    print(g1.nick) #删

    可以增加: 增
    g1.sex='female'
    print(g1.sex) #增加

    四、面向对象的软件开发:

    分为五部:

    1、面向对象分析(object oriented analysis,OOA):
    产品经理调研市场,考察,明确软件的用途和应用场景。
    2、面向对象设计(object oriented design,OOD):
    根据需求,对每一部分进行具体的设计,例如:类的设计
    3、面向对象编程(object oriented programming,OOP):
    将设计编程成代码
    4、面向对象测试(object oriented test,OOT):
    对写好的代码进行测试,发现错误并改正。面向对象的测试是用面向对象的方法进行测试,以类为测试的基本单元。
    5、面向对象维护(object oriented soft maintenance,OOSM):
    解决用户使用产品过程中出现的问题,或是增加新的功能。

    面向对象编程思想:
    1、设计的时候,一定要明确应用场景

    2、由对象分析定义类的时候,找不到共同特征和技能不用强求

  • 相关阅读:
    条目二十八《正确理解由reverse_iterator的base()成员函数所产生的iterator的用法》
    条目二十六《iterator优先于const_iterator、reverse_iterator以及const_reverse_iterator》
    ubuntu16.04 能启动mysql服务
    《[MySQL技术内幕:SQL编程》读书笔记
    条目二十五《熟悉非标准的散列容器》
    稳健的漫步~~~
    条目二十四《当效率至关重要时,请在map::operator[]与map::insert之间谨慎做出选择》
    条目二十三《考虑用排序的vector替代关联容器》
    条目二十一《总是让比较函数在等值情况下返回false》
    条目二十二《切勿修改set或multiset的键》
  • 原文地址:https://www.cnblogs.com/SHENGXIN/p/7577937.html
Copyright © 2011-2022 走看看