No.13装饰器&推导式

NO.13

今日概要

  • 作业题
  • 装饰器
  • 推导式
  • 模块

内容回顾

1.函数

  • 参数

    • 位置参数 > 关键字参数

    • 默认参数:推荐使用不可变类型,慎用可变类型。

    • *args / **kwarge

      • 接收任意个位置参数和关键字参数
      • 位置参数一定放在关键字参数前面
    • 函数可以作参数

      def func(arg):
          arg()    
      def show():
          pass
      func(show)
      
    • 函数的参数传递的是什么?

      v = [1,2,3,4]
      def func(arg):
          print(id(arg)) #列表的内存地址
          
      print(id(v)) #列表的内存地址
      func(v)
      #传递的是内存地址(引用)
      
  • 返回值

    • 常见数据类型可以返回

    • 函数也可以返回

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

      • 默认返回值为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[0]() # 9
      v2 = func_list[5]() # 9
      
      func_list = []
      for i in range(10):
          func_list.append(lambda :i) #函数不被调用,内部永远不执行。(不知道是什么。)
          # func_list.append(lambde :x)
      print(func_list)                #无论有没有x,函数未执行程序都不会报错。
      v = func_list[2]()              #执行函数时没有x,此时才会报错。
      
    • 函数执行时,才会开辟内存保存本次执行时的信息 → 闭包

      def func(arg):
          def inner():
              return arg
          return inner
      v1 = func(1) # 第一次执行时开辟内存1存储{ arg=1 , inner第一个地址}
      v2 = func(2) # 第二次执行时开辟内存2存储{ arg=2 , inner第二个地址}
      ret1 = v1() # 1
      ret2 = v2() # 2
      
      def base():
          return i
      def func(arg):
          def inner():
              return arg
          return inner
      base_list = []  # 内部元素指向都是base函数地址
      func_list = []  # 内部元素指向i=10个inner函数地址
      for i in range(10):
          base_list.append(base)
          func_list.append(func(i))
      #1.base_list 和 func_list 分别保存的是什么?
      前者放的是base函数的地址,后者放的是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 ~ 9
      

总结:

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

2.内置和匿名函数

  • 内置函数

  • 匿名函数

3.模块

  • getpass
  • random
  • hashib

使用模块时要先导入,本质就是导入一个py文件,然后调用此文件内的函数。

内置函数也是py文件,按理使用时也应该先导入,只不过解释器帮我们做了导入这个步骤。

python创始人会根据程序员的使用频率情况,把模块中的常用函数升级成内置函数(省去导入步骤),或把已有内置函数中很少用的函数降级放入模块。

内容详细

1.作业题讲解

2.装饰器

def func():
    pass
v = func
#分割
def base():
    print(1)
    
def bar():
    print(2)

bar = base  # bar本来指向其自身函数地址,被赋值后指向base函数地址。
bar()       # 运行的是base,结果为1。
def func():
    def inner():
        pass
    return inner
v = func()  # inner函数
#分割
def func(arg):
	def inner():
		print(arg)
	return inner
v1 = func(1)
v2 = func(2)
#分割
def func(arg):
	def inner():
		arg()
	return inner
def f1():
    print(123)
    return 666    
v1 = func(f1)
result = v1()  # inner没有返回值
print(result)  # None
#分割
def func(arg):
    def inner():
        return arg()
    return inner
def f1():
    print(123)
    return 666
v1 = func(f1)
result = v1()
print(result)

引入装饰器

def func():
    print(1)
v1 = func    
func = 666  #可以认为函数名是个变量指向函数体的内存地址,现在这个变量被重新赋值为666了。
def func(arg):
    def inner():
        return arg()
    return inner
def index():
    print('123')
    return '666'

示例一
v1 = index()     # 执行index函数,打印123并返回666赋值给v1
示例二
v2 = fun(index)  # v2是inner函数,arg = index 函数
index = 666
v3 = v2()
示例三
v4 = func(index)
index = v4       # index → inner地址
index()
#示例三的简写
index = func(index)
index()
#上述绕来绕去意义何在?
#在于不改变原函数内部代码的基础上,在其执行前后自定义一些代码进行操作。
def func(arg):
    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):
    def inner():
        print('before')
        v = arg()
        print('after')
        return v
    return inner
@func                 # 第一步:执行@的函数并将下面的函数当作参数传递。相当于:func(index)
def index():          # 第二步:将@的函数执行后的返回值重新赋值给下面的函数名。相当于:index = func(index)
    print('123')
    return '666'
index()

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

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

#计算函数执行时间
import time
def wapper(func):
    def inner():
        start = time.time()
        v = func()
        end = time.time()
        print(end-start)
        return v
    return inner

@wapper
def func1():
    time.sleep(2)
    print(123)
@wapper
def func2():
    time.sleep(2)
    print(123)
@wapper
def func3():
    time.sleep(2)
    print(123)

func1()
func2()
func3()

#管理已登录的用户
def add_user():
    #1.判断用户是否登陆
    #2.已经登陆可以继续
    pass
def del_user():
    #1.判断用户是否登陆
    #2.已经登陆可以继续
    pass
def update_user():
    #1.判断用户是否登陆
    #2.已经登陆可以继续
    pass

总结

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

  • 装饰器的编写和使用

    #编写
    def x(func):
        def y():
            #前加功能
            ret = func()
            #后加功能
            return ret
        return y
    #使用
    @x
    def index():
        pass
    @x
    def manage():
        pass
    #执行函数时,自动触发装饰器
    v = index()
    print(v)
    
  • 记住

    • 装饰器编写格式

      def 外层函数(func):
          def 内层函数(*args,**kwargs):
              return func(*args,**kwargs)
          return 内层函数
      
    • 装饰器使用格式

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

      def wrapper(func):
          def inner(*args,**kwargs):
              print('before')
              v = func(*args,**kwargs)
              print('after')
              return v
          return inner
      @wrapper
      def index():
          print(123)
      index()
      @wrapper
      def show(a1):
          print(a1+100)
      show(1)
      

3.推导式

  • 列表推导式

    • 基本格式

      #目的:方便的生成一个列表
      变量 = [ 变量 for i in 可迭代对象]
      v = [ i for i in 可迭代对象 if 条件] 条件为True才添加
      
      #变量 = [ 变量 for循环的一个可迭代对象 ]
      v1 = [ i for i in 'alex' ]
      v2 = [ i+100 for i in range(10)]
      v3 = [ 100 for i in range(10)]
      v4 = [ 99 if i>5 else 66 for i in range(10)]
      
      def fun():
          return 100
      v5 = [ func for i in range(10)]
      
      v6 = [lambda :100 for i in range(10)]
      result = v6[0]()
      result = v6[9]()
      
      def fun():
          return i
      v7 = [ func for i in range(10)]
      result = v7[0]()
      
      v8 = [lambda :i for i in range(10)]
      result = v8[0]()
      
      #面试题1
      v = [lambda x:x*i for i in range(10)]
      #1.请问v是什么?
      #2.请问v[0](2)的结果是什么?
      
      #面试题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]
      
      #筛选
      v9 = [ i for i in range(10) if i > 5]
      [6,7,8,9]
      
  • 集合推导式

    #不常用,除了括号和去重其余都和列表一样。
    #注意:不是所有类型都能当集合元素。
    v = { i for i in 'alex'}
    
  • 字典推导式

    #不常用,除了括号和冒号其余都和列表一样。
    #注意:不是所有类型都能当键值。
    v = { 'k'+str(i):i for i in range(10)}
    v = { 'k':i for i in range(10)}   # k重复最后结果{k:9}
    

总结

  • 装饰器▲▲▲

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

    • 使用格式:@外层函数

    • 理解:

      • 变量赋值

        def func():
        	print(1)
        v = func
        func = 666
        
      • 看清楚return到底是什么

      • 自己作用域 → 上级作用域

    • 背会

      @x  # index = xx(index)
      def index():
          pass
      
      index()
      
  • 推导式▲

  • 模块

    import time
    v = time.time() # 获取当前时间
    time.sleep(2)   # 执行到此会停两秒
    
posted @ 2020-03-19 05:14  Sco_Lunatic  阅读(110)  评论(0)    收藏  举报