• 函数部分总结


    一、自定义函数

      一、函数概念

        1、什么是函数:函数就是封装一个功能。(程序中如果没有函数的引用,会产生重复代码多,可读性差的特点。)

        2、函数的定义:def 关键词开头,空格之后接函数名称和圆括号()

    l1 = [1,2,3,4]
    def my_len():
        # def 关键字 定义一个函数
        # my_len 函数名书写规则与变量一样
        # def与函数名中间一个空格
        # 函数名():加上冒号
        # 函数体
        count = 0
        for j in l1:
            count += 1
        print(count)
    my_len()
    l1 = [1,2,3,4]
    def my_len():
        count = 0
        for j in l1:
            count += 1
        return count
    print(my_len())
    # 函数的返回值:
    # 写函数,不要在函数中写print()
    # return
    # 1、在函数中,遇到return结束函数。
    # 2、将返回值给函数的调用者。
    #   无 return = return None
    #   return 1个值 该值是什么,就直接返回给函数的调用者,函数名()
    #   return 多个值,将多个值放到一个元组中,返回给函数的调用者。

      二、函数的传参   

        函数分为形参和实参:

        形参:形式参数,不代表实际的变量。

        实参:实际参数,带入形参中的变量。

        形参传参:1、位置传参。按顺序,一一对应。

                2、默认参数。传参则覆盖,不传则默认,默认参数永远在位置参数的后面。

        形参传参:1、位置传参。按顺序,一一对应。

               2、关键字传参,不按顺序,一一对应。

               3、混合传参,关键字参数永远在位置参数的后面。

        形参传递顺序:位置参数,*args,默认参数,**kwargs

    def test(a, *args, **kwargs):
        print(a)    # 1
        print(args) # (2, 3)
        print(kwargs)   # {'e': 5, 'd': '4'}
    test(1, 2, 3, d='4', e=5)
     
    # 1还是参数a的值,args表示剩余的值,kwargs在args之后表示成对键值对。
    # * 魔法运用
    def func(*args):
        print(args)
    l1 = [1,2,30]
    l2 = [1,2,33,21,45,66]
    tu = (1,2,3)
    func(1,2,30,1,2,33,21,45,66)    # (1, 2, 30, 1, 2, 33, 21, 45, 66)
    func(*'qweqrfdsaf') # ('q', 'w', 'e', 'q', 'r', 'f', 'd', 's', 'a', 'f')
    func(*{'name':'alex',"age":12}) # ('name', 'age')
    func(*l1,*l2)   # (1, 2, 30, 1, 2, 33, 21, 45, 66)
    def func(*args):
        print(args)
    func(1,2,3,10,20,80)    # (1, 2, 3, 10, 20, 80)
    def func(**kwargs):
        print(kwargs)
    dic1 = {'name1':'alex','age1':46}
    dic2 = {'name':'老男孩','age':56}
    func(**dic1,**dic2) # {'age1': 46, 'name1': 'alex', 'name': '老男孩', 'age': 56}
    # 在函数的调用执行时,
    #   *可迭代对象,代表打散(list,tuple,str,dict(键))将元素一一添加到args。
    #  **字典,代表打散,将所有键值对放到一个kwargs字典里。
    
    # 在函数定义时, *args,**kwargs代表的是聚合。
    def func(*args,**kwargs):
        print(args)
        print(kwargs)
    dic1 = {'name1':'alex','age1':46}
    dic2 = {'name':'老男孩','age':56}
    func(*[1,2,3,4],*'asdfsad',**dic1,**dic2)
    # (1, 2, 3, 4, 'a', 's', 'd', 'f', 's', 'a', 'd')
    # {'name': '老男孩', 'name1': 'alex', 'age': 56, 'age1': 46}

      三、函数有用信息

    def func1():
        """
        此函数是完成登陆的功能,参数分别是...作用。
        :return: 返回值是登陆成功与否(True,False)
        """
        print(666)
        return True
    func1() # 666
    print(func1.__name__)   # func1
    print(func1.__doc__)    # 显示注释内容

    二、命名空间和作用域

      一、命名空间

        命名空间的本质:存放名字与值的绑定关系   

        命名空间一共分为三种:

          全局命名空间:代码在运行伊始,创建的存储“变量名与值的关系”的空间

          局部命名空间:在函数的运行中开辟的临时的空间

          内置命名空间:存放了python解释器

        三种命名空间之间的加载与取值顺序:

        加载顺序:内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载)

        取值:在局部调用:局部命名空间->全局命名空间->内置命名空间

        在全局调用:全局命名空间->内置命名空间

      二、作用域

        作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域。

        全局作用域(globals):包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用、全局有效

        局部作用域(locals):局部名称空间,只能在局部范围内生效

        global关键字

    #global
    # 1,在局部空间内,声明一个全局变量
    def func1():
        global name
        name = '老男孩'
        print(name) # 老男孩
    func1()
    print(name) # 老男孩
    # 2,在局部空间内改变一个全局变量
    a = 4
    def func1():
        global a    # 5
        a = 5
    func1()
    print(a)

        nolocal关键字

    #nonlocal
    # 1,不能修改全局变量。
    #在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,
    # 并且引用的哪层,从那层及以下此变量全部发生改变。
    a = 4
    def func1():
        b = 6
        def func2():
            b = 666
            print(b) # 666
        func2()
        print(b) # 6
    func1()
    
    b = 4
    def func1():
        b = 6
        def func2():
            nonlocal b
            b = 666
            print(b) # 666
        func2()
        print(b) # 666
    print(b)    # 4
    func1()

      三、函数名的应用

    # 函数名是函数的名字,本质:变量,特殊的变量。
    # 1,单独打印函数名  <function func1 at 0x0000000000872378>
    def func1():
        print(666)
    print(func1)  # <function func1 at 0x0000000000872378>
    a = 6
    print(a)    # 6
    # 2、函数名的赋值
    def func2():
        print(666)
    
    f = func2
    f() # 666
    # 3、函数名可以作为容器类数据的元素
    def f1():
        print(1211)
    def f2():
        print(1222)
    def f3():
        print(1233)
    def f4():
        print(1233)
    l1 = [f1, f2, f3, f4]
    for i in l1:
        i()
    # 4、函数名可以作为参数
    a = 1
    def f1(x):
        print(x)    # 1
    f1(a)
    def f1():
        print(666)
    def f2(x):  # x = f1
        x()  # f1()
    f2(f1)
    # 5、函数名可以作为函数的返回值
    def wraaper():
        def inner():
            print(666)
        return inner
    ret = wraaper()  # inner
    ret()  # inner()

    三、闭包和装饰器

      一、闭包

        闭包:就是内层函数对外层函数(非全局)变量的引用。

        闭包:当函数开始执行时,如果遇到闭包,他又一个机制,他会永远开辟一个内存空间,将闭包中的额变量等值放入其中,不会随着函数的执行完毕而消失。

        判断是不是闭包:内层函数名.__closure__ 结果是:cell...就是闭包

    name = '老男孩'
    def wraaper2(n):
        #  n = '老男孩'
        def inner():
            print(n)    # 老男孩
        inner()
        print(inner.__closure__)    # (<cell at 0x000001E3F9123B28: str object at 0x000001E3F9010F30>,)
    wraaper2(name)

      二、装饰器

        开放封闭原则:

        1、对扩展是开放的

        2、对修改是封闭的

        装饰器主要功能和装饰器固定结构:在不改变函数调用方式的基础上在函数的前、后添加功能。

        装饰器固定格式

    def timer(func):
        def inner(*args,**kwargs):
            '''执行函数之前要做的'''
            re = func(*args,**kwargs)
            '''执行函数之后要做的'''
            return re
        return inner

        带参数的装饰器

    def outer(flag):
        def timer(func):
            def inner(*args,**kwargs):
                if flag:
                    print('''执行函数之前要做的''')
                re = func(*args,**kwargs)
                if flag:
                    print('''执行函数之后要做的''')
                return re
            return inner
        return timer
    @outer(False)
    
    def func():
        print(111)
    
    func()

        多个装饰器装饰同一个函数

    def wrapper1(func):
        def inner():
            print('wrapper1 ,before func')  # 第二步
            func()
            print('wrapper1 ,after func')   # 第四步
        return inner
    
    def wrapper2(func):
        def inner():
            print('wrapper2 ,before func')  # 第一步
            func()
            print('wrapper2 ,after func')   # 第五步
        return inner
    
    @wrapper2
    @wrapper1
    def f():
        print('in f')   # 第三步
    f()

    四、迭代器和生成器

      一、迭代器

        可迭代协议:可以被迭代要满足的要求,可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代,内部实现了__iter__方法

        迭代协议:必须拥有__iter__方法和__next__方法

        迭代器的好处:

          1、节省内存空间。

          2、满足惰性机制。

          3、不能反复取值,不可逆。

         可迭代计算过程:

          1、将可迭代对象转化成迭代器

          2、内部使用__next__方法取值

          3、运用了异常处理去处理报错。    

    l2 = [1, 2, 3, 4, 5, 6, 7, 8]
    l2_obj = l2.__iter__()
    while True:
        try:
            i = l2_obj.__next__()
            print(i)
        except Exception:
            break

      二、生成器

        生成器:生成器本质上是迭代器。

        初始生成器:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

        生成器函数定义:

          1、一个包含yield关键字的函数就是一个生成器函数

          2、next 和send 功能一样,都是执行一次,send获取下一个值可以给上一个yield赋值。

          使用send的注意事项:第一次使用生成器的时候,使用next获取下一个值,最后一个yield不能接受外部的值

    def generator():
        print(123)  # 123
        content = yield 1
        print(content)  # hello
        print(456)  #456
        yield 2
    g = generator()
    g.__next__()
    g.send('hello')

      三、列表推导式和生成器表达式

        1、列表推导式:用列表推导式能够构建的任何列表,用别的都可以构建,一目了然,占内存。

    l2 = [i*i for i in range(1,11)]
    print(l2)   # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

        2、生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表,不易看出,节省内存。

    l_obj = ('python%s期' % i for i in range(1,12))
    print(l_obj)    # <generator object <genexpr> at 0x000001AAF0AEBDB0>
    print(l_obj.__next__()) # python1期
    print(l_obj.__next__()) # python2期
    print(l_obj.__next__()) # python3期

        总结:

          1.把列表解析的[]换成()得到的就是生成器表达式

          2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

          3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可 以直接这样计算一系列值的和:

    五、内置函数

        3.x版本python共提供68种内置函数

    详细内容见http://www.cnblogs.com/qiujie/p/8982773.html,内置函数思维导图:https://www.processon.com/view/link/5ae949b8e4b09b1bf63730c4

    六、匿名函数

        匿名函数:为了解决那些功能很简单的需求而设计的一句话函数。

    def calc(n):
        return n*n
    print(calc(10))
    
    cal = lambda n:n*n
    print(cal(10))

    上面是我们对calc这个匿名函数的分析,下面给出了一个关于匿名函数格式的说明

    函数名 = lambda 参数 :返回值
    
    #参数可以有多个,用逗号隔开
    #匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值
    #返回值和正常的函数一样可以是任意数据类型

    我们可以看出,匿名函数并不是真的不能有名字。

      匿名函数的调用和正常的调用也没有什么分别。 就是 函数名(参数) 就可以了~~~

      匿名函数与内置函数举例:

    l=[3,2,100,999,213,1111,31121,333]
    print(max(l))
    
    dic={'k1':10,'k2':100,'k3':30}
    print(max(dic))
    print(dic[max(dic,key=lambda k:dic[k])])
    
    # 31121
    # k3
    # 100
    
    res = map(lambda x:x**2,[1,5,7,4,8])
    for i in res:
        print(i)
    
    # 1
    # 25
    # 49
    # 16
    # 64
    
    res = filter(lambda x:x>10,[5,8,11,9,15])
    for i in res:
        print(i)
        
    # 11
    # 15

    七、递归函数

        递归:一个函数在内部调用自己的函数称为递归,递归的次数在python是有限制的,默认递归次数是997次。

    # 输出斐波那契第n个数
    def fib(n):
        if n==1 or n==2:
            return 1
        return fib(n-1)+fib(n-2)

    函数部分思维导图:https://www.processon.com/view/link/5ae94a2be4b09b1bf637320e

  • 相关阅读:
    [汇编与C语言关系]1.函数调用
    深入理解计算机系统
    设计模式
    深度探索C++对象模型
    More Effective C++
    MySQL必知必会
    数据结构与算法分析
    Java编程思想(后)
    Java编程思想(前十章)
    Java 入门
  • 原文地址:https://www.cnblogs.com/qiujie/p/8977972.html
Copyright © 2020-2023  润新知