函数复习

1 什么是函数?
  函数就是具备某一个功能的工具,
    ----需要工具时,需要提前准备好,然后拿来就用且可以重复使用
  所以
    函数需要先定义,再使用


2 为什么要用函数?
  1,代码的组织结构不清晰,可读性差
  2,遇到重复的功能只能重复编写实现代码,代码冗余
  3,功能需要扩展时,需要找出所有实现该功能的地方修改之,无法统一管理且维护难度极大


3 函数的分类:内置函数与自定义函数
  内置函数:python解释器已经为我们定义好了的函数
  自定义函数:我们自己根据需求,事先定制好的我们自己的函数,来实现某种功
4 如何自定义函数
 
  语法
  def 函数名(参数1,参数2,参数3.......):
      """注释"""
      函数体
      return 返回的值
  # 函数名要能反映其意义
  
  
  函数使用的原则:先定义,再调用
    函数即"变量","变量"必须先定义后引用。未定义而直接引用函数,就相当于在引用一个不存在的变量名
    函数的使用,必须遵循原则:先定义,后调用
   ###我们在使用函数时,一定要明确区分定义阶段和调用阶段###
    #定义阶段
      def foo():
        print('from foo')
        bar()
      def bar():
        print('from bar')
     #调用阶段
       foo()
定义有参数函数,及有参函数的应用场景
  有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度等
    def tell_tag(tag,n): #有参数
      print (tag*n)
定义无参数函数,及无参函数的应用场景
  无参:应用场景仅仅只是执行一些操作,比如用户交互,打印
    def tell_msg(): #无参数
      print ('hello world') 定义空函数,及空函数的应用场景
   设计代码结构

 #结论:
  #1,定义是无参,意味着调用时也无需传入参数
  #2,定义是有参,意味着调用时则必须传入参数
 函数在定义阶段
    只检测语法,不执行代码
      --语法错误在函数定义阶段就会检测出来,而代码的逻辑错误只有在执行时才会知道
5 调用函数 如何调用函数
    函数的调用:函数名加括号
      1,先找到名字
      2,根据名字调用代码
函数的返回值
    无return--->None
    return 1个值->返回1个值
    return 逗号分隔多个值 -->返回元组
    
    什么时候该有返回值:
      调用函数,经过一系列的操作,最后拿到一个明确的结果,则必须要有返回值
      通常有参函数需要有返回值,输入参数,经过计算,得到一个最终的结果
  
    什么时候不需要有返回值:
      调用函数,仅仅只是执行一系列的操作,最后不需要得到什么结果,则无需有返回值
      通常无参函数不需要有返回值
   

  函数调用的三种形式
    1,语句形式:foo()
    2,表达式形式:3*len(’hello‘)
    3,当中另外一个函数的参数:range(len(’hello‘))
函数参数的应用:
    形参和实参
      形参即变量名,实参即变量名,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定
    
    位置参数
按照从左到右的顺序定义的参数      位置形参:必选参数            位置实参:按照位置给形参传值

    
关键字参数:按照key=value的形式定义的实参
      无需按照位置为形参传值
      注意的问题:
          1,关键字实参必须在位置实参后面
          2,对同一个形参不能重复传值
    默认参数:形参在定义时就已经为其赋值
      可以传值也可以不传值,经常需要变的参数定义成位置形参,变化较小的参数定义成默认参数(形参)
      注意的问题:
        1,只在定义的时候赋值一次
        2,默认参数的定义应该在位置形参右边
        3,默认参数通常应该定义成不可变类型
可变长参数:
    可变长指的是实参值得个数不固定
    而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整的存放它们,
   分别是 *args,**kwargs(args,kwargs只是约定俗成的表示,没有特殊意义)
 ===========*args===========
        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,3,4,5)

        def foo(x,y,*args):
            print(x,y)
            print(args)
        foo(1,2,*[3,4,5])


        def foo(x,y,z):
            print(x,y,z)
        foo(*[1,2,3])

        ===========**kwargs===========
        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,a=1,b=2,c=3)

        def foo(x,y,**kwargs):
            print(x,y)
            print(kwargs)
        foo(1,y=2,**{'a':1,'b':2,'c':3})


        def foo(x,y,z):
            print(x,y,z)
        foo(**{'z':1,'x':2,'y':3})

        ===========*args+**kwargs===========

        def foo(x,y):
            print(x,y)

        def wrapper(*args,**kwargs):
            print('====>')
            foo(*args,**kwargs)

  命名关键字参数:

    * 后定义的参数,必须被传值(有默认值得除外),且必须按照关键字实参的形式传递

    可以保证,传入的参数中一定包含某些关键字

def foo(x,y,*args,a=1,b,**kwargs):
            print(x,y)
            print(args)
            print(a)
            print(b)
            print(kwargs)

        foo(1,2,3,4,5,b=3,c=4,d=5)
        结果:
            1
            2
            (3, 4, 5)
            1
            3
            {'c': 4, 'd': 5
      
6 高阶函数(函数对象)
  函数是第一类对象,即函数可以当做数据传递
  1,函数可以被引用
  2,函数可以当做参数传递
  3,函数的返回值可以是函数
  4,函数可以当做容器类型的元素
 
  利用这些特性,可以取代多分支的if
  
 1 def foo():
 2     print('foo')
 3 
 4 def bar():
 5     print('bar')
 6 
 7 dic={
 8     'foo':foo,
 9     'bar':bar,
10 }
11 while True:
12     choice=input('>>: ').strip()
13     if choice in dic:
14         dic[choice]()
  
7 函数嵌套
  函数的嵌套调用
    
1 def max(x,y):
2     return x if x > y else y
3 
4 def max4(a,b,c,d):
5     res1=max(a,b)
6     res2=max(res1,c)
7     res3=max(res2,d)
8     return res3
9 print(max4(1,2,3,4))
    
8 作用域与名称空间
  名称空间:存放名字的地方,三种空间:内置名称空间,全局名称空间,局部名称空间    存放的是名字和内存地址的对应关系
 名称空间的加载顺序
python test.py
#1、python解释器先启动,因而首先加载的是:内置名称空间
#2、执行test.py文件,然后以文件为基础,加载全局名称空间
#3、在执行文件的过程中如果调用函数,则临时产生局部名称空间

名字的查找顺序
  局部名称空间--全局名称空间--内置名称空间
   注意:在全局无法查看局部的,在局部可以查看全局的

作用域:作用域即范围
  -全局范围:(内置名称空间与全局名称空间属于该范围):全局存活,全局有效
  -局部范围:(局部名称空间属于该范围):临时存活,局部有效

查看作用域: globals(),locas()
  
1 LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__
2 locals 是函数内的名字空间,包括局部变量和形参
3 enclosing 外部嵌套函数的名字空间(闭包中常见)
4 globals 全局变量,函数定义所在模块的名字空间
5 builtins 内置模块的名字空间


闭包函数
  内部函数包含对外部作用域而非全局作用域的引用
1     def index(url):
2         def get():
3             return urlopen(url).read()
4         return get
 1 #闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
 2 #应用领域:延迟计算(原来我们是传参,现在我们是包起来)
 3     from urllib.request import urlopen
 4 
 5     def index(url):
 6         def get():
 7             return urlopen(url).read()
 8         return get
 9 
10     baidu=index('http://www.baidu.com')
11     print(baidu().decode('utf-8'))
9 装饰器
  为什么要用装饰器?
    开放封闭原则:对修改封闭,对扩展开放
  什么是装饰器?
    装饰器本身是任意可调用对象,被装饰着也可以是任意可调用对象
    装饰器的原则:
      1,不修改被装饰对象的源代码
      2,不修改被装饰对象的调用方式
      3,在遵循1和2的前提下,为被装饰对象添加新功能
  装饰器的基本语法:(任何装饰器都可以套用)
 
def  foo(func):
    def wrappers(*args,**kwargs):
        res = func()
      return res
    return wrappers


   无参装饰器
import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s' %(stop_time-start_time))
        return res
    return wrapper

@timmer
def foo():
    time.sleep(3)
    print('from foo')
foo()

  有参装饰器

def auth(driver='file'):
    def auth2(func):
        def wrapper(*args,**kwargs):
            name=input("user: ")
            pwd=input("pwd: ")

            if driver == 'file':
                if name == 'egon' and pwd == '123':
                    print('login successful')
                    res=func(*args,**kwargs)
                    return res
            elif driver == 'ldap':
                print('ldap')
        return wrapper
    return auth2

@auth(driver='file')
def foo(name):
    print(name)

foo('egon')

10 迭代器与生成器及协程函数
  1,迭代器就是迭代的工具,迭代就是一个重复的过程,每次重复就是一次迭代,
并且每次迭代的结果都是下一次迭代的初始值
  2,为什么要有迭代器?
    对于没有索引的数据类型,迭代器提供了一种不依赖索引的迭代方式
  3,可迭代对象
    内置有__iter__方法的对象,即obj.__iter__
    可迭代对象:字符串,列表,元组,字典,集合,文件
  4,迭代器对象
    可迭代对象执行__iter__得到的结果就是迭代器对象
    迭代器对象指的是既内置有__iter__又内置有__next__方法的对象
    文件类型是迭代器对象
dic={'a':1,'b':2,'c':3}

iter_dic=dic.__iter__()  #可迭代对象执行__iter__方法得到的结果就是迭代器对象
#迭代器对象内置有__iter__方法和__next__方法
iter_dic.__iter__() id iter_dic #  迭代器执行__iter__()得到的仍然是迭代器本身
print(iter_dic.__next__())
print(iter_dic.__next__())
print(iter_dic.__next__()) #等同于next(iter_dic)
#迭代对象有几个值就需要执行几次,直到没有值可取

print(iter_dic.__next__()) #抛出异常StopIteration,标志迭代对象的值已经全部取出
迭代器的使用

基于for循环,我们可以实现不依赖索引取值
1 dic={'a':1,'b':2,'c':3}
2 for k in dic:
3     print(dic[k]

for循环工作原理
1,执行in后的对象__iter__()方法,得到一个迭代器对象
2,执行__next__方法,将得到的值赋值变量,然后执行循环体代码
3,重复过程2,直到捕捉到异常StopIteration
for循环原理

迭代器的优缺点:

  优点:提供了一种不依赖索引的迭代方式

  缺点:无法获取长度

    只能一直往前取,无法往后取

生成器
  函数内包含有yield关键字
  再调用函数,就不会执行函数体代码,拿到的返回值就是一个生成器对象
  注意::生成器本质就是迭代器,也就是说迭代器的用法就是生成器的用法

11 三元运算,列表解析、生成器表达式
  三元运算:
    格式:
      为真时的结果 if 判断条件 else 为假时的结果
  例子: print(1 if 5>3 else 0)
  
  列表解析(列表推导式)
    基本形式:[表达式 for 参数 in 可迭代对象]
       或者 [表达式 for 参数 in 可迭代对象 if 条件]
  实例
 1 l = []
 2 for i in range(100):
 3     l.append('egg%s' %i)
 4 print i
 5 
 6 #不带if条件
 7     l = ['agg%s' %i for i in range(100) ]
 8 
 9 #带if条件
10     l = ['agg%s' %i for i in range(100)  if i>10]
View Code

    生成器表达式

      将列表推导式的中括号改为小括号即可

  

  l = ('egg%s' %i  for i in range(100)  if i>10)

  print(next(l))

  注意:得到的结果为迭代器
生成器表达式
12 函数的递归调用
  递归调用是函数嵌套调用的一种特殊形式,函数在调用时,直接或间接调用了自身
就是递归调用
  递归的两个阶段:
    回溯:往前搜索,以达到目标
        注意:一定要在满足某个条件的情况下结束回溯,否则就是无限递归  
    递推:往回推
 
1 def age(n):
2     if n == 1:
3         return 1
4     else:
5         return age(n-1)+2
6 
7 print(age(5))
递归实例
   递归总结:
     递归必须有一个明确的结束条件
     每次进入更深一层递归时,问题规模相比上次递归都应有所减少
     python没有尾递归优化,但是设置了最大递归层数
13 内置函数
  内置函数就是python解释器定义好的函数

  reduce(func,iterable) 从可迭代系列中循环取值,参与第一个函数参数的计算,最后得到一个结果


reduce(lambda x, y: x+y, [1,2,3,4,5]) # 使用 lambda 匿名函数



  bytes()将unicode指定编码后转化为bytes类型


  chr()返回值是传入整数对应的ascii字符


  divmod()将除数和余数的运算结果结合起来,返回一个包含商和余数的元组(a//b,a%b)


>>>divmod(7, 2)
(3, 1)
>>> divmod(8, 2)
(4, 0)
>>> divmod(1+2j,1+0.5j)
((1+0j), 1.5j)



  enumerate()将一个可遍历的数据对象组合为一个索引序列,同时列出数据个数据下标,一般用在for循环


  


>>>seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]



  eval()执行一个字符串表达式,并返回表达式的值


>>>x = 7
>>> eval( '3 * x' )
21
>>> eval('pow(2,2)')
4
>>> eval('2 + 2')
4
>>> n=81
>>> eval("n + 4")
85



  filter(func,iterable)函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表


 


import math
def is_sqr(x):
    return math.sqrt(x) % 1 == 0
newlist = filter(is_sqr, range(1, 101))
print(newlist)



  id() 返回参数的内存地址序号


  input()获取输入


  iter(object)生成迭代器


  len()返回参数长度


  map(func,iterable)第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。


  


map(lambda x: x ** 2, [1, 2, 3, 4, 5])  # 使用 lambda 匿名函数
[1, 4, 9, 16, 25]

>>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
[3, 7, 11, 15, 19]



 


 max()返回给定参数的最大值,参数可以是系列


egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000
yuanhao female 28 10000

with open('db.txt') as f:
    items=(line.split() for line in f)
    info=[{'name':name,'sex':sex,'age':age,'salary':salary} 
          for name,sex,age,salary in items]

print(max(info,key=lambda dic:dic['salary']))

max(iterable, key, default) 求迭代器的最大值,其中iterable 为迭代器,max会for i in … 遍历一遍这个迭代器,然后将迭代器的每一个返回值当做参数传给key=func 中的func(一般用lambda表达式定义) ,然后将func的执行结果传给key,然后以key为标准进行大小的判断



  min()返回给定参数的最小值,参数可以是系列


  ord()返回给定参数的十进制数


>>>ord('a')
97
>>> ord('b')
98
>>> ord('c')
99



  sorted()对所有可迭代的对象进行排序操作。


sort 与 sorted 区别:
sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。



iterable -- 可迭代对象。
cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

>>>a = [5,7,6,3,4,1,2]
>>> b = sorted(a)       # 保留原列表
>>> a 
[5, 7, 6, 3, 4, 1, 2]
>>> b
[1, 2, 3, 4, 5, 6, 7]
 
>>> L=[('b',2),('a',1),('c',3),('d',4)]
>>> sorted(L, cmp=lambda x,y:cmp(x[1],y[1]))   # 利用cmp函数
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
>>> sorted(L, key=lambda x:x[1])               # 利用key
[('a', 1), ('b', 2), ('c', 3), ('d', 4)]
 
 
>>> students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
>>> sorted(students, key=lambda s: s[2])            # 按年龄排序
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
 
>>> sorted(students, key=lambda s: s[2], reverse=True)       # 按降序
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
>>>
14 面向过程编程
#1、首先强调:面向过程编程绝对不是用函数编程这么简单,面向过程是一种编程思路、思想,而编程思路是不依赖于具体的语言或语法的。言外之意是即使我们不依赖于函数,也可以基于面向过程的思想编写程序

#2、定义
面向过程的核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么

基于面向过程设计程序就好比在设计一条流水线,是一种机械式的思维方式

#3、优点:复杂的问题流程化,进而简单化

#4、缺点:可扩展性差,修改流水线的任意一个阶段,都会牵一发而动全身

#5、应用:扩展性要求不高的场景,典型案例如linux内核,git,httpd

#6、举例
流水线1:
用户输入用户名、密码--->用户验证--->欢迎界面

流水线2:
用户输入sql--->sql解析--->执行功能
面向过程编程


 
原文地址:https://www.cnblogs.com/guodengjian/p/8710617.html