• Python 函数


    一、函数

    1、什么是函数:函数就是具备某一功能的工具

        函数的使用必须遵循先定义、后调用的原则

          事先准备工具的过程即函数的定义

          拿来就用即为函数的调用

        函数分为两大类:1、内置的函数   2、自定义的函数

    2、为什么要用函数:

          2.1 程序的组织结构不清晰、可读性差

          2.2 日积月累冗余代码过多

          2.3 程序的可扩展性极差

    3、怎么用函数

    3.1定义函数  

    3.1.1 语法 

    # def 函数名(参数1,参数2,参数3,...):
    #     """
    #     文档注释
    #     """
    #     code1
    #     code2
    #     code3
    #     ...
    #     return 返回值

    3.1.2 定义函数阶段发生哪些事:只检测语法,不执行代码

    def foo(): # foo=函数的内存地址
        print('first')
        print('sencod')
        print('asdfsadfasdfas')
        print('third')
    foo()
    # # 定义阶段
    def foo():
        print('from foo')
        bar()
    
    def bar():
        print('from bar')
    
    #调用阶段
    foo()

    3.1.3 定义函数的三种形式

        1.无参函数

    def bar():
        print('from bar')
    bar()

        2.有参函数

    def func2(x,y):
        # x=1
        # y=3
        if x > y:
            print(x)
        else:
            print(y)
    
    func2(1,3)

        3.空函数(做占位使用)

    def foo():
        pass

    3.2调用函数

    语法:函数名()   

    调用函数发生了:1、根据函数名找到函数的内存地址  2、函数的内存地址加括号可以触发函数体代码的执行

    调用函数的三种方式:

    3.2.1 语句

    def f1():
        print('from 1')
    f1()

    3.2.2表达式

    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    
    res=max(1,2)*10
    print(res)

    3.2.3当做参数传给其他函数

    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    
    res=max2(max2(1,2),3)
    print(res)

     4、函数的返回值

    1、什么是函数的返回值:函数体代码运行的一个成果

      return 值:

        返回值没有类型限制、返回值没有个数限制

          逗号分割多个值:返回一个元组

          一个值:返回一个值

          没有return:默认返回None

    def login():
        while True:
            username=input('name>>: ').strip()
            pwd=input('password>>:').strip()
            if username not in user_dic:
                print('not found')
                continue
            if pwd != user_dic[username]:
                print('pwd error')
                continue
            print('login successful')
            return username
    print(login())
    return 登录名
    # return是函数结束的标志:
    # 函数内可以有多个return,但只要执行一次,整个函数就立即结束,并且将return后的值当作本次调用的结果返回

    二、函数的参数

    1、函数的参数分为两大类:形参、实参

        形参:指的是在定义函数时,括号指定的参数,本质就是变量名

        实参:指的是在调用函数时,括号内传入的值,本质就是值

      只有在调用函数时才会在函数体内发生实参(值)与形参(变量名)的绑定关系

      该绑定关系只在调用函数时临时生效,在调用函数结束后就解除绑定

        def foo(x,y): #x=1,y=2
            print(x)
            print(y)
        # a=1
        # b=2
        # foo(a,b)
        foo(1,2)

    2、位置参数

        位置形参:在定义函数时,按照从左到右的顺序依次定义的形参称之为位置形参

           ps:但凡是按照位置定义的形参,在调用函数时必须为其传值,多一个不行少一个也不行

        位置实参:在调用函数时,按照从左到右的顺序依次传入的值

           ps:传值是按照顺序与形参一 一对应

    def foo(x,y,z):
        print(x,y,z)
    # foo(1,2)
    foo(1,2,3,4)#多传一个值  报错
    # foo(1,2,3)
    foo(3,2,1)

    3、关键字实参:

             在调用函数时,按照key=value的形式定义的实参,称之为关键字实参
          注意:
          1、在传值时可以完全打乱顺序,但仍然能指定道姓地为指定的参数传值
          2、可以在调用函数时,混合使用位置实参与关键字实参
          但是位置实参必须跟在关键字实参左边
          并且不能为一个形参重复传值

    def register(name,sex,age):
        print(name)
        print(sex)
        print(age)
    register(sex='male',name='mogu',age=18)
    register('mogu',age=18,sex='male')#混合使用

    4、默认参数

        在定义函数时,就已经为某些参数绑定值,称为默认参数

          ps:1、在定义阶段就已经有值,意味在调用阶段可以不用传值

            2、默认形参必须放在位置形参的后面

            3、默认形参的值只在定义阶段生效一次,在函数定义之后发生的改动无效

            4、默认形参的值通常应该是不可变类型

      默认形参:大多数情况下值都一样

      位置形参:大多数情况值都不同

    def foo(x,y,z=3):
        print(x)
        print(y)
        print(z)
    foo(1,2)
    foo(1,2,4) #传值后改变了默认值
    def register(name,age,sex='female'):
        print(name)
        print(sex)
        print(age)
    register('mogu',18)
    register('xiaohuochai',28)
    register('momo',19)
    register('张三',33,'male')
    默认与位置示例
    m=10
    def foo(x,y,z=m):
        print('x:%s' %x)
        print('y:%s' %y)
        print('z:%s' %z)
    m=111111111    #定义阶段就是10   此更改无效
    foo(1,2)
    def foo(name,hobby,l=None):
        if l is None:
            l=[]
        l.append(hobby)
        print('%s 的爱好是 %s' %(name,l))
    l1=[]
    foo('mogu','read',l1) #l1=['read']
    foo('xiaomogu','movie')  #l1=['read','music']
    foo('nvhai',' 卖火柴')
    foo('张三','吹牛')
    foo('关二爷','耍大刀')
    默认形参示例2

    5、可变长度的参数

        可变长度指的是在调用函数时,函数参数的个数可以不固定

    然而实参终究是要为形参传值的,针对两种形式实参个数不固定,对应着形参也必须有两种解决方案

    那就是 * 和 ** 来分别处理溢出位置实参与溢出关键字实参

    5.1 * 会将溢出的位置实参存成元组,然后赋值给紧跟其后的变量名

    5.1.1 形参中带 *

    def foo(x,y,*z): #z=(3,4,5,6,7,8)
        print(x)
        print(y)
        print(z)
    foo(1,2,3,4,5,6,7,8)

    5.1.2  形参中带*   实参中带 * ,窍门:但凡碰到实参中带*  都先将其打散成位置实参,然后考虑传值

    def foo(x,y,*z): #z=(3,4,5,6,7,8)
        print(x)
        print(y)
        print(z)
    foo(1,2,[3,4,5,6,7,8]) #z=([3,4,5,6,7,8],)
    foo(1,2,*[3,4,5,6,7,8]) #foo(1,2,3,4,5,6,7,8)====>z=(3,4,5,6,7,8)
    foo(1,2,*'hello') #foo(1,2,'h','e','l','l','o')
    foo(1,*[2,3,4,5,6])  #foo(1,2,3,4,5,6)

    5.1.3 实参中带 *  窍门同上

    def foo(x,y,z):
        print(x,y,z)
    l = ['mogu', 'huochai', 'nvhai']
    foo(*l) # foo('mogu', 'huochai', 'nvhai')

    5.2  ** 会将溢出的关键字实参存成字典,然后赋值给紧跟其后的变量名

    5.2.1 形参中带 **

    def foo(x,y,m,n,**z): #
        print(x)
        print(y)
        print(m)
        print(n)
        print(z)
    foo(1,2,n=10,m=20,a=1,b=2,c=3)
    View Code

    5.2.2 形参中带 **  实参中带 **  窍门:但凡碰到实参中带**  都先将其打散成位置实参,然后考虑传值

    def foo(x,y,**z): #
        print(x,y,z)
    foo(1,2,**{'a':1,'b':2,'c':2}) #foo(1,2,c=2,a=1,b=2)
    foo(1,**{'a':1,'b':2,'c':2,'y':111}) #foo(1,c=2,a=1,b=2,y=111)

    5.2.3 实参中带**

    def foo(x,y,z):
        print(x,y,z)
    foo(1,**{'y':111,'z':222}) #foo(1,y=111,z=222)
    foo(**{'z':1,'y':2,'x':3}) #foo(y=2,z=1,x=3)

     6、 *args  和 **kwargs

    可接收任意长度,任意格式的参数(ps:实参中:位置实参必须在关键字实参的左边)

    def foo(*args,**kwargs):
        print(args,kwargs)#可完美转嫁
    
    foo(任意长度,格式的实参)
    #需要将外层函数的参数格式原封不动的转嫁给其内部调用的函数,就需要以下
    def index(name,age,sex):
        print('name:%s age:%s sex:%s' %(name,age,sex))
    def foo(*args,**kwargs):
        index(*args,**kwargs)#可完美转嫁
    
    foo('mogu',sex='male',age=18)#虽然调用的是foo函数,但是需要遵循        
                                                       index函数的参数规则
    示例

    三、函数对象

    函数是第一类对象,意味着函数可以当做数据去使用

    def foo():
        print('from foo')

    引用

    print(foo)
    func=foo
    print(func)
    func()

    当做参数传给另外一个函数

    def bar(x): #x=foo的内存地址
        print(x)
        x()
    bar(foo)

    当做函数的返回值

    def bar():
        return foo
    f=bar()
    # print(f is foo)
    f()

    当作容器类型的元素

    def f1():
        print('from f1')
    def f2():
        print('from f2')
    l=[f1,f2]   #列表内全为函数体
    print(l)
    l[1]()
    l[0]()

    四、函数的嵌套调用

    1、嵌套调用

      在调用一个函数时,其内部的代码又调用其他的函数

    def bar():
        print('from bar')
    
    def foo():
        print('from foo')
        bar()
    foo()
    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    #
    def max4(a,b,c,d):
        res1=max2(a,b)
        res2=max2(res1,c)
        res3=max2(res2,d)
        return res3
    
    print(max4(1,2,3,4))
    数值大小比较

    2、嵌套定义

    在一个函数的内部又定义了另外一个函数

    def f1():
        x=1
        def f2():
            print('from f2')
        print(x)
        print(f2)
        f2()
    f1()

    五、名称空间和作用域

    1、什么是名称空间:名称空间是存放名字与值绑定关系的地方

      要取到值必须通过名字才能找,而名字又在名称空间中存放着,所以取值时首先去名称空间中找名字

        找到了名字自然拿到值的内存地址。

    2、名称空间分为三种:

      2.1 内置名称空间:存放的python解释器自带的名字

          生命周期:在解释器启动时产生,在解释器关闭时回收

      2.2 全局名称空间:除了内置的与局部的之外名字都属于全局名称空间

          生命周期:在程序文件执行时就立刻产生,在程序执行完毕后就回收

    x=1
    y=2
    def foo():
        x=1
        y=2
    foo()
    if y > x:
        print(x)
    z=3
    # 其中:x,y,foo,z都是全局名称空间中的名字

    2.3 局部名称空间:存放的是函数内部定义的名字

          生命周期:在调用时临时生效,在函数结束后立刻回收

    len=100
    # print(len) # 站在全局查找
    
    def foo():
        len=2222
        print(len)  #先在局部查找
    foo()

    加载顺序

      内置名称空间--->全局名称空间--->局部名称空间

      加载名称空间的目的是为了将名字与值的绑定关系存放起来

      而存的目的是为了取,也就是当我们查找名字时,必然是在三者之一中找到

    查找顺序

      局部名称空间--->全局名称空间--->内置名称空间

      基于当前所在位置往后查找

    x=100
    y=200
    
    # 强调:函数的形参名属于局部名称空间
    def foo(x,y):
        print(x,y)
    
    foo(1,2)    #print结果为1,2
    x=2222
    def f1():
        # x=1
        def f2():
            # x=2
            print('from f2',x)
        f2()
    
    x=111
    f1()   #print结果为   from f2  111
    ps:全局查找
    x=2222
    def f1():
        # x=1
        def f2():
            x=2           #先在局部查找
            print('from f2',x)
        f2()
    
    x=111
    f1()          #结果为  from f2   2
    ps:局部查找

    3、作用域

      域指的是范围,作用域指的是作用范围

        3.1.全局作用范围:包含内置名称空间与全局名称空间中的名字

            特点:全局有效,全局存活

        3.2.局部作用范围:包含局部名称空间中的名字

            特点:局部有效,临时存活

    x=1
    
    def f1():
        def f2():
            def f3():
                x=3   #函数此处有值  所有全局的x=1 并不会取
                print(x)
            f3()
        f2()
    
    f1()   #函数调用会先在函数内部寻找,所有结果为 3
    #
    def foo():
        print(x)
    
    foo()  #而此处函数内部未定义x  所以会找全局   1
    作用范围
    #如何打破函数层级带来的访问限制,让我能够在任意位置都可以访问到一个内部函数
    # 基于函数对象的概念将一个内部函数返回(return)到全局使用,从而打破了函数的层级限制

    3.3.函数的作用域关系是在函数定义阶段就已经固定死的,与函数的调用位置无关

      即在调用函数时一定要跑到定义函数的位置寻找作用域关系

    x=111
    def outter():
        x=33333
        def inner():
            print('from inner',x)
            # x=4444   #此处再定义会报错
        return inner
    x=222
    f=outter() #f=指向outter.locals.inner
    f()     #结果为from inner  33333
    作用域关系

    3.4.  global 和  nonlocal

    global :在局部声明名字是来自全局的

    x=1
    def func():
        global x   #声明x为全局
        x=2          #所以此处即修改了全局的x
    func()
    
    print(x)  #结果为 2

    nonlocal :声明变量来自当前层外层(必须在函数内)

    x=222
    def f1():
        x=111
        def f2():
            # nonlocal x
            x=3
            print('f2---->',x) #f2----->  3
        f2()
        print('f1---->',x)  # f1------->  111
    
    f1()
    print('global------>',x)   #global------> 222
    无nonlocal结果
    x=222
    def f1():
        x=111
        def f2():
            nonlocal x
            x=3
            print('f2---->',x) #f2----->  3
        f2()
        print('f1---->',x)  # f1------->  3
    
    f1()
    print('global------>',x)   #global------> 222
    有nonlocal结果

    六、装饰器

    一、闭包函数(函数体传值的新方式)

      1、 -------->定义在函数内部的函数

      2、 -------->该内部函数包含对其外层函数作用域名字的引用

    闭包函数通常需要结合函数对象的概念,将闭包函数返回到外部使用

    #闭包函数基本形式
    def outter():
        x=1
        def inner():
            print(x)
        return inner
    # 将值包给函数
    import requests  #导入爬虫模块
    # def outter(url):
    #     #url='https://www.jd.com'
    #     def get():
    #         response=requests.get(url)
    #         print(len(response.text))
    #     return get
    #
    # jd=outter('https://www.jd.com')#第一调用传入京东
    # jd()   #  以后调用只需要 jd加括号就能得到结果, 新的传值方式
    示例:闭包应用

    二、装饰器

      装饰指的是为被装饰对象添加新的功能

      指的工具

      装饰器本身是任意可以调用的对象,被装饰对象也是任意可以调用的对象

    ps:写一个函数用来为另一个函数添加新功能,需要遵循开放封闭原则(对修改是封闭的,对扩展是开放的)

      1、不修改被装饰对象的源代码

      2、不修改被装饰对象的调用方式

    import time
    
    def index():   #被装饰对象
        time.sleep(2)
        print('welcome to index page')
    #
    # index()  #原先功能
    def outter(func): #func=最原始index
        def wrapper():
            start_time=time.time()
            func()  #上方的index() 原先功能
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time)) #加入新功能
        return wrapper
    
    index=outter(index) #index=wrapper 加入新功能,并且调用方式没变
    index()
    装饰器的示例
    import time
    
    def home(name):  #有参
        time.sleep(1)
        print('welcome %s to home page' %name)
        return 'lalala'
    
    def timmer(func): #func=最原始index
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs) #原封不动转嫁参数
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    
    home=timmer(home)  #home=warapper
    print(home('mogu'))
    被装饰对象有参

    二、1、装饰器的语法糖  

      在被装饰对象正上方单独一行写上@装饰器名字

    import time
    
    def timmer(func): #func=最原始index
        def wrapper(*args,**kwargs):
            start_time=time.time()
            res=func(*args,**kwargs)
            stop_time=time.time()
            print('run time is %s' %(stop_time-start_time))
            return res
        return wrapper
    
    
    @timmer #index=timmer(index)
    def index():
        time.sleep(1)
        print('welcome to index page')
        return 'lalala'
    index()
    装饰器的语法糖!!
    import time
    
    current_userinfo={'user':None}
    
    def outter(func):
        def wrapper(*args,**kwargs):
            if current_userinfo['user']:
                return func(*args,**kwargs)
            user=input('please input you username: ').strip()
            pwd=input('please input you password: ').strip()
            if user == 'mogu' and pwd == '123':
                print('login successfull')
                # 保存登录状态
                current_userinfo['user']=user
                res=func(*args,**kwargs)
                return res
            else:
                print('user or password error')
    
        return wrapper
    
    @outter # index=outter(index)
    def index():
        print('welcome to index page')
        time.sleep(3)
    
    @outter #home=outter(home)
    def home(name):
        print('welecom %s ' %name)
        time.sleep(2)
        return 123
    
    index() # wrapper()
    res=home('mogu') # res=wrapper('mogu')
    认证功能装饰器

    二、2、添加多个装饰器

    import time
    
    current_userinfo={'user':None}
    
    def timmer(func): #func=最原始的index指向的内存地址
        def wrapper2(*args,**kwargs):
            print('wrapper2.....')
            start=time.time()
            res=func(*args,**kwargs) # func=最原始的index指向的内存地址
            stop=time.time()
            print('run time is %s' %(stop - start))
            return res
        return wrapper2
    
    def outter(func): # func=wrapper2
        def wrapper1(*args,**kwargs):
            print('wrapper1.....')
            if current_userinfo['user']:
                return func(*args,**kwargs)
            user=input('please input you username: ').strip()
            pwd=input('please input you password: ').strip()
            if user == 'mogu' and pwd == '123':
                print('login successfull')
                # 保存登录状态
                current_userinfo['user']=user
                res=func(*args,**kwargs) # func=wrapper2
                return res
            else:
                print('user or password err')
        return wrapper1
    
    
    # 解释语法的时候应该自下而上
    # 执行时则是自上而下
    # 可以连续写多个装饰器,处于最顶层的装饰器先执行
    @outter  # index=outter(wrapper2) # index=wrapper1
    @timmer # timmer(最原始的index指向的内存地址) ==>wrapper2
    def index():
        print('welcome to index page')
        time.sleep(3)
    
    index() #wrapper1()
    多个装饰器使用

    二、3、有参数的装饰器

    import time
    
    current_userinfo={'user':None}
    
    def auth(engine='file'):#参数代表认证模式
        def outter(func): #func=最原始的index
            def wrapper(*args,**kwargs):
                if engine == 'file':#if判断认证模式
                    if current_userinfo['user']:
                        return func(*args,**kwargs)
                    user=input('please input you username: ').strip()
                    pwd=input('please input you password: ').strip()
                    if user == 'mogu' and pwd == '123':
                        print('login successfull')
                        # 保存登录状态
                        current_userinfo['user']=user
                        res=func(*args,**kwargs)
                        return res
                    else:
                        print('user or password err')
                elif engine == 'mysql':
                    print('mysql 的认证机制')
                    res = func(*args, **kwargs)
                    return res
                elif engine == 'ldap':
                    print('ldap 的认证机制')
                else:
                    print('不支持该engine')
            return wrapper
        return outter
    
    @auth(engine='mysql') #@outter # index=outter(最原始的index) # index= wrapper
    def index():
        print('welcome to index page')
        time.sleep(3)
    
    @auth(engine='ldap')
    def home(name):
        print('welecom %s ' %name)
        time.sleep(2)
        return 123
    
    index() #warpper()
    home('蘑菇') #wrapper('蘑菇')
    View Code

    二、4、wraps装饰器

      被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的decorator来消除这样的副作用。

    #wraps作用将被装饰对象属性赋值给 装饰器的wrapper
    import time
    from functools import wraps
    
    def timmer(func):
        @wraps(func)
        def wrapper(*args,**kwargs):
            start=time.time()
            res=func(*args,**kwargs)
            stop=time.time()
            print('run time is %s' %(stop - start))
            return res
        # wrapper.__doc__ = func.__doc__
        # wrapper.__name__= func.__name__
        return wrapper
    
    @timmer
    def index():
        """
        这是一个index函数
        :return:
        """
        print('welcome to index page')
        time.sleep(1)
        return 123
    
    print(help(index)) # index.__doc__
    
    # print(index.__name__)
    wraps 装饰器

    七、表达式,生成式

    三元表达式

      语法:【条件成立时的返回值】 +  if 条件    +  else【条件不成立时的返回值】

    # res=条件成立时的返回值 if 条件 else 条件不成立时的返回值
    
    def max2(x,y):
        if x > y:
            return x
        else:
            return y
    res=max2(1,2)
    
    x=10
    y=2
    
    res=x if x > y else y
    res=True if x > y else False
    print(res)
    三元表达式

    列表生成式

      语法: i  +    for循环   可以跟 【条件】

    # 原先列表生成
    l=[]
    for i in range(10):
        if i > 3:
            l.append(i)
    print(l)
    #列表生成式
    l1=[i for i in range(10) if i > 3]  
    
    print(l1)
    #原先操作列表
    user=input('>>>:').strip()
    names=['hello world','hello dream','hello %s'%(user)]
    l=[]
    for name in names:
        if name.startswith('he'):
            l.append(name.upper())
    names=l
    print(names)
    #列表生成式操作
    user=input('>>>:').strip()
    names=['hello world','hello dream','hello %s'%(user)]
    names=[name.upper() for name in names if 
                  name.startswith('hello')]
    print(names)
    列表生成式:示例

    字典生成式

    info=[
        ['name','mogu'],
        ('age',18),
        ['sex','male']]
    #将列表转成字典:方法一
    d={}
    for item in info:
        d[item[0]] = item[1]
    print(d)
    
    #字典生成式   :方法二
    d={item[0]:item[1] for item in info}
    print(d)
    字典生成式
    d={
        'name':'蘑菇',
        'age':18,
        'sex':'male'
    }
    d={k.upper():v for k,v in d.items()}
    print(d)
    生成式改字典k的大小写

    语法:同列表一样   用到  for循环操作时优先考虑生成式操作

    八、函数的递归调用

    在调用一个函数的过程中又直接或间接的调用了自身。

    本质就是一个重复的过程,必须有两个明确的阶段

    1、回溯:一层一层地递归调用下去,每进入一层问题的规模都应该有所减少

    2、递推:递归必须有一个明确的结束条件,在满足该条件的情况下终止递归,往回一层一层地结束调用

    #询问年龄,第一个人说我比第二个人大2岁,第二个人说我比第三个人大2岁,。。。第六个人说“我18岁”
    # age(6) = age(5) + 2
    # age(5) = age(4) + 2
    # age(4) = age(3) + 2
    # age(3) = age(2) + 2
    # age(2) = age(1) + 2
    # age(1) = 18
    
    # age(n) = age(n-1) + 2 #n > 1
    # age(n) = 18           #n=1
    #
    
    def age(n):
        if n == 1:   #结束条件
            return 18
        return age(n-1) + 2  #基于上一次的结果调用自己
    
    print(age(6))
    示例1
    #  将一个列表中包含的值全部取出
    l=[1,[2,[3,[4,[5,[6,[7,[8,[9,]]]]]]]]]
    
    def tell(l):
        for item in l:
            if type(item) is list:
                #item 是列表
                # 再次调用本身的逻辑,传入item
                tell(item)
            else:
                #item是单独的元素
                print(item)
    
    tell(l)
    示例2
    #数字列表,数字是从小到大排列的
    nums=[3,11,13,15,23,27,43,51,72,81,93,101]
    
    #算法:就是如何高效地解决某一个具体问题的方法
    l1=[3,11,13,15,23,27]
    l2=[23,27]
    l3=[23]
    
    def binary_search(nums,find_num):
        print(nums)
        if len(nums) == 0:
            print('not exists')
            return
        mid_index=len(nums) // 2
        if find_num > nums[mid_index]:
            # in the right
            nums=nums[mid_index+1:]
            # 重复调用本身的逻辑,传入新的nums
            binary_search(nums,find_num)
    
        elif find_num < nums[mid_index]:
            # in the left
            nums=nums[:mid_index]
            # 重复调用本身的逻辑,传入新的nums
            binary_search(nums,find_num)
        else:
            print('find it')
    
    binary_search(nums,94)
    函数的递归调用+二分法

    九、匿名函数

      匿名函数lambda:临时用一次以后不再使用了。

    #格式:
    def sum2(x,y):
        return x + y
    print(sum2)
    
    sum2=lambda x,y:x + y
    wage={
        'I':3800,
        'BOSS':9999999,
        'friends':10000,
        'web celebrity':1000000
    }
    
    print(max(wage,key=lambda x:wage[x]))#匿名函数使用场景 最大
    print(min(wage,key=lambda x:wage[x]))#最小
    
    # 按照薪资高低排序人名
    print(sorted(wage,key=lambda x:wage[x])) #从小到大
    
    print(sorted(wage,key=lambda x:wage[x],reverse=True))#翻转

    十、迭代器,生成器,生成器表达式

     1、迭代器

      迭代器就是迭代取值的工具

      迭代是一个重复的过程,但是每一次重复都是基于上一次的结果而进行

    迭代器的作用:针对没有索引的数据类型,比如(字典、集合、文件)想要迭代取出其中包含的值

           python解释器提供了一种不依赖索引取值的工具

    # 可迭代的对象:在python中但凡内置有__iter__方法的对象都称之为可迭代对象
      (字符串、列表、元组、字典、集合、文件)
    str1 = 'hello'
    list1 = ['a', 'b', 'c']
    t1 = ('a', 'b', 'c')
    dic = {'x': 1, 'y': 2}
    set1 = {'m', 'n'}
    f = open('a.txt', mode='rt', encoding='utf-8')
    可迭代对象
    # 迭代器对象
    # 1、内置有__iter__方法,调用迭代器对象的__iter__方法得到仍然是迭代器本身
    # ps: 文件对象本身就是一个迭代器对象
    # 2、内置有__next__方法
    dic = {'x': 1, 'y': 2}
    
    iter_dic = iter(dic)   # iter_dic=dic.__iter__()
    #上面得到迭代器对象 iter_dic
    
    print(iter_dic.__next__())
    print(iter_dic.__next__())
    #就可以调__next__方法取值
    dic={'x':1,'y':2}
    iter_dic=iter(dic) # 调__iter__得到迭代器
    
    while True:
        try:      #检测异常
            k=next(iter_dic)    #执行__next__取值
            print(k)
        except StopIteration:  #接try 的检测   
            break
    
    -----------------------------------------------------------------
    #上述即为  for循环的   底层原理
    for循环运行机制!!

    总结

    迭代器的优点:
    一、提供了一种能够不依赖索引的、通用的迭代取值方式
        补充:for循环可以称之为迭代器循环

     list1=['a','b','c']
        for item in list1:
        print(item)

    for循环的工作流程
       1、调用 in 后面那个对象的__iter__方法,拿到一个迭代器对象
       2、调用迭代器对象的__next__方法,拿到一个返回值赋值给变量名item
       3、循环往复,直到抛出异常,for循环会自动捕捉异常结束循环

    二、节省内存

    迭代器的缺点:
      1、针对同一个迭代器对象只能取完一次,不如按照索引或者key取值方式灵活
      2、无法预测迭代器对象所包含值的个数

    2、生成器

    在函数内但凡出现yield 关键字,在调用函数就不会触发函数体代码的执行了,

    会得到一个返回值,返回值就是一个生成器对象

    而生成器对象本质就是迭代器(ps:生成器是自定义的迭代器)

    def foo():
        print('first')
        yield 1
        print('second')
        yield 2
        print('third')
        yield 3
        print('fourth')
    
    g=foo() #g是生成器=》就是迭代器
    g.__next__()
    g.__next__()
    g.__next__()

    上述会触发g对应的函数体代码的执行,直到碰到一个yield就暂停住,该yield后的值当做本次__next__的返回值返回

    print(g.__next__())
    print(g.__next__())
    print(g.__next__())

    总结yield的功能:

    1、提供了一种自定义迭代器的方式

    2、可以用于返回值

      yield和return的区别:

        相同点:都可以用于返回值,个数以及类型都没有限制

        不同点:yield可以返回多次值,return只能返回一次值整个函数就结束了

    3、函数暂停以及继续执行的状态是由yield保存的

    def my_range(start,stop,step=1):
        while start < stop: # 4 < 4
            yield start #start = 3
            start+=step #star=4
    #----------------------------------------------------------
    #range()的原理
    
    for i in my_range(1,5): # 1  3
        print(i)

    了解:yield关键字表达式形式的应用

    def cat(name):
        print('橘猫[%s]准备开吃' %name)
        food_list=[]
        while True:
            food=yield food_list#food=yield='鱼干'
            print('橘猫[%s]吃了: %s' %(name,food))
            food_list.append(food)
    #
    ct=cat('蘑菇')
    
    # 强调:针对表达式形式的yield,在使用生成器时必先send(None),相当于先完成一个初始化操作
    res0=next(ct) #ct.send(None)
    # print(res0)
    
    #send有两个功能:
    #1、为当前暂停位置的yield赋值
    #2、与next的效果一样
    ct.send('鱼干')
    # next(ct)
    # ct.send(None)
    ct.send('三鹿')
    res1=ct.send('鱼干')
    # print(res1)
    res2=ct.send('牛奶')
    print(res2)
    yield关键字表达式

     3、生成器表达式

     同上述列表、字典生成式一样的形式,只是两边换成了()

    l=[i**2 for i in range(1,11)]
    print(l)###列表生成式
    #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    #==================================
    l1=(i**2 for i in range(1,11))
    print(l1)
    #<generator object <genexpr> at 0x0000000001EC05C8>
    #()括号生成了一个迭代器对象,只要不调用l1,其内部就没有值,调一次next方法就取出一个值
    print(next(l1))

    优点是:

      更加节省内存

      自定义迭代器的方式

    十一、面向过程编程

    #=============复杂的问题变得简单
    #注册功能:
    #阶段1: 接收用户输入账号与密码,完成合法性校验
    def talk():
        while True:
            username=input('请输入你的用户名: ').strip()
            if username.isalpha():
                break
            else:
                print('用户必须为字母')
    
        while True:
            password1=input('请输入你的密码: ').strip()
            password2=input('请再次输入你的密码: ').strip()
            if password1 == password2:
                break
            else:
                print('两次输入的密码不一致')
    
        return username,password1
    
    #阶段2: 将账号密码拼成固定的格式
    def register_interface(username,password):
        format_str='%s:%s
    ' %(username,password)
        return format_str
    
    #阶段3: 将拼好的格式写入文件
    def handle_file(format_str,filepath):
        with open(r'%s' %filepath,'at',encoding='utf-8') as f:
            f.write(format_str)
    
    
    def register():
        user,pwd=talk()
        format_str=register_interface(user,pwd)
        handle_file(format_str,'user.txt')
    
    
    register()
    面向过程编程
    #1、首先强调:面向过程编程绝对不是用函数编程这么简单,
    面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。
    言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序
    #2、定义 面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么 基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式 #3、优点:复杂的问题流程化,进而简单化 #4、缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身 #5、应用:扩展性要求不高的场景,典型案例如linux内核,git,httpd #6、举例 流水线1: 用户输入用户名、密码--->用户验证--->欢迎界面 流水线2: 用户输入sql--->sql解析--->执行功能

    十二、补充内置函数

    链接地址:https://www.cnblogs.com/nixindecat/p/9599829.html#label5

  • 相关阅读:
    【反编译系列】一、反编译代码(dex2jar + jd-gui)和反编译资源(apktool)
    【Android Studio安装部署系列】目录
    Android快速开发常用知识点系列目录
    Android根据word模板文档将表单数据生成word文档的方案整理
    PoiDocxDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0),目前只能java生成】
    PoiDemo【Android将表单数据生成Word文档的方案之二(基于Poi4.0.0)】
    FreemarkerJavaDemo【Android将表单数据生成Word文档的方案之一(基于freemarker2.3.28,只能java生成)】
    XiaomiPushDemo【小米推送集成,基于V3.6.12版本】
    HWPushDemo【华为推送集成,基于2.6.1.301版本】
    JPushDemo【极光推送集成,基于v3.1.8版本】
  • 原文地址:https://www.cnblogs.com/nixindecat/p/9436201.html
Copyright © 2020-2023  润新知