本文主要学习内容有

函数知识的补充

装饰器(无参、有参、非固定参数、有返回值)

一、函数知识的补充

1、使用函数的好处

  可以进行模块化设计,如果不使用函数的话,在完成某些功能或者某些项目时,所有的功能都堆积在一起了,那么久容易造成:

  ① 体系结构不清晰,可读性差

  ② 可扩展性差

  ③ 程序冗长

2、定义函数



def fun(args)
    '''文档描述,函数的功能、参数等信息'''
    print("in the fun")#函数体
    return #返回值



3、定义函数的形式



def foo():
    '''无参函数'''
foo()

def bar(x,y):
    '''有参函数'''
bar(1,2)

def func():
    '''空函数'''
    pass



4、函数的调用
函数的调用有:语句形式、表达式形式、作为另外一个函数的参数



#语句形式
def foo():
    print('in the foo')
foo()

#表达式形式
def my_max(x,y):
    if x > y:
        return x
    else:return y
res = my_max(1,2)
print(res)

res2 = 10*my_max(1,2)#表达式形式
print("res2:",res2)

#作为另外一个函数的参数
res3 = my_max(1,my_max(2,3))
print("res3",res3)



5、函数的返回值形式

  不返回内容、返回1个、返回多个



#不返回
def foo():
    pass
res = foo()
print(res)

#返回一个
def foo1():
    return 1
res1 = foo1()
print(res1)

#返回多个
def foo3():
    return 1,'s',[1,2,3]
res3 = foo3()
print(res3)



6、函数的参数
  定义形参的时候不用定义参数的类型,这就是参数的动态性。

从实参角度讲:

  针对同一个形参,我们要么按照位置传参、要么按照关键字传参。

从形参角度讲:

  站在形参角度讲,位置参数(特性:必传)、默认参数、可变长参数(*args,**kwargs)

  *args 等同于按位置方式传参;**kwargs等同于按关键字方式传参

7、高阶函数

  高阶函数的定义:

  ① 函数接收的参数是一个函数名

  ② 函数的返回值是一个函数名

  满足以上任意一个条件,都可称之为高阶函数



def foo():
    print('我的函数名将要作为参数传给高阶函数')

def gaojie1(func):
    print('我就是高阶函数1,接收一个函数名为参数%s'%func)
    func()

def gaojie2(func):
    print('我是高阶函数2,将一个函数名返回给函数%s'%func)
    return func

res1 = gaojie1(foo)
res2 = gaojie2(foo)



高阶函数的应用1:



#高阶函数的应用1:把函数当做参数传给高阶函数
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
timmer(foo)
#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式



高阶函数的应用2:



#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    return func
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能



高阶函数的总结:
  ① 函数接收的参数时一个函数名

  作用:在不修改函数源代码的前提下,为函数添加新功能

  不足:会改变函数的调用方式

  ② 函数的返回值是一个函数名

  作用:不修改函数的调用方式

  不足:不能添加新功能

8、嵌套函数



def one(name):
    print('一级 %s' %name)
    def two():
        print('二级')
        def two1():
            print('三级')
        two1()
    two()

one('xiaoling')



9、闭包



'''
闭包:在一个作用域里放入定义变量,相当于打了一个包
'''
def one(name):
    def two():
        print('我是一级 [%s]' %name)
        def two1():
            print('我上级的上级 [%s]' %name)
        two1()
    two()

one('xiaoling')



二、装饰器

  什么是装饰器?就是函数,为他人装饰(其他函数),就是为其他函数增加功能。

  装饰器遵循的原则:

  1、不修改被装饰函数的源代码(开放封闭原则)

  2、为被装饰的函数装新增功能后,不改变原函数的调用方式

1.1、无参装饰器:



import time,functools
#无参数
def timer(func):
    def wrapper():
        start_time = time.time()
        func()  #运行最原始的index
        stop_time = time.time()
        print("运行时间%s"%(stop_time-start_time))
    return wrapper

@timer #index = timer(index)
def index():
    print('in the index:')

index()



1.2、被装饰的函数需要传参



import time,functools
#index有参数
def timer(func):
    def wrapper(msg):
        start_time = time.time()
        func(msg)  #运行最原始的index
        stop_time = time.time()
        print("运行时间%s"%(stop_time-start_time))
    return wrapper

@timer #index = timer(index)
def index(msg): #该参数实际是传到wrapper函数了,接受到该参数后给func使用。
    print('in the index:',msg)

index('hello')



1.3、被装饰的函数需要传多个参数



def timer(func):
    def warpper(*args,**kwargs):#因为不知道被装饰的函数有多少个参数,所以这个地方使用非固定参数
        func(*args,**kwargs)
    return warpper

@timer # index = timer(index)
def index(msg):
    print('in the index',msg)

@timer # home = timer(home)
def home(user,msg):
    print('in the home %s %s'%(user,msg))

index('hello')
home('tom',msg='XXXX')



1.4、被装饰的函数有返回值



import time,functools
#有返回值的装饰器
def timer(func):
    def warpper(*args,**kwargs):#因为不知道被装饰的函数有多少个参数,所以这个地方使用非固定参数
        res = func(*args,**kwargs)
        return res #因为被装饰的函数有返回值,所以将运行结果返回
    return warpper

@timer # index = timer(index)
def index(msg):
    print('in the index',msg)

@timer # home = timer(home)
def home(user,msg):
    print('in the home %s %s'%(user,msg))
    return 1 #被装饰的函数有返回值
index('hello')
res = home('tom',msg='XXXX')
print(res)



1.5、多个装饰器套用



@deco3
@deco2
@deco1 #func1 = deco1(index)--> func2 = deco2(func1) -->index = deco3(func2)  index = deco3(deco2(deco1(index)))
def index():
    print('in the index')
index()



装饰器小知识点:

  函数被装饰了之后,如果使用help()来查看被装饰函数的内容时此时显示的是装饰器函数的内容,此时可以用到Python中的一个模块“functools”



import time,functools#导入functools模块
def timer(func):
    @functools.wraps(func)#使用warps方法后,在使用help查看index函数时,查看的是index的函数信息。
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print('运行时间:%s'%(start_time-stop_time))
        return res
    return wrapper

@timer # index = timer(index)
def index(msg):
    '''
    装饰器测试
    :param msg:
    :return:
    '''
    print('in the index',msg)
index('hello index')



   2、有参装饰器

  有参装饰器,其实是在原来无参装饰器的基础上在套上一层函数。

  以下代码其实有个bug,俩被装饰的函数,每次调用都会提示输入用户名和密码



def auth(type_file):
    def auth_deco(func):
        def warpper(*args,**kwargs):
            username = input("请输入用户名:")
            password = input("请输入密码:")
            if type_file == 'file':
                if username == 'xiaoling' and password =='123':
                    res = func(*args,**kwargs)
                    return res
            elif type_file == 'ldap':
                print("使用的是ldap")
                return func(*args,**kwargs)
        return warpper
    return auth_deco


@auth('file') #有参装饰器
def index(msg):
    print('in the index')
index('hello')

@auth('ldap') #有参装饰器
def home():
    print('in the home')
home()