python笔记(12)--装饰器和推导式

内容目录

  • 装饰器
  • 推导式

内容回顾

1.函数:

  • 参数

    • def(a1,a2):pass

    • def(a1,a2=None):pass 默认参数推荐用不可变类型,慎用可变类型。

    • def(*args,**kwargs):pass

    • 注意:位置参数 > 关键字参数

    • 面试题:

      • 函数可以做参数【知识点】

        def func(arg):
            arg()
        def show():
            pass
        func(show)
        
      • 函数的参数传递的是什么?【内存地址 = 引用 or 值】

        v = [11,2,33,4]
        
        def func(arg):
            print(id(arg))	#列表内存地址
         
        print(id(v))	#列表内存地址
        func(v)
        
        #其打印的都是列表的内存地址,表示传递的都是内存地址
        
      • *args和**kwargs的作用

  • 返回值

    • 常见数据类型可以返回

    • 函数也可以返回

      def func():
          def inner():
              pass
          return inner
      
      v = func()
      
    • 特殊

      • 默认没返回就是None
      • return 1,2,3 等价于return(1,2,3)
  • 执行函数

    • 函数不被调用,内部代码永远不执行

      def func():
          return i
      func_list = []
      for i in range(10):
          func_list.append(func)
      
      print(i)	# 9
      v1 = func_list[4]()
      v2 = func_list[0]()
      
      func_list = []
      for i in range(10):
          #func_list.append(lamdba:x)	#函数不被调用,内部永远不执行
          func_list.append(lamdba:i)	#函数不被调用,内部永远不执行
      print(func_list)	#10个lambda函数
      
      result = func_list[2]()
      print(result)		#9
      
  • 执行函数时,会新创建一块内存保存自己函数执行的信息 =》闭包

    def base(arg):
        return arg
    
    def func(arg):
        def inner():
            return arg
        return inner
    
    base_list = []
    func_list = []
    
    for i in range(10):
        base_list.append(base)
        func_list.append(func(i))
    
    # 1. base_list 和func_list中分别保存了什么?
    """
    base_list = [base,base,base......]共10个相同的base函数(内存地址)
    func_list = [inner,inner,inner......]共10个不同的inner(内存地址),从第一个i = 0,i = 1.....循环到9的不同inner函数的内存地址
    """
    # 2. 如果循环打印什么?
    for item in base_list:
        v = item()	#执行base函数
        print(v)	#都是9
    for data in func_list:
        v = data()
        print(v)	#0,1,2,3,...9
    

总结:

  • 传参:位置函数 > 关键字参数
  • 函数不被调用,内部代码永远不执行
  • 每次调用函数时,都会为此次调用开辟一块内存,内存可以保存自己以后想要用的值。
  • 函数是作用域,如果自己作用域中没有,则往上级作用域找。

2.内置和匿名函数

  • 内置函数
  • 匿名函数

3.模块

  • getpass
  • random
  • hashlib

4.重点作业

#1.看代码分析结果
func_list = []
for i in range(10):
    func_list.append(lambda x:x + i)#此时列表中增加了i=0-9的匿名函数


for i in range(0,len(func_list)):#i=0-9
    result = func_list[i](i)#重新覆盖列表中原i的值,i重新赋值并做参数传入函数
    print(result)#结果为0,2,4,6....18
    
#2.看代码分析结果【面试题】
def f1():
    print("f1")
    return f3()

def f2():
    print("f2")
    return f1

def f3():
    print("f3")

func = f2()		#先算等号右边,f2函数执行,输出"f2"返回值为函数f1,此时  func = f1
result = func() #等号右边为f1(),函数执行后,输出"f1",返回值
print(result)

#3.分析代码(闭包和调用)
def func(name):
    return lambda x: x + name

v1 = func(1)    #形成闭包(lambda x:x+1)
v2 = func(2)    #形成闭包(lambda x:x+2)
result1 = v1(100)     #执行闭包函数,x = 100,return返回值为101
result2 = v2(200)     #执行闭包函数,x = 200,return返回值为202
print(result1,result2)

内容详细

1.装饰器

#######################
def func(arg):
    def inner():
        arg()
    return inner

def f1():
    print(123)

v1 = func(f1)
v1()

#######################
def func(arg):      
    def inner():
        arg()
    return inner

def f1():
    print(123)
    return 666

v1 = func(f1)   #{arg = f1,v1 = inner,函数inner的闭包}
result = v1()   #v1() = inner(),arg = f1,执行inner()函数,结果为print(123),返回值为None
print(result)   #结果为123,None

#######################
def func(arg):      
    def inner():
        return arg()		#后续执行函数arg()时,返回值返回给inner函数
    return inner

def f1():
    print(123)
    return 666

v1 = func(f1)   #{arg = f1,v1 = inner,函数inner的闭包}
result = v1()   #v1() = inner(),arg = f1,执行inner()函数,结果为print(123),返回值为666
print(result)   #结果为123,666

#######################
def func(arg):
    def inner():
        return arg()
    return inner

def index():
    print('123')
    return 666

#示例一:
v1 = index()        #执行index函数,打印'123',并返回666给v1

#示例二:
v2 = func(index)	#index函数作为参数传入func()函数中执行,返回{arg=index函数}的inner函数闭包赋值给v2
index = 666		    #index函数重新指向666内存地址,但是v2闭包中的index还是指向原来的index函数
v3 = v2()#因v2中有闭包,相当于执行函数index()并返回值传给inner函数,inner函数中return接收后赋值给v3。
print(v3)#所以结果为打印123,666

#示例三:
v4 = func(index)
index = v4
index()

通过以上的例子,得出装饰器最终的状态:

#第一形态
def func(arg):
    print("此为index的装饰器")
    def inner():
        print("before")
        v = arg()
        print("after")
        return v
    return inner

def index():
    print('123')
    return 666

index = func(index)
index()

##最终形态:注意	@装饰器函数
def func(arg):
    print("此为index的装饰器")
    def inner():
        print("before")
        v = arg()
        print("after")
        return v
    return inner

#第一步:执行func函数并将index函数作为参数传递,相当于func(index)
#第二步:将func的返回值重新赋值给下面的函数名。index = func(index)
@func
def index():
    print('123')
    return 666

print(index())

装饰器:在不改变原函数内部代码的基础上,在函数执行之前和执行之后自动执行某个功能

应用:

import time

def func():
    time.sleep(4)
    print(123)

start_time = time.time()#获取当前时间
func()
end_time = time.time()
time = start_time - end_time
print(time)

总结:

  • 目的:在不改变原来函数的基础上,再函数执行前后在定义功能

  • 编写装饰器的标准格式:

    #装饰器的编写:
    def x(arg):
        def y():
            ret = arg()
            return ret
        return y
    
    #装饰器的应用:
    @x
    def index():
        pass
    
    @x
    def manager():
        pass
    
    #执行函数,自动触发装饰器
    v = index()
    m = manager()
    print(v,m)
    

应用场景:

  • 想要为函数扩展功能时,可以选择用装饰器。

总结:

  • 装饰器的编写格式

    • 装饰器第一层函数return的返回值不加内层函数的括号
    def 外层函数(参数):
        def 内层函数(*args,**kwargs):
            return 参数(*args,**kwargs)
        return 内层函数
    
  • 装饰器应用格式:

    @外层函数
    def index():
        pass
    
    index()
    
  • 问题:为什么要加*args,**kwargs

2.推导式

列表推导式(常用,熟记)

  • 基本格式

    '''
    目的:方便的生成一个列表
    格式:
    	v1 = [ i for i in 可迭代对象 ]
    	v2 = [ i for i in 可迭代对象 if 条件 ]    #条件为True,才可进行append
    '''
    v1 = [i for i in 'alec']
    v2 = [i+100 for i in range(10)]
    v3 = [99 if i>5 else 66 for i in range(10)]
    
    def func():
        return 100
    v4 = [func for i in range(10)]
    
    v5 = [ lambda : 100 for i in range(10) ]
    result = v5[9]()
    
    def func():
        return i 
    v6 = [func for i in range(10)]
    result = v6[5]()
    
    v7 = [lambda : i for i in range(10)]
    result = v7[5]()
    
    #新浪微博面试题
    #############第一题################
    val = [lambda x:x*i for i in range(10)]
    #1.请问val是什么结果?
    #2.请问val[0](2)的结果是什么?
    
    #############第二题################
    def num():
        return [lambda x:i*x for i in range(4)]
    #num() -> [函数,函数,函数,函数]
    print ([m(2) for m in num()])#[6,6,6,6]
    #1.看代码分析结果
    
    #############筛 选################
    v8 = [i for i in rang(10) if i>5 ]
    #第一步:计算for i in range(10)
    #第二步:判断条件if i>5
    #第三步:符合判断条件的依次赋值给i,添加进列表
    

集合推导式(集合特性:去重)

  • 跟列表推导式雷同
  • 仅适用集合的特性
v1 = {i for i in 'alec'}

字典推导式

  • 跟列表推导式雷同
  • 仅适用于字典的特性
    • key键不可重复
v1 = { 'k'+str(i):i for i in range(10) }

总结

  • 装饰器(特重点,理解+巩固)

    • 编写格式:双层嵌套函数

    • 应用格式:@外层函数

    • 重点记住:

      @xx		# index = xx(index)
      def index():
          pass
      
      index()		#为加入装饰器的index
      
  • 推导式(常用优化)

  • 模块

    import time
    
    v = time.time()	#获取当前时间
    time.sleep(2)	#时间睡眠2秒
    
posted @ 2020-05-18 11:11  薛定谔的猫儿  阅读(72)  评论(0编辑  收藏  举报