• 第四篇 函数


    一.函数的定义

    # 函数的定义
    
    def 函数名(形参):
        '''
        文档字符串
        函数功能:
        函数参数:
        函数返回值
        '''
        function_body
        return [expression]
    
    # 函数的使用
    函数名(实参)
    # 1. 函数的定义
    def sayHello(name):
        print("你好,{},很高兴再次见到你".format(name))
    
        return "{}来北京看我了".format(name)
    
    
    #函数的调用
    print(sayHello("dali"))
    
    # 输出
    你好,dali,很高兴再次见到你
    dali来北京看我了
    # 2. 函数可以没有参数
    def Hello():
        a= 3+4
        return a
    
    print(Hello())
    
    #输出
    7
    # 3. 定义一个变量,给变量的赋值是个函数名,就相当于把这个变量变成一个函数了
    
    def sayHello2(name):
        print("你好,{},很高兴再次见到你".format(name))
        return 1
    message = sayHello2
    print(message("xiaochengzi"))
    
    # 输出
    你好,xiaochengzi,很高兴再次见到你
    1

    二.函数的参数

    1. 必备参数 或者 位置参数

    位置参数的特点:必须要给它传值,位置在最前面,定义了几个位置参数,调用函数的时候就必须传几个参数,否在会报错

    # x,y 是位置参数,位置参数就是必须参数,函数调用时不能缺少
    def add(x,y):
        return x+y
    
    print(add(2,3))   #5
    # 错误示例
    def add(x,y):
        return x+y
    
    print(add(2))  
    
    # TypeError: add() missing 1 required positional argument: 'y'

    2. 默认参数

    如果不想给某个参数传值,但是参数个数还不减少,那可以在函数声明时设置默认参数,就是给某个参数一个默认值,

    如果不传值,函数调用时,默认就用的是设置的默认参数,如果传值了,函数调用时就用的是传的值

    特点:默认参数的位置,一定要放到所有的位置参数的后面

    # # j 定义时就给了个默认参数,如果j不传值,就默认取0, 默认参数一定要放在所有参数的最后面
    def add1(i,j=0):
        return i+j
    
    print(add1(3))   # 3

    3. 不定长参数

    如果函数声明时,还不能确定到底会有多少个参数,可以定义不定长参数

    特点:1) 不定长参数用*args表示, 2) *args的类型是元组 3)它的位置必须在默认参数后面

    def add2(x,y=0,*args):
        print(args)
        return x + y
    
    print(add2(2))
    # 输出
    ()    # 此时x=2,y =0, *args没有传参,是个空元组
    2
    
    print(add2(4,5))
    #输出
    ()   # 此时x=4,y =5, *args没有传参,是个空元组
    9
    
    print(add2(1,3,5,7,9))
    # 输出
    (5, 7, 9)  # 此时x=1,y =3, *args是个元组,其值是(5,7,9)
    4
    def add2(x,y=0,*args):
        print(args)
        return x + y + sum(args)  # 使用参数,要去掉*号
    
    
    print(add2(1,3,5,7,9))
    
    #输出
    (5, 7, 9)
    25

    4. 关键字参数

    如果想传的参数是字典,就可以用关键字参数

    特点:关键字参数 **kargs ,其类型是字典,必须最最后面,以 a = 1的形式传参

    def add4(x,y,*args,**kwargs):
        print(kwargs)
        return x + y + sum(args) + sum(kwargs.values())
    
    print(add4(1,3,3,4,5,a=1,b=5,c=5,d=-5))
    
    # 输出
    {'a': 1, 'b': 5, 'c': 5, 'd': -5} # 此时,x=1,y=3, args=(3,4,5),kwargs = {'a': 1, 'b': 5, 'c': 5, 'd': -5}
    
    22

    5. 形参与实参

    三.函数的作用域

    函数作用域的寻找顺序:Local -> enclosing->global -> build-in

    1. L(Local)局部作用域

    变量是在函数内定义的

    a = 3  # 全局作用域
    
    def scope():
        a = 5   # 局部作用域
        print(a)
    
    scope()
    
    # 输出
    5

    2. E(Enclosing)闭包函数外的函数中

    见后面闭包的介绍

    3.G (Global)全局作用域

    变量是在函数外定义的,是整个文件的

    a = 3
    
    def scope():
        print(a)
    
    scope()
    #输出
    3

    4. B(Built-in) 内建作用域

    Python 自带的,预留的一些变量,函数名等

    Python自带的不太适合举例说明

    作用域的查找顺序是先局部,后全局,最后再内建,如果都没有该变量,就会报错

    def scope():
        print(a)
    
    scope()
    
    # NameError: name 'a' is not defined

    5. 作用域有两个函数:Locals() 和 globals()

    a = 3
    
    def scope():
        a = 5
    
    
    print(globals())
    # 输出
    {'__name__': '__main__', '__doc__': '
    作用域生效机制
    局部  闭包函数外的函数中 全局 内建
    
    ', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10511a470>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/qiaoersun/Documents/千万别删/测试/Codes/testfanStudyPractice/lesson02/作用域.py', '__cached__': None, 'a': 3, 'scope': <function scope at 0x10529bd08>}

    暂时还没弄明白

    四.闭包(_closure_)

    闭包的特点:

    1. 闭包函数必须有内嵌函数

    2. 内嵌函数需要引用嵌套函数的变量

    3. 闭包函数必须返回内嵌函数

    闭包的作用:

    1. Python闭包就是装饰器(或叫修饰器)

    2. 在不改原有函数任何内容的情况下,给原有函数增加功能

    def greeting(name):
        '''
        1.在greeting函数中内嵌了一个greet函数
        2.greeting函数的返回值是一个函数greet
    
        '''
        def greet():
            print(name)
        return greet   # 函数的返回值是greet函数
    
    # 定义一个func变量,调用greeting函数,因为greeting函数的返回值是greet,而greet也是个函数,所以就相当于func是个函数
    # 此时只是返回了greet,greet函数并没有被调用,所以也不会有任何返回值
    func = greeting('老刘')
    
    
    # 那么再调用func这个函数就等于是调用的下面的部分
    '''
        def greet():
            print(name)
    '''
    func()
    # 输出
    老刘
    # greeting()其实就是greet函数,那么也可以用下面的方式调用
    greeting("小猫")()
    # 输出
    小猫

    对闭包函数的公式总结

    def greeting(name):
        # 1. greeting函数里内嵌,嵌套了一个greet函数 --> 满足了:闭包函数必须有内嵌函数
        a = 5
        def greet():
            # 2.在内嵌函数里引用了嵌套函数(greeting)的变量:a 和 name, 这个变量必须是内嵌函数外层已经定义的,不能是全局变量--->
            # 满足了:内嵌函数必须要引用嵌套函数的变量
            print(name)
            print(a)
        # 3. greeting函数里返回了一个内嵌函数greet--->满足了:函数必须返回内嵌函数
        return greet   # 注意此处不能返回greet()
    
     # 4. 由上面3点的同时满足,才使得greeting成为一个闭包函数
     
     # 5. 闭包函数的调用,在上面已经有了,此处略

    在Python里闭包其实就是装饰器

    五.装饰器

     装饰器的作用:就是为已经存在的对象添加额外的功能

     装饰器的应用场景:插入日志,性能测试,事务处理,缓存,权限校验等等

    示例:计算一个函数执行用了多长时间

    '''
    闭包的作用:
    1. 在Python闭包就是装饰器(或叫修饰器)
    2. 在不改原有函数任何内容的情况下,给原有函数增加功能
    
    利用闭包实现修饰器
    '''
    
    '''
    1. 计算原有函数wait()的执行时间,但是不能改wait()函数的任何代码
    2. add()函数,把add()执行结果写入一个文件,不能改变add()函数的任何值
    '''
    
    
    import  time
    import random
    
    '''
    解决办法:用闭包的方式解决,那么就要把原来已经存在的功能,即函数作为参数传递给闭包,此处形参用func代替
    闭包一定是写在原还是的前面的
    '''
    # 2.用闭包的方式不改变原代码的情况下,新增计算时间的功能
    def decorator(func):
        def wrapper():
            startTime = time.time()
            result = func()
            endTime = time.time()
            print("测试结束,花费时间{}秒".format(endTime-startTime))
            return result   # 上面已经执行过了result,这里为什么还要再返回一下result?不返回会有什么影响?
        return wrapper
    
    '''
    wait函数是已经存在的一段代码,假设有一万行,突然有个需求,要在wait上加一个功能,计算wait函数执行需要花多长时间
    如果直接在wait函数上改,可能会引起其他bug,第二你也懒得看wait的代码,一个好的解决办法就是使用闭包,用装饰器来解决
    这个问题
    '''
    
    # 1. 已有的功能
    def wait():
        w = random.randint(5,10)
        print(w)
        time.sleep(w)
        print("执行wait完毕,用了{}秒".format(w))
    
    # 3. 调用闭包,获取执行结果
    a = decorator(wait)  # 相当于a 就是 wrapper函数里
    a()  # 再调用wrapper函数, 就能得到计算的结果
    
    # 输出
    9
    执行wait完毕,用了9秒
    测试结束,花费时间9.005208253860474秒

    上面利用闭包写好了修饰器,但是闭包的使用不是像上面那样通过a = decorator(wait)()的方式使用的,而是通过在原有函数的上面加@闭包函数名的方式使用

    import  time
    import random
    
    
    # 2.用闭包的方式不改变原代码的情况下,新增计算时间的功能
    def decorator(func):
        def wrapper():
            startTime = time.time()
            result = func()
            endTime = time.time()
            print("测试结束,花费时间{}秒".format(endTime-startTime))
            return result   
        return wrapper
    
    
    # 3.通过@闭包函数名的方式,实现装饰器
    @decorator
    # 1. 已有的功能
    def wait():
        w = random.randint(5,10)
        print(w)
        time.sleep(w)
        print("执行wait完毕,用了{}秒".format(w))
    
    # 4. 直接调用原函数就可以实现功能
    wait()
    
    # 输出
    10
    执行wait完毕,用了10秒
    测试结束,花费时间10.002923727035522秒
    # 示例2
    
    '''
    已知:现有add函数
    需求:add函数执行结果写到一个文件里去
    '''
    
    
    def writeAddtoFile(func):  # 闭包的参数func,将来传的就是原有的功能函数add,这是永远不变的,套路,固定写法;外面的函数传函数名
        def wrapper(a,b):      # 内嵌函数的参数,接受的是原函数add的参数,这也是永远不变的,套路,固定写法;里面的函数传的才是参数
            result = func(a,b)
            with open("add.txt",'a',encoding='utf-8') as f:
                f.write(str(result)+"
    ")   # 换行写入,要在写入的内容后面 加 +"
    "
                f.close()
        return wrapper
    
    @writeAddtoFile
    def add(x,y):
        return x+y
    
    
    add(5,8)
    add(3,5)
    add(1,1)
    # 固定写法
    def deco(func):    # 固定写法,这里的func将来接收的是add
        def wrapper(*args, **kargs):   #  固定写法:这里的参数将来接收的时候 add函数的a 和 b 两个参数
            result = func(args, kargs)    # 新功能在内嵌函数里写
            return result
        return wrapper   # 固定写法;要把内嵌的函数返回
    
    
    def add(a,b):
        pass

    练习:输入某年某月某日,判断这一天是这一年的第几天?

    import time
    
    def calDay(date):
        '''
        输入某个日期,计算是这一年的第几天
        :param date:
        :return:
        '''
        # 1. 先把输入的日期格式化
        fenGefu = ['/','.','-','','']
        try:
            for i in date:
                if i in fenGefu:
                    date=date.replace(i,'-')
                elif i == '':
                    date=date.replace(i,"")
    
            # 2.利用time模块函数得到
            forMatDate = time.strptime(date, '%Y-%m-%d')
            result = time.struct_time(forMatDate)
            # 3. 提取想要的结果返回
            days = result.tm_yday
            return "{}是今年的地{}天".format(date, days)
        except Exception:
            print("您输入的日期格式不对,请检查后重新输入")
    
    
    date=input("请输入年月日:")
    
    print(calDay(date))

     六.内置函数

    1. 类型转换函数

    bool , int , long ,float ,bytearray  str,  unicode, basestring,list tuple
    set,dict, frozenset, complex

    2.文件IO

    input, print, open,file, format

    3. 数学运算

    abs,divmod, pow, sum, cmp, bin, oct, hex, chr, unichr, ord, max, min, round
    # 1. 求模求余
    divmod(99,1) # (14,1)
    
    #2. 求幂
    pow(2,3)    $ 8
    
    # round()四舍五入, 有bug,慎用

    4. 集合切片

    len, range, iter, next, slice(切片), enumerate, sorted, reversed
    data = ['a','b','c']
    # enumerate 返回对象的下标
    for i,v in enumerate(data): 
    print(i,v)

    # 输出

    0 a
    1 b
    2 c

    5. 高阶函数

    高阶函数:返回值是函数,或者函数的参数是函数

    any(任意一个满足条件,返回True), all(所有满足条件,返回TRUE), map,reduce, filter, zip

    map,reduce,filter是Python里很常用的三个高阶函数

    map(func,iter):第一个参数是个函数,第二个参数要是一个可迭代对象

    # map的第一个参数是个函数,第二个参数是个可迭代对象
    # map的作用:对data数据里的每个元素,分别执行函数pow
    # map的返回是个map对象,所以,map的两种使用方法:1. 用list转化,  2.用for循环
    
    data = [1,2,3,4,5,6,7,8,9]
    def pow(n):
        return n**n
    
    # map的第一个参数是个函数,第二个参数是个可迭代对象
    # map的作用:对data数据里的每个元素,分别执行函数pow
    # map的返回是个map对象,所以,map的两种使用方法:1. 用list转化,  2.用for循环
    
    
    # 使用list获取map的返回值
    print(list(map(pow,data)))
    # 输出
    [1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489]
    
    # map函数用for循环取结果
    for p in map(pow,data):
        print(p)
    
    # 输出
    1
    4
    27
    256
    3125
    46656
    823543
    16777216
    387420489
    # 还有更简单的,就是可以用lambda 匿名函数,替换 pow函数,就不用再定义上面的pow函数了
    
    print(map(lambda n: n**2, data))
    
    lambda 返回值:表达式

    reduce(function,sequence): 第一个参数是个函数,

    reduce():折叠函数,

    # reduce函数:折叠函数
    # 作用:类似于sum(),
    # 函数的运行方式:data里的1和2先相加得到3,然后再用3+ data里的3,得到6,然后用6再加data里的4,依次类推,直到data的最后一个数
    
    from functools import reduce  # reduce 在Python3里,要先导入才能使用
    print(reduce(lambda x,y:x+y, data))
    # 输出 45

    filter(func, iter):过滤器

    作用:filter函数作为过滤器,挑选满足条件的数据

    # filter 函数
    # 作用:filter函数作为过滤器,挑选满足条件的数据
    # 从data里挑选出奇数
    print(list(filter(lambda x:x % 2 !=0, data)))
    
    # 输出
    [1, 3, 5, 7, 9]
    # 从data里取出偶数
    
    print(list(filter(lambda x:x % 2 == 0, data )))
    
    # 输出
    [2, 4, 6, 8]

    6. 反射与内省

    type, isinstance,issubclass,callable,staticmethod,classmethod,getattr, setattr, delattr,hasattr,
    super,dir,help,id,hash,object,__import__,compile,reload, repr,vars,locals,globals,eval,exec , execfile,
    property,memoryview
  • 相关阅读:
    jquery 里面对数组去重操作-unique
    jquery序列化form表单
    [转载]说说JSON和JSONP,也许你会豁然开朗,含jQuery用例
    AMD和CMD的区别
    CSS中!important的使用
    HTML的map-area的使用
    CSS Sprite 精灵图
    UA 用户代理
    IE haslayout
    心情随笔
  • 原文地址:https://www.cnblogs.com/victorm/p/11289624.html
Copyright © 2020-2023  润新知