python-自定义函数详解(匿名函数、偏函数、装饰器)

python-自定义函数


  • def关键字定义一个函数,def后必须后跟函数名称和带括号的形式参数列表。构成函数体的语句从下一行开始,并且必须缩进。

  • 示例:
    '''定义一个函数:1+2+3...+num'''
    def cumsum(num):
    	i = 0
    	for each in range(1,num + 1):
    		i += each
    	return i
    	
    '''或者也可以用递归写'''
    def cumsum(num):
        if num > 1:
            return num + cumsum(num - 1)
        else:
            return num
            
    cumsum(10)		#调用函数,传入参数10
    #out: 55
    

  • 设置默认参数值
    def cumsum(end=10, start=1):
    		i = 0
    		for each in range(start,end + 1):
    			i += each
    		return i
    cumsum()
    #out: 55	函数参数调用默认值
    
    '''我们也可以参数传入其他值,如果传入的参数没有指定参数名称,需要按照函数定义参数的顺序传入,这里end=5,start=2'''
    cumsum(5,2)
    #out: 14	
    
    '''如果指定参数名称赋值,可以不按照函数定义参数顺序传入,这里使用参数名称赋值,把start参数放在了开头。'''
    cumsum(start=2, end=5)
    #out: 14		
    

  • 可变参数
    • *args,加“*”号为若干个参数,返回元组,*args放在普通参数后。
    def cumsum(num,*args):
    	for each in args:	#args是一个元组
    		num += each
    	return num
    
    cumsum(1,5,6,7)
    #out:19	num后面参数5,6,7以元组args传入函数内。
    

  • 关键字参数
    • 虽然一个参数可以接受多个实参,但是这些实参都被捆绑为元组了,而且无法将具体的实参指定给具体的形参。关键字参数,可以把带参数名的参数值组装到一个字典中,键就是具体的实参名,值就是传入的参数值。**kwargs:注意关键字参数定义时,放在最后面,如果存在可变参数,就放在可变参数定义后面。
    def update_dic(name,age,**kwargs):
        person_info = {}
        person_info['name'] = name
        person_info['age'] = age
        person_info.update(kwargs)
        return person_info
        
    update_dic('张三',18,weight='70kg', height='178cm')
    #out: {'name': '张三', 'age': 18, 'weight': '70kg', 'height': '178cm'}	weight='70kg', height='178cm'以字典kwargs传入函数内
    

  • 解包参数列表
    • 函数定义时,*args和**kwargs会将参数以元组和字段返回到函数内调用,相反地,在函数调用时,传参前加上*和**表示解包,将元组列表拆解为元素,下面来做个示例:
    def cumsum(num,*args):
    	for each in args:	#args是一个元组
    		num += each
    	return num
    	
    cumsum(1,2,3,4) 
    #out: 10	正常情况下,我们在num参数后,逐个输出arg参数
    
    '''我们也传入*列表代表args'''
    ls = [2,3,4]
    cumsum(1,*ls)
    #out: 10	传入*列表表示解包列表为单个元素,*ls就相当于2,3,4。
    
    '''关键字参数也是一样的,我们暂且还是借用上面的函数'''
    def update_dic(name,age,**kwargs):
        person_info = {}
        person_info['name'] = name
        person_info['age'] = age
        person_info.update(kwargs)
        return person_info
        
    dic = {'weight': '70kg', 'height': '178cm'}
    '''我们直接传入字典,这里**dic跟直接传入weight='70kg', height='178cm'是一样的。'''
    update_dic('张三',18,**dic)
    #out: out: {'name': '张三', 'age': 18, 'weight': '70kg', 'height': '178cm'}		
    
    • 我们或可以这么理解,对于函数定义时使用了可变参数:*args和关键字参数:**kwargs,函数调用时,对应的参数是元素,以元组,字典返回到函数内部调用。如果调用函数参数使用 *列表或元组 | **字典会将列表或元组|字典解包成元素传参,到函数内部时,依旧是元组|字典,只是传参的形式不一样罢了。

  • 匿名函数:lambda
    • 使用lambda关键字定义函数,lambda var :exp(var)
    fun1 = lambda x : x + 1
    
    def fun2(x):
    	return x + 1
    	
    fun1(1)
    #out: 2
    
    fun2(1)
    #out: 2
    
    '''这里的fun1函数和fun2函数是一样的,如果函数设计比较简单,我们完全可以使用lambda方式定义函数,书写简洁。'''
    

  • 关于局部变量与全局变量
    • 函数内部的变量如果没有声明,只在函数内部生效,全局变量需要使用global关键字声明,来个简单的栗子:
    a = 1
    
    def about_global()
    	a = 10
    	return a
    
    '''a=10,在函数内部有效,正常返回'''
    about_global()
    #out: 10
    
    '''函数内部的赋值,a=10,函数外无效,仍然返回1'''	
    print(a)
    #out: 1		
    
    def about_global()
    '''声明a为全局变量'''
    	global a	
    	a = 10
    	return a
    
    '''a=10,函数内部始终有效'''	
    about_global()
    #out: 10
    
    '''函数内部定义a为全局变量,函数外,a变量也随着函数内修改而修改,返回10'''	
    print(a)
    #out: 10		
    

  • 偏函数的使用
    • functools.partial可以帮助我们创建一个偏函数,它把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
    import functools
    
    def cumsum(end=10, start=1):
    		i = 0
    		for each in range(start,end + 1):
    			i += each
    		return i
    
    cumsum()
    #out: 55
    
    '''创建一个cumsum偏函数'''
    cumsum_patrial  = functools.partial(cumsum,end=5,start=1)
    
    cumsum_partial()
    #out: 15	函数的默认参数修改了。
    
    • 其他
      函数参数里可以传入类,也可以传入函数方法名称
    class TT:
       @classmethod		# 类方法,无需实例,类可以直接调用
       def pt(cls):
           print("执行了类TT的方法:pt")
    
    def test(cls):
        cls.pt()
    
    test(TT)
    
    #out: 执行了类TT的方法:pt
    
    • 装饰器
      在不改变原函数代码调用方式的前提下,为原函数添加一些扩展功能,比如下面的计算函数耗时(通过outer传参控制装饰函数是否生效)。
      这里我们定义了一个outer装饰器,函数定义上方带有“@装饰器名”,在实际调用该函数时,实际调用的是装饰器函数内最终的return函数:
    import time
    
    def outer(flag):
        def timer(fun):
            def inner(*args,**kwargs):		# 不定长参数
                if flag:
                    start = time.time()
                fun(*args,**kwargs)			# 这里的args是元组,kwargs是字段,前面加‘*’号解包
                if flag:
                    print('函数名:"{}";运行耗时:{:.2f}'.format(fun.__name__,time.time()-start),fun.__doc__)
            return inner
        return timer
    
    '''装饰函数传入‘False’参数,装饰效果不生效'''
    @outer(False)
    def fun1(num):
        '''
        这里是函数说明文档:
        param num:整数
        return:返回0+1+2+3+...+(num-1)的累加和
        '''
        i = 0
        for each in range(num):
            i += each
        print(i)
    
    fun1(10000000)
    
    '''这里fun1函数我们去掉@outer(False)装饰,下面的方法是等价于函数fun1上添加@outer(True)装饰'''
    outer(True)(fun1)(10000000)
    # outer(True)返回timer函数对象引用;
    # outer(True)(fun1)返回inner函数对象引用;
    # outer(True)(fun1)(10000000):inner函数传参:10000000,执行inner函数
    
    '''
    使用装饰器@outer(False)调用fun1(10000000)
    out:49999995000000
    
    不使用装饰器执行outer(True)(fun1)(10000000)
    out:49999995000000
    out:函数:"fun1";运行耗时:0.54 
    out:这里是函数说明文档:
    out:param num:整数
    out:return:返回0+1+2+3+...+(num-1)的累加和
    '''
    

你可能感兴趣的:(Python)