• Python学习之路8——函数介绍


      1、函数是什么?

    在学习函数之前,一直遵循面向过程编程,即根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能。

    开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处。

    这样最后的程序会变得特别冗长,有没有什么办法把这些相同的代码块做一些处理?

    让程序的代码显得简便明朗,这就引出了今天要学习的内容:函数。

    定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。

    特性:减少重复代码、使程序变的可扩展、使程序变得易维护。

       2、定义函数

    1 def 函数名(参数):
    2      
    3     ....
    4     函数体
    5     ....
    6     return 返回值
    7  
    8 函数名()

       函数组成:函数名、参数、函数体、返回值,接下来进行详细介绍。

       3、普通参数

    学习函数参数前,我们先认识下形参和实参的区别:

      • 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。

           形参只在函数内部有效。

           函数调用结束返回主调用函数后则不能再使用该形参变量。

      • 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

           应预先用赋值,输入等办法使参数获得确定值。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 # 函数的普通参数
     6 # name 叫做函数func的形式参数,简称:形参
     7 def func(name):  # 定义函数 函数名func
     8     print(name)
     9 
    10 #  'vison' 叫做函数func的实际参数,简称:实参
    11 func("vison")  # 执行函数

      4、默认参数

      默认参数的应用环境。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 # 函数默认参数
     6 def stu_register(name, age, country, course):  # 定义函数
     7     print("----注册学生信息------")
     8     print("姓名:", name)
     9     print("age:", age)
    10     print("国籍:", country)
    11     print("课程:", course)
    12 
    13 stu_register("张三", 22, "CN", "Python")  # 执行函数
    14 stu_register("赵四", 21, "CN", "Linux")
    15 stu_register("王五", 25, "CN", "JAVA")

      输出结果:

     1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
     2 ----注册学生信息------
     3 姓名: 张三
     4 age: 22
     5 国籍: CN
     6 课程: Python
     7 ----注册学生信息------
     8 姓名: 赵四
     9 age: 21
    10 国籍: CN
    11 课程: Linux
    12 ----注册学生信息------
    13 姓名: 王五
    14 age: 25
    15 国籍: CN
    16 课程: JAVA
    17 
    18 Process finished with exit code 0

       通过上面代码发现country 这个参数基本都 是"CN"。

       在网站上注册用户,国籍默认是中国,这就是通过默认参数实现的,把country变成默认参数。

    1 def stu_register(name,age,course,country="CN"):

      这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 # 指定默认参数
     6 def stu_register(name, age, course, country="CN"):  # 定义函数
     7     print("----注册学生信息------")
     8     print("姓名:", name)
     9     print("age:", age)
    10     print("国籍:", country)
    11     print("课程:", course)
    12 
    13 stu_register("张三", 22, "Python")  # 不指定country参数值
    14 stu_register("赵四", 21, "Linux", "US")  # 指定country参数值

      输出结果:

     1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
     2 ----注册学生信息------
     3 姓名: 张三
     4 age: 22
     5 国籍: CN
     6 课程: Python
     7 ----注册学生信息------
     8 姓名: 赵四
     9 age: 21
    10 国籍: US
    11 课程: Linux
    12 
    13 Process finished with exit code 0

      注意:定义函数默认参数必须放在非默认参数之后。

     5、关键字参数

      正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可。

      但记住一个要求就是,关键字参数必须放在位置参数之后

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 # 关键字参数
     6 def stu_register(name, age, course, country="CN"):  # 定义函数
     7     print("----注册学生信息------")
     8     print("姓名:", name)
     9     print("age:", age)
    10     print("国籍:", country)
    11     print("课程:", course)
    12 
    13 stu_register( 'vison',course= "Python",age=22)  # 不指定country参数值

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 ----注册学生信息------
    3 姓名: vison
    4 age: 22
    5 国籍: CN
    6 课程: Python
    7 
    8 Process finished with exit code 0

     6、非固定参数

      非固定参数 *args。

    1 #!/user/bin/env ptyhon
    2 # -*- coding:utf-8 -*-
    3 # Author: VisonWong
    4 
    5 def stu_register(name, *args):  # *args 会把多传入的参数变成一个元组形式
    6     print(name, args, type(args))  # 打印传入args的类型
    7 
    8 stu_register("vison", "18", "CN", "Python")

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 vison ('18', 'CN', 'Python') <class 'tuple'>
    3 
    4 Process finished with exit code 0

      输入列表参数。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 def stu_register(name, *args):  # 测试*args传入list参数
     6     print(name, args, type(args))  # 打印传入args的类型
     7 
     8 
     9 info_list = ["18", "CN", "Python"]
    10 stu_register("vison", info_list)

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 vison (['18', 'CN', 'Python'],) <class 'tuple'>
    3 
    4 Process finished with exit code 0

      总结:

      由上面代码可以看出,*args会把多传入的实参变成一个元组的类型;

      即使传入的是list类型也会变成元组,成为元组中的一个元素;

      另函数中有*args与其他形参的时候,*args一定要写到其他形参的后面,否则传入的实参都会被传入到*args当中打印成元组;

      还有如果没有多出传入的实参即*args没有值的时候,*args为空,不会报错。

      非固定参数 **kwargs 。

    1 #!/user/bin/env ptyhon
    2 # -*- coding:utf-8 -*-
    3 # Author: VisonWong
    4 
    5 def stu_register(name, *args, **kwargs):  # **kwargs 会把多传入的参数变成一个dict形式
    6     print(name, args, type(args))  # 打印args的类型
    7     print(kwargs, type(kwargs))  # 打印kwargs的类型
    8 
    9 stu_register("viosn", 28, "CN", "Python", sex="Male", province="HeNan")

       输出结果:

    1 1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 2 viosn (28, 'CN', 'Python') <class 'tuple'>
    3 3 {'sex': 'Male', 'province': 'HeNan'} <class 'dict'>
    4 4 
    5 5 Process finished with exit code 0

      传入列表和字典。

     1 # -*- coding:utf-8 -*-
     2 # Author: VisonWong
     3 
     4 def stu_register(name, *args, **kwargs):  # **kwargs 会把多传入的参数变成一个dict形式
     5     print(name, args, type(args))  # 打印args的类型
     6     print(kwargs, type(kwargs))  # 打印kwargs的类型
     7 
     8 
     9 info_list = [28, "CN", "Python", ]  # 定义列表
    10 info_dict = {"sex": "Male", "province": "HeNan"}  # 定义字典
    11 stu_register("vison", info_list, info_dict)  # 传入列表和字典

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 vison ([28, 'CN', 'Python'], {'sex': 'Male', 'province': 'HeNan'}) <class 'tuple'>
    3 {} <class 'dict'>
    4 
    5 Process finished with exit code 0

      看完上面的第一段代码,

      **kwargs会把多出的a=b这种类型的实参打印成字典的类型(要区分开与关键参数的区别,关键参数的实参有对应的形参)

      但是第二段代码为毛下面把字典传入函数后,打印的**kwargs为空值呢?!  

      是这样的,传入的字典会被当成一个元素传入函数,所有被当成多余的实参传入到了*args里面,所以**kwargs的值才为空;那么有什么办法可以把字典传入到**kwargs呢?

     1 # -*- coding:utf-8 -*-
     2 # Author: VisonWong
     3 
     4 def stu_register(name, *args, **kwargs):  # **kwargs 会把多传入的参数变成一个dict形式
     5     print(name, args, type(args))  # 打印args的类型
     6     print(kwargs, type(kwargs))  # 打印kwargs的类型
     7 
     8 
     9 info_list = [28, "CN", "Python", ]  # 定义列表
    10 info_dict = {"sex": "Male", "province": "HeNan"}  # 定义字典
    11 stu_register("lzl",*info_list,**info_dict)     #传入列表和字典

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 lzl (28, 'CN', 'Python') <class 'tuple'>
    3 {'sex': 'Male', 'province': 'HeNan'} <class 'dict'>
    4 
    5 Process finished with exit code 0

      把定义好列表info_list、info_dict,分别用*inf_list和**info_dict的方式传入到*args、**kwargs当中,解决了第二块代码中的问题

      总结:

      *args必须放到**kwargs前面(规定);位置参数一定要放到关键参数之前(规定);默认参数不能跟*args、**kwargs一块存在(会报错)。

      7、return返回值

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 # ruturn 返回值
     6 def func(name, age):
     7     print(name)
     8     print(age)
     9 
    10 
    11 result = func("Vison", 28)  # 赋值变量result函数func执行的返回值
    12 print(result)             # 函数不声明return,返回值为None
    13                           # 函数在赋值变量result的时候也进行了打印

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 Vison
    3 28
    4 None
    5 
    6 Process finished with exit code 0

      添加返回值。

     1 # -*- coding:utf-8 -*-
     2 # Author: VisonWong
     3 
     4 def func(name, age):
     5     print(name)
     6     return "best"  # 执行return返回值
     7     print(age)
     8 
     9 
    10 result = func("Vison", 28)  # 赋值变量result函数func执行的返回值
    11 print(result)                # 函数返回值为best
    12                              # age没有打印,表明函数执行到return后,函数结束

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 Vison
    3 best
    4 
    5 Process finished with exit code 0

      结论:、

      如果不执行return,函数的默认返回值为None;当函数执行到return时,函数结束执行。

     8、局部变量

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 name = "Alex Li"  # 定义变量name
     6 
     7 def change_name(name):
     8     print("before change:", name)
     9     name = "金角大王,一个有Tesla的男人"  # 函数内部更改变量
    10     print("after change", name)  # 打印更改后的变量name
    11 
    12 change_name(name)
    13 print("在外面看看name改了么?", name)  # 现在看看name变量有没有被更改

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 before change: Alex Li
    3 after change 金角大王,一个有Tesla的男人
    4 在外面看看name改了么? Alex Li
    5 
    6 Process finished with exit code 0

      总结:

      函数内部对变量进行更改后,生效范围仅限于函数内部,对外部变量没有影响,这种变量称为局部变量;

      函数内部也可以让变量全局生效,需要加参数global,这种情况很少用。

     9、递归函数 

      定义:如果一个函数在内部调用自身本身,这个函数就是递归函数

    递归特性:

      •  必须有一个明确的结束条件
      •  每次进入更深一层递归时,问题规模相比上次递归都应有所减少
      •  递归效率不高,递归层次过多会导致栈溢出

          在计算机中,函数调用是通过栈(stack)这种数据结构实现的。

          每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。

          由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

      利用函数编写一个斐波那契数列。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 def func(n1,n2):        #获取斐波那契数列100之前的数字
     6     if n1 > 100:
     7         return
     8     print(n1)
     9     n3 = n1 + n2
    10     func(n2,n3)
    11 func(0,1)

      输出结果:

     1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
     2 0
     3 1
     4 1
     5 2
     6 3
     7 5
     8 8
     9 13
    10 21
    11 34
    12 55
    13 89
    14 
    15 Process finished with exit code 0
     获取斐波那契数列第20个数字并返回给调用者。
     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 def func(count,n1,n2):        #获取斐波那契数列第20个数字并返回给调用者
     6     if count == 20:
     7         return n1
     8     n3 = n1 + n2
     9     r = func(count + 1,n2,n3)
    10     return r                   #不断返回结果给上一层调用函数
    11 ret = func(1,0,1)
    12 print(ret)

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 4181
    3 
    4 Process finished with exit code 0

     10、函数式编程

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。

    函数就是面向过程的程序设计的基本单元。

    而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。

    我们首先要搞明白计算机(Computer)和计算(Compute)的概念。

    在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。

    而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。

    对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。

     

    函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。

    而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

     

    函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

    Python对函数式编程提供部分支持。

    由于Python允许使用变量,因此,Python不是纯函数式编程语言。

    简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。

    主要思想是把运算过程尽量写成一系列嵌套的函数调用。

    举例来说,现在有这样一个数学表达式:

    1 (1 + 2) * 3 - 4

      传统的过程式编程,可能这样写:

    1 var a = 1 + 2;
    2  
    3 var b = a * 3;
    4  
    5 var c = b - 4;

      函数式编程要求使用函数,我们可以把运算过程定义为不同的函数,然后写成下面这样:

    1 var result = subtract(multiply(add(1,2), 3), 4);

      这就是函数式编程。

     11、匿名函数

      匿名函数就是不需要显式的指定函数。

    1 #这段代码
    2 def calc(n):
    3     return n**n
    4 print(calc(10))
    5   
    6 #换成匿名函数
    7 calc = lambda n:n**n
    8 print(calc(10))

      匿名函数主要是和其它函数搭配使用如下:

    1 #!/user/bin/env ptyhon
    2 # -*- coding:utf-8 -*-
    3 # Author: VisonWong
    4 
    5 res = map(lambda x:x**2,[1,5,7,4,8])
    6 for i in res: 
    7     print(i)

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 1
    3 25
    4 49
    5 16
    6 64
    7 
    8 Process finished with exit code 0

      加入列表。

    1 #!/user/bin/env ptyhon
    2 # -*- coding:utf-8 -*-
    3 # Author: VisonWong
    4 
    5 calc = map(lambda n,x,y:n*10000+x*100+y,[1,5,7,4,8],[2,2,2,2,2],[3,3,3,3,3])
    6 for i in calc:
    7     print(i)

       输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 10203
    3 50203
    4 70203
    5 40203
    6 80203
    7 
    8 Process finished with exit code 0

      关于map函数的用法看下面两个例子。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 def abc(a, b, c):
     6     return a*10000 + b*100 + c
     7 
     8 list1 = [11,22,33]
     9 list2 = [44,55,66]
    10 list3 = [77,88,99]
    11 
    12 calc = map(abc,list1,list2,list3)
    13 for i in calc:
    14     print(i)

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 114477
    3 225588
    4 336699
    5 
    6 Process finished with exit code 0

      某种意义上实现了并行计算。

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 list1 = [11,22,33]
     6 list2 = [44,55,66]
     7 list3 = [77,88,99]
     8 
     9 calc = map(lambda x,y,z:[x,y,z],list1,list2,list3)
    10 
    11 for i in calc:
    12     print(i)

      输出结果:

    1 E:PythonPythonLearingvenvScriptspython.exe E:/Python/PythonLearing/func.py
    2 [11, 44, 77]
    3 [22, 55, 88]
    4 [33, 66, 99]
    5 
    6 Process finished with exit code 0

      12、高阶函数

      变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。 

     1 #!/user/bin/env ptyhon
     2 # -*- coding:utf-8 -*-
     3 # Author: VisonWong
     4 
     5 def add(x, y, f):
     6     return f(x) + f(y)
     7 
     8 
     9 res = add(3,-6, abs)
    10 print(res)

      13、内置函数

      

  • 相关阅读:
    FreeMarker缓存处理
    freemarker入门实例与源码研究准备工作
    Freemarker常用技巧(二)
    Freemarker常用技巧(一)
    Hessian与Spring整合
    Hessian学习
    数组常见的面试题
    关于排序的实现
    Redis与Memcache的区别
    JDBC编程步骤
  • 原文地址:https://www.cnblogs.com/visonwong/p/8983232.html
Copyright © 2020-2023  润新知