回顾一

函数

函数知识体系

  

 

 what is function

  • 函数的特点:
    • 提高了代码的重用性-->不使用函数遇到重复的功能只能重复编写代码,代码冗余
    •  结构清晰, 易维护--->不使用函数代码的组织结构不清晰, 可读性差
    • 扩展性好--->现实中程序功能需要扩展
  • 函数分类:
    • 内置函数<python解释器已经为我们定义好功能的函数>
    • 自定义函数<顾名思义需要我们自己编写该函数的功能>
  • 定义函数
    • 如何定义函数
    • # 函数基本语法
      def func(参数1,参数2,....):
          '''注释'''
          函数体
          return 返回值
      
      # 函数名即func要反应其意义
    • 函数使用的原则:先定义, 在调用
      • 函数即"变量", 任何的"变量"必须先定义好然后才可以 引用,未定义而直接引用的函数, 就相当于在引用一个不存在的变量名
        # test1
        def foo():
            print("来自foo")
            bar()
        foo() 
        # 这里直接运行foo函数会报错, 因为函数体内部的bar()函数并没有定义
        
        # test2
        def bar():
            print("来自bar"')
        def foo():
            print("来自foo")
            bar()
        
        foo() 
        # 这里再次运行foo函数, 就不会再报错, 因为定义了bar函数
        
        # test3
        def foo():
            print('来自foo')
            bar()
        
        def bar():
            print('来自bar')
        
        foo()
        # 这里不会报错, 函数的使用,必须遵守原则, 先定义,后调用, 而且要明确区分定义阶段和调用阶段
        
        
        # 定义阶段
        def foo():
            print('来自foo')
            bar()
        
        def bar():
            print('来自bar')
        
        # 调用阶段<可以理解为运行函数>
        foo()
        View Code
      • 函数在定义阶段:只检测语法, 不执行代码, 即纠正语法错误, 逻辑错误只有执行后才会知道

 

    • 定义函数的三种形式
      • 无参: 应用场景仅仅执行一些操作
      • 有参: 需要根据外部传入的参数, 才能执行相应的逻辑
      • 空函数: 设计代码结构   
      • 有参&无参
         1 def test1(tag, n):
         2     '''有参'''
         3     print(tag*n)
         4 
         5 def test2():
         6     '''无参'''
         7     print("hello world")
         8 
         9 test1('=', 12)
        10 test2()
        11 test1('=', 12)
      • 空函数
         1 def auth(user,password):                             
         2     '''                                                           
         3     auth function                                                 
         4     :param user: 用户名                                              
         5     :param password: 密码                                           
         6     :return: 认证结果                                                 
         7     '''                                                           
         8     pass                                                          
         9                                                                   
        10 def get(filename):                                                
        11     '''                                                           
        12     :param filename:                                              
        13     :return:                                                      
        14     '''                                                           
        15     pass                                                          
        16                                                                   
        17 def put(filename):                                                
        18     '''                                                           
        19     :param filename:                                              
        20     :return:                                                      
        21     '''                                                           
        22 def ls(dirname):                                                  
        23     '''                                                           
        24     :param dirname:                                               
        25     :return:                                                      
        26     '''                                                           
        27     pass                                                          
        28 
        29 #程序的体系结构立见 
        View Code    

 调用函数

  • 调用函数: 函数名加括号
  • 返回值<return>: 
    • 没有return--->None
    • return一个值--->返回一个值
    • return多个值--->返回一个元组
    • 什么时候用return
      • 需要一个明确的结果, 则必须有返回值, 通常有参函数需要有返回值,
      • 仅仅只是执行一些列操作, 最后不需要得到什么结果, 则不需要有返回值,通常无参函数不需要有返回值

 函数的参数

  • 形参与实参

    • 形参即变量名

    • 实参即变量值   

    • 顾名思义, 形参形式上是参数, 其实只是一个虚假的, 实参实际运行中需要的参数   

  • 位置参数<按照位置给形参传值>
    • 从左到右的顺序定义  
      1 def foo(x, y, z):
      2     print('传入的参数是:', x, y, z)
      3 
      4 foo(1, 2, 3)
      5 foo('a', 'b', 'c')
      6 # 从左到右位置一一对应
  • 关键字参数<在位置参数右边, 同一个形参不能重复传值>
    • 按照k=v的形式定义的实参  
      1 def foo(name, age, addr):
      2     print("姓名: %s, 年龄:%s, 地址:%s" % (name, age, addr))
      3 
      4 foo(name='李云龙', age=30, addr='平安县')
  • 默认参数<位置参数右边,通常为不可变类型>
    • 形参在定义时就已经为其赋值
    • 运行时可以传值也可以不传值, 经常需要变得参数定义成位置参数, 变化小的定义为默认参数 
      1 def foo(age, job, name='李云龙'):
      2     print("姓名: %s, 年龄:%s, 职务:%s" % (name, age, job))
      3 
      4 foo(age=30, job='团长')
      5 foo(name='张大彪', age=28, job='参谋长')
      6 # 第二次运行, name重新赋值'张大彪'
  • 可变长参数
    • *args和**kwargs 
      1 def foo(name, job, *args):
      2     print("姓名:%s, 职务:%s" % (name, job))
      3     print("事迹:", args)
      4 
      5 foo('李云龙', '团长', '击溃坂田联队','攻打平安县', '剿灭黑云寨')
      6 # name= 李云龙, job=团长, 其余事迹分别传入*args中
  • 命名关键字参数
    • *后定义的参数, 必须传值(有默认值的除外),必须按照关键字实参的形式传递
       1  def foo(x,y,*args,a=1,b,**kwargs):
       2             print(x,y)
       3             print(args)
       4             print(a)
       5             print(b)
       6             print(kwargs)
       7 
       8  foo(1,2,3,4,5,b=3,c=4,d=5)
       9 # 运行一下看一下输出结果
      10

 函数对象

  • 函数第第一类对象, 即函数可以当做数据传递
    • 函数可以被引用
    • 可以当做参数传递
    • 返回值可以是函数
    • 可以当做容器类型的元素
  • 函数的嵌套调用
     1 def max(x, y): 
     2     '''选出较大的值''' 
     3     return x if x > y else y 
     4 
     5 def func(a, b, c, d): 
     6     '''用max()函数选出四个数中的最大值'''
     7      res1 = max(a, b) 
     8      res2 = max(res1, c) 
     9      res3 = max(res2, d) 
    10      return res3 
    11  
    12 print('最大值是:', func(2,4,6,8))        
  •  函数的嵌套定义

    1 def foo():
    2     def bar():
    3         def test():
    4             print("from the test")
    5         test()
    6     bar()
    7 foo()

     

名称空间和作用域

  • 三种名称空间:1.局部名称空间, 2.全局名称空间, 3.内置名称空间
  • 名称空间加载顺序: 先是内置, 接着全局, 最后局部
  • 名字查找顺序:先是局部, 接着全局, 最后内置<注意:全局的不可以查看局部的, 局部的可以查看全局的,换言之,-->段鹏知道丁伟, 丁伟不知道段鹏>
     1 name = '李云龙'
     2 def foo():
     3     name = "赵刚"
     4     print('from the foo' ,name)
     5     def bar():
     6         name = '丁伟'
     7         print('from the bar', name)
     8         def test():
     9             name = '孔杰'
    10             print("from the test", name)
    11         test()
    12     bar()
    13 foo()
    14 # 可以将name分别注释, 即可看出效果
  • 作用域
    • 全局范围<内置与全局名称空间属于这个范畴>,全局存活 全局都有效
    • 局部范围<局部名称空间属于该范畴>,临时存活, 局部有效
  • 作用域关系是在函数定义阶段就已经固定的, 与函数的调用位置无关
  • 查看作用域: globals(), locals()

 

global和nonlocal关键字

  • 闭包:
    • 内部函数包含对外部作用域而非全局作用域的引用
  • 闭包的意义与应用
    • 意义:返回的函数对象, 不仅仅是一个函数对象, 在该函数外还包裹了一层作用域,这使得函数无论在何处调用,优先使用自己外层包裹的作用域
    • 应用领域:延迟计算
       1 from urllib.request import urlopen
       2 
       3 def index(url):
       4     def get():
       5         return urlopen(url).read()
       6     return get
       7 
       8 
       9 baidu = index('http://www.baidu.com')
      10 print(baidu().decode('utf-8'))

 

 装饰器

  • 装饰器的作用
    • 开放封闭原则: 对修改封闭, 对扩展开放
  • 什么是装饰器
    • 装饰其他的器具,本身可以是任意可调用对象, 被装饰者也可以是任意可调用对象
    • 原则: 1.不修改被装饰对象的源代码,2.不修改被装饰对象的可调用方式
    • 目标: 在遵循1和2的前提下, 为被装饰对象添加新的功能
  • 装饰器的使用
    • 无参装饰器
       1 import time
       2 
       3 def timmer(func):
       4     def wrapper():
       5         start_time = time.time()
       6         func()
       7         stop_time = time.time()
       8         print("函数的运行时间是: ",stop_time-start_time)
       9     return wrapper
      10 
      11 @timmer
      12 def test():
      13     '''测试函数'''
      14     time.sleep(3)
      15     # 函数运行时间延迟3秒
      16     print("函数运行完毕!")
      17 
      18 test()
    • 有参装饰器
       1 import time
       2 def timmer(func):
       3     def wrapper(*args,**kwargs):
       4         start_time = time.time()
       5         res = func(*args,**kwargs) # 运行的是test
       6         stop_time = time.time()
       7         print("test函数运行时间是 %s" %(stop_time-start_time))
       8         return res
       9     return wrapper
      10 
      11 
      12 @timmer
      13 def test(name, age,gender):
      14     time.sleep(3)
      15     print("test函数运行完毕")
      16     print("作者是 %s, 今年 %s 岁, 性别 %s" %(name, age, gender))
      17     return '这是test的返回值'
      18 
      19 res = test('Gunner',25,gender = 'male') # 就是运行wrapper
  • 装饰器的语法
  • 装饰器补充:wraps
     1 from functools import wraps
     2 
     3 def deco(func):
     4     @wraps(func) #加在最内层函数正上方
     5     def wrapper(*args,**kwargs):
     6         return func(*args,**kwargs)
     7     return wrapper
     8 
     9 @deco
    10 def index():
    11     '''哈哈哈哈'''
    12     print('from index')
    13 
    14 print(index.__doc__)

     

 

迭代器

  • 迭代器概念
    • 迭代是一个重复的过程, 每次重复即一次迭代, 并且每次迭代的结果都是下一次迭代的初始值
  • 为什么要有迭代器
    • 字符串, 字典, 元组可以通过索引取值, 但对于字典, 集合,文件等没有索引, 为了获取没有索引的值, 则必须找出一种不依赖于索引的迭代方式, 这就是迭代器
    • 可迭代对象就是指内置有__iter__方法的对象
    • 可迭代对象执行__iter__()得到的结果就是迭代器对象,而迭代器对象指的是不仅内置有__iter__又的内置有__next__方法的对象,文件类型是可迭代对象
    • 注意: 迭代器对象一定是可迭代对象, 而可迭代对象不一定是迭代器对象
  • 迭代器对象的使用
  • for循环
    1 #基于for循环,我们可以完全不再依赖索引去取值了
    2 dic={'a':1,'b':2,'c':3}
    3 for k in dic:
    4     print(dic[k])
    5 
    6 #for循环的工作原理
    7 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
    8 #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
    9 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环

     

  • 迭代器的优缺点
    • 优点:提供一种统一的, 不依赖于索引的迭代方式, 惰性计算, 节省内存
    • 缺点: 无法获取长度(只能在程序运行结束后才回到有几个值),一次性, 只能往后走, 不能往后退

生成器

  • 什么是生成器
    • 只要函数内部包含有yield关键字, 那函数名()得到的结果就是生成器, 并且不会执行函数内部代码
  • 生成器与迭代器的关系
  • 协程函数
  • yield总结

三元表达式

  • 1 name = input("姓名>>: ")
    2 res = '团长' if name =='李云龙' else '你他娘的真是个天才'
    3 print(res)

列表推导式

1 # 列表解析
2 egg_list1 = []
3 for i in range(10):
4     egg_list1.append('鸡蛋%s' % i)
5 
6 print(egg_list1)
7 # egg_list2是列表解析
8 egg_list2 = ['鸡蛋%s' % i for i in range(10)]
9 print(egg_list2)
  • 优点: 方便, 改变了编程习惯, 可称之为声明式编程

生成器表达式

egg_list2 = ('鸡蛋%s' % i for i in range(10))
print(egg_list2.__next__())
print(egg_list2.__next__())
print(egg_list2.__next__())
print(next(egg_list2))
print(list(egg_list2))
# __next__() = next()二者等效
# 将列表解析的[]换成()就是生成器表达式
# 优点: 省内存, 一次只产生一个值在内存中

 

递归

  • 定义
    • 递归调用时函数嵌套调用的一种特殊形式, 函数在调用时, 直接或间接调用了自身, 就是递归调用
       1 # 自己调用自己
       2 def foo():
       3     print('from the foo')
       4     foo()
       5 
       6 foo()
       7 
       8 # 间接调用自己
       9 def f1():
      10     print('来自f1')
      11     f2()
      12 
      13 def f2():
      14     print('来自f2')
      15     f1()
      16 
      17 f1()
      View Code
  • 递归调用的两个阶段
    • 推递
      • --->就是从里向外一层一层结束递归
    • 回溯
      • --->就是从外向里一层一层递归调用下去<必须要有一个明确的结束条件, 没进入下一次递归时, 问题的规模都应该有所减少>
  • python中的递归效率低且没有尾递归优化
    • python中的递归效率低, 需要在进入下一次递归时保留当前的状态, python没有尾递归, 且对递归层级做了限制
    • 总结递归的使用
      • 1.必须有一个明确的结束条件
      • 2.每次进入更深一层递归时,问题规模相比上一次递归都应有所减少
      • 3.递归效率不高, 递归层次过多会导致栈溢出
  • 二分法
    • 想从一个按照从小到大排列的数字列表中找到指定的数字, 遍历的效率太低, 用二分法可以极大缩小问题规模

匿名函数

  • 什么是匿名函数
    def func(x, y):
        return x + y
    
    print(func(10, 20))
    
    res = lambda x, y: x + y
    print(res(5,10))
    
    # 即lambda表达式, 后面跟参数, :后面是简单的式子
  • 有名字的函数与匿名函数对比
    • 有名函数:循环使用, 保存了名字, 通过名字就可以重复引用函数功能
    • 匿名函数:一次性使用, 随时使用随时定义

内置函数

  • https://docs.python.org/3/library/functions.html?highlight=built#ascii

 

 

posted @ 2018-11-13 22:08  李建清  阅读(73)  评论(0)    收藏  举报