python学习之函数

  • 三元运算表达式
    • a = 1
    • b = 2
    • c = a if a > b else b # c 等于 如果a大于b得a,否咋等于b
  • 编程方式
    • 1、面向过程式编程:根据业务逻辑从上到下垒代码实现功能
    • 2、函数式编程:将某功能代码封装到函数中,日后使用相同功能时,无需重复编写,直接函数调用即可
    • 3、面向对象编程:对函数进行分类和封装,让开发“更快更好更强”
  • 函数式编程
    • 函数定义
      • 将可以实现某种功能,可重复使用的,组织在一起的代码块
    • 函数的作用
      • 增强代码的重用性和可读性
    • 函数语法
      • def 函数名 (参数可有可无)
        • 函数体(代码块)
        • return
    • 函数返回值 return
      • 函数执行完毕后,返回给调用者的结果(调用者需通过定义变量接受)
      • 函数一遇到return就结束,不再执行后面的代码,结束函数
        • 不写return ,python内置规定默认返回None
        • return None ,返回None
        • return 单个值 ,返回此单个值
        • return 多个值 ,将多个值包含在(元组)中,返回给调用者(可通过定义解构来直接接受)
    • 函数参数
      • 形参:函数定义时,声明的变量即括号里的变量
        • 位置参数
        • 默认参数
          • def fun(a,b,c ="默认值"):
          • 1、必须先声明位置参数,才能声明默认参数
        • 动态参数
          顺序:位置参数,*args,默认参数,**kwargs

          • 1、第一种:动态的位置参数
            • 语法:def fun(*args):pass
            • 传参:将多个参数以元组的形式传给函数
            • args 是元组,它包含了所有实参传过来的位置参数
          • 2、第二种:动态的关键字参数
            • 语法:def fun(**kwargs): pass
            • 传参:将多个参数以字典的形式传给函数,传参格式必须为“key”= “value”
            • kwargs 是字典,它包含了所有实参传过来的关键字参数
          • 3、第三种:无敌传参
            • 语法:def fun(*args,**kwargs):pass
            • *,**的作用:
              • 形参:聚合 (将元素聚合成元组,字典)
              • 实参:打散 (打散成各个元素,当变量传给函数)
      • 实参:调用者调用函数时实际给函数传的值
        • 位置参数
          • 实参与形参个数、位置必须一一对应
        • 关键字参数
        • 混合参数
          • 1、位置参数与关键字参数混合使用
          • 2、必须先写位置参数、后关键字参数,不然报错:(SyntaxError: positional argument follows keyword argument)
      • 作用域:
        • 在计算机执行自定义的函数时,计算机只会把函数名放在内存中,而函数体不会放在内存当中,因此在pycharm执行函数时,并不会真正的运算函数,函数内的语句题没有执行,只有遇见函数名()时才会在内存中圈定一块函数的运行区域,使函数开始执行
        • 全局命名空间
          • 直接在py文件中,函数外声明的变量都属于全局命名空间
        • 局部命名空间
          • 函数中声明的变量会放在局部命名空间
        • 内置命名空间
          • 存放python解释器提供的变量名称,list,tuple,str,int这些都是内置命名空间
        • 加载顺序:
          • 内置-全局-局部
        • 取值顺序
          • 局部-全局-内置
        • 作用域命名空间
          • 1、全局作用域:全局命名空间+内置命名空间(函数外面的)
          • 2、局部作用域:局部命名空间(函数里面的)
          • 查看方式:
            • 1、globals()函数查看全局作用域中的内容
            • 2、locals()函数查看局部作用域中的变量和函数信息
        • 改变变量的作用域
          • 1、global 变量 将函数局部作用域中的变量改成全局变量(也就是调用全局)
          • 2、nonlocal 变量 将当前局部作用域变量,改成上一级作用域中的变量(调用上级作用域)
            如果上一级没有该变量,继续找上一级,直到找到为止(非全局),否则返回空
        • 函数名
          第一类对象:可以在运行期调用、可用作函数参数或返回值,可存入变量的实体(当普通变量使)
          • 1、函数名的内存地址,print(func),它是函数整体的地址;id(func)是单纯func这个变量名的地址
          • 2、函数名可以赋值给其他变量 如:f = func
          • 3、函数名可以当做容器类的元素 如:【func1,func2】或【func1(),func2()】
          • 4、函数名可以当做函数的参数 如: def f(func)
          • 5、函数名可以当函数的返回值
        • 闭包
        • 在python中对闭包有特殊的机制,遇到闭包,它会在内存中开辟一个空间,不会随着函数的结束而结束,所以方便了多次的调用,减少多次对内存空间的关闭或打开,增加了代码块的执行效率。
          内层函数对外层函数(非全局)的变量的引用
          • 检测是不是闭包,函数名.__closure__ #cell
            通过nolocal引用的上一级局部变量,该函数也是闭包​​
          • 装饰器都是闭包函数
          • 语法范例
            • def func(f):
              • a = 0
              • def inner():
                • print("此处调用外层函数的变量a或f,故inner函数为闭包函数",a)
              • return inner
        • 高阶函数
          • 两条件满足其一即可称为高阶函数
            • 1、函数名作为函数的返回值 return func_name
            • 2、函数名作为参数传入 func(fun_name)​
        • 装饰器(wrapper)
          • 定义:在不改变原函数的功能外(及调用方式),添加或扩展额外的功能
          • 开闭原则:对代码的扩展是开放的,对代码的修改是封闭的
          • 语法范例:(手写装饰器)
            • def wrapper_name (func):
              • def inner(*args,**kwargs):
                • """计划在执行功能函数前扩展的功能"""
                • ret = func(*args,**kwargs)
                • """计划在执行功能函数后扩展的功能"""
                • return ret
              • return inner
          • 装饰器调用:
            • func = wrapper_name(func)
            • func()
          • 语法糖调用:
            • 在需要扩展新功能的功能函数上方@装饰器函数名
            • @wrapper

     

       

  • 带参数的装饰器
    • 1、为了自定义是否使用扩展功能,更智能化,可以为是否使用扩展功能加个开关
    • 2、具体就是在装饰器函数外面再嵌套一层函数wrapper_out(flag),设定一个形参flag,返回值为装饰器函数名wrapper
    • 3、在inner函数里加一层判断flag为True使用附加功能,False为不添加附加功能
    • 3、在功能函数上加上@wrapper_out(True或者Falsh)
      •  1 # 带参数的装饰器
         2 # # 自定义是否使用添加的功能,故需要定义一个开关来是否执行通过装饰器添加的功能
         3 # # 1、如果在wrapper函数里添加的参数,就改变了调用装饰器的方式,因为调用装饰器时并没有给与参数:@wrapper
         4 # # 2、如果在inner函数里再添加参数,而inner函数里所有的参数都会给原功能函数,就会导致原功能函数执行异常
         5 """ 3、****故只能在wrapper函数外层再添加一层函数,加一个参数作为开关,来决定是否使用扩展功能,这就是装饰器添加参数***"""
         6 def wrapper_choice(flag):   # falg 是定义是否使用扩展功能的开关参数
         7     def wrapper(func_name):
         8         def inner(*args, **kwargs):
         9             if flag == True:    # 就使用扩展的功能
        10                 '''函数执行前添加的功能代码块'''
        11                 ret = func_name(*args, **kwargs)
        12                 '''函数执行后添加的功能代码块'''
        13                 return ret  # 返回执行结果
        14             else:  # 直接执行原函数,不要扩展功能
        15                 ret = func_name(*args, **kwargs)
        16                 return ret
        17         return inner  # 返回带有新功能且可以执行原函数的函数名
        18     return wrapper   # 返回装饰器函数名
        19 
        20 @wrapper_tell_you(True)  # 先执行右边的wrapper_tell_you(True)返回wrapper装饰器函数名,从而形成@wrapper
        21 def fun2(*args, **kwargs):
        22     pass
        23 fun2()  # 调用,相当于inner()调用
        带参数的装饰器

         

  • 装饰器的嵌套
    • 功能函数嵌套多层装饰器,记住取值顺序就不怕嵌套多少了
    • 装饰器中函数前添加的功能,函数后添加的功能可以用作括号来表示,中间是被装饰函数
      • 【 ( 被装饰函数 ) 】
      • 从左至右取值
      •  1 # 多个装饰器嵌套
         2 '''取值顺序:[   (    目标   )   ] 从左到右显示,
         3 最外层装饰器函数执行前功能、
         4 内层装饰器函数执行前功能
         5 原功能函数
         6 内层装饰器函数执行后功能
         7 最外层装饰器函数执行后功能'''
         8 def wrapper1(func1_name):
         9     def inner(*args, **kwargs):
        10         print("上车")
        11         ret = func1_name(*args,**kwargs)
        12         print("下车")
        13         return ret
        14     return inner
        15 
        16 def wrapper2(func2_name):
        17     def inner(*args, **kwargs):
        18         print("出发了……")
        19         ret = func2_name(*args, **kwargs)
        20         print("到站了……")
        21         return ret
        22     return inner
        23 
        24 def wrapper3(fun3_name):
        25     def inner(*args, **kwargs):
        26         print("计划去东莞了……")
        27         ret = fun3_name(*args, **kwargs)
        28         print("不虚此行,质量不错……")
        29         return ret
        30     return inner
        31 
        32 @wrapper3
        33 @wrapper2
        34 @wrapper1
        35 def by_car():
        36     print("去浪了……")
        37     return
        38 
        39 by_car()
        40 '''
        41 结果为:
        42 计划去东莞了……
        43 出发了……
        44 上车
        45 去浪了……
        46 下车
        47 到站了……
        48 不虚此行,质量不错……
        49 '''
        装饰器的嵌套取值顺序

         

  • 函数的注释:
    • 在函数体第一行用三个双引号将需要注释的内容写在里面,包括函数是干嘛的、函数的参数、函数的返回值
    • 语法:
      • def func_name(args):
        • """函数的注释内容"""
        • pass
    • 函数注释的查看:print(func_name.__doc__)
  • 函数名的查看:(因如果函数被装饰过,就不是它本来的名字了,而是装饰器返回来的inner)
    • 1、未被装饰过的函数名查看方法:print(func_name.__name__)
    • 2、被装饰过的函数需先导入模块、再在装饰器inner函数上面加一个装饰器@wrap(func_name)
    • 2.3、通过print(fn.__name__) 查看到的就不是inner而是本身的fn函数名了
    •  1 # 函数名的显示
       2 '''
       3 1、未加装饰器函数的函数名查看
       4 print(func_name.__name__)
       5 2、加了装饰器的函数,因为看起来还是原来的函数名,实际是返回来的inner函数名,
       6    故python做了一个优化,加了个功能,将函数名转换回来
       7 2.1、导入模块 from functools import wraps
       8 2.2、在inner函数上方加一个固定装饰器 @wraps(func_name)
       9 '''
      10 from functools import wraps
      11 def wrapper(fn):
      12     @wraps(fn)   # 这个代码的作用,将inner的__name__替换成fn的__name__
      13     def inner(*args, **kwargs):
      14         print("功能1")
      15         ret = fn(*args, **kwargs)
      16         return ret
      17     return inner
      18 @wrapper
      19 # 原功能函数
      20 def fun2(*args, **kwargs):
      21     pass
      22 print(fun2.__name__)  # fun2
      函数名的查看
  • 迭代器
      • 迭代器协议:必须为可迭代对象提供一个next方法,执行该方法要么返回迭代的下一项,要么就引起一个stopIteration的异常,终止迭代(只能往前走,不能回退)
      • 可迭代对象iterable:内部含有__iter__方法的对象、遵循可迭代协议、str、list、tuple、dict、set、range(int、float不是)
        • 判断是否为可迭代对象:print("__inter__" in dir(对象)) 或 from collections import Iterable;print(isinstance(对象,Iterable))
      • 迭代器iterator:内部含有__iter__和__next__方法的对象、遵循迭代器协议
        • 判断是否为迭代器:print("__iter__" and "__next__" in dir("djsks".__iter__())) 或 from collections import Iterator;print(isinstance(对象,Iterable))
      • 可迭代对象转成迭代器:对象.__iter__()
      • 迭代器的好处:节省内存、满足惰性机制(运行一次在内存中取一次值)、不能反复取值,只能从前到后,下一次接着上一次后面取,不可逆
      • 有哪些用了迭代器:for、sum、max、min等
      • for循环函数就是迭代器最好的例子
        • 1、通过__iter__()方法将可迭代对象转换成迭代器【对象.__iter__()】
        • 2、通过__next__()方法进行取值【对象.__next__()】
        • 3、通过异常处理机制规避报错
      • -----------------------下例以while模拟-------------------------------
      • lis = [11,33,44,55,66]
      • while True:
        • try:
          • gn = lis.__iter__()
          • print(gn)
        • except Exception:
          • break
      • -------------------------end--------------------------------------------
  •   生成器
      • (一般是函数)内部带有关键字yield的对象,生成器的本质是迭代器,遵循迭代器协议(所有的生成器一定是迭代器,反之不一定)
      • 函数中如有yield就不是普通的函数而是生成器,yield功能类似如return,为调用者返回函数执行结果,但yield后还有编码,不结束,而return是直接结束函数
      • --------------------示例------------------------
      • def func():
        • print("你想吃啥")
        • a = yield 2222
        • print(222)
        • yield 3333 # 出现yield就是生成器
      • gn = func() # gn就是迭代器
      • print(gn.__next__()) # 生成器调用元素,到第一个yield结束,等待第二次继续调用
      • print(gn.__send("红烧鲤鱼")
      • -----------------------------------------------------
      • send()和next()执行方法一样,都是返回一个迭代器内部的元素,使光标向后移动一个位置,但send可以上上一个yield传递一个参数,默认传none,改变上一个yield的值;第一次调用不能用send的因为第一个前面没有yield;最后一个元素不能改变其值
posted @ 2018-06-19 13:16  Alive_2020  阅读(227)  评论(0编辑  收藏  举报