zoukankan      html  css  js  c++  java
  • 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、内置函数

      

  • 相关阅读:
    POJ 1328 Radar Installation
    POJ 1700 Crossing River
    POJ 1700 Crossing River
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3253 Fence Repair (贪心,优先队列)
    poj 3069 Saruman's Army(贪心)
    poj 3069 Saruman's Army(贪心)
    Redis 笔记与总结2 String 类型和 Hash 类型
    数据分析方法有哪些_数据分析方法
    数据分析方法有哪些_数据分析方法
  • 原文地址:https://www.cnblogs.com/visonwong/p/8983232.html
Copyright © 2011-2022 走看看