一、 函数介绍

1、函数是什么

在学习函数之前,一直遵循面向过程编程,即根据业务逻辑从上到下实现功能,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,也就是将之前实现的代码块复制到现需功能处。这样最后的程序会变得特别冗长,有没有什么办法把这些相同的代码块做一些处理?让程序的代码显得简便明朗,这就引出了今天要学习的内容:函数。

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

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

2、定义函数

def 函数名(参数):

    ....
函数体
....
return 返回值 函数名()

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

3、普通参数

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

  • 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
  • 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

通过下面代码来认识下普通参数、形参、实参

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#函数的普通参数
# name 叫做函数func的形式参数,简称:形参
def func(name): #定义函数 函数名func
print(name) # 'lzl' 叫做函数func的实际参数,简称:实参
func("lzl") #执行函数 ########打印输出########
#lzl  

 4、默认参数

默认参数的应用环境

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#函数默认参数
def stu_register(name, age, country, course): #定义函数
print("----注册学生信息------")
print("姓名:", name)
print("age:", age)
print("国籍:", country)
print("课程:", course) stu_register("张三", 22, "CN", "Python") #执行函数
stu_register("赵四", 21, "CN", "Linux")
stu_register("王五", 25, "CN", "JAVA") ###########打印###############
#----注册学生信息------
#姓名: 张三
#age: 22
#国籍: CN
#课程: Python
#----注册学生信息------
#姓名: 赵四
#age: 21
#国籍: CN
#课程: Linux
#----注册学生信息------
#姓名: 王五
#age: 25
#国籍: CN
#课程: JAVA

通过上面代码发现country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是 中国, 这就是通过默认参数实现的,把country变成默认参数

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

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
#指定默认参数
def stu_register(name, age,course,country="CN"): #定义函数
print("----注册学生信息------")
print("姓名:", name)
print("age:", age)
print("国籍:", country)
print("课程:", course) stu_register("张三", 22, "Python") #不指定country参数值
stu_register("尼古拉斯.赵四", 21, "Linux", "US") #指定country参数值 ##############打印################
#----注册学生信息------
#姓名: 张三
#age: 22
#国籍: CN
#课程: Python
#----注册学生信息------
#姓名: 尼古拉斯.赵四
#age: 21
#国籍: US
#课程: Linux

另外,你可能注意到了,在把country变成默认参数后,我同时把它的位置移到了最后面,为什么呢? 

5、关键参数  

正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可,但记住一个要求就是,关键参数必须放在位置参数之后

#关键参数
stu_register(age=22,name='lzl',course="python") ##############打印################
#----注册学生信息------
#姓名: lzl
#age: 22
#国籍: CN
#课程: python

6、动态参数  

①  非固定参数 *args

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian def stu_register(name,*args): # *args 会把多传入的参数变成一个元组形式
print(name,args,type(args)) #打印传入args的类型 stu_register("lzl","18","CN","Python")
##############打印################
#lzl ('18', 'CN', 'Python') <class 'tuple'> def stu_register(name,*args): #测试*args传入list参数
print(name,args,type(args)) #打印传入args的类型 info_list = ["18","CN","Python"]
stu_register("lzl",info_list)
##############打印################
#lzl (['18', 'CN', 'Python'],) <class 'tuple'>

总结:由上面代码可以看出,*args会把多传入的实参变成一个元组的类型;即使传入的是list类型也会变成元组,成为元组中的一个元素;另函数中有*args与其他形参的时候,*args一定要写到其他形参的后面,否则传入的实参都会被传入到*args当中打印成元组;还有如果没有多出传入的实参即*args没有值的时候,*args为空,不会报错。

② 非固定参数 **kwargs

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian def stu_register(name, *args, **kwargs): # **kwargs 会把多传入的参数变成一个dict形式
print(name, args, type(args)) # 打印args的类型
print(kwargs, type(kwargs)) #打印kwargs的类型 stu_register("lzl", 18, "CN", "Python", sex="Male", province="HeBei")
##############打印################
#lzl (18, 'CN', 'Python') <class 'tuple'>
#{'sex': 'Male', 'province': 'HeBei'} <class 'dict'> def stu_register(name, *args, **kwargs): # **kwargs 会把多传入的参数变成一个dict形式
print(name, args, type(args)) # 打印args的类型
print(kwargs, type(kwargs)) #打印kwargs的类型 info_list=[18, "CN", "Python",] #定义列表
info_dict={"sex":"Male","province":"HeBei"} #定义字典
stu_register("lzl",info_list,info_dict) #传入列表和字典
##############打印################
#lzl ([18, 'CN', 'Python'], {'sex': 'Male', 'province': 'HeBei'}) <class 'tuple'>
#{} <class 'dict'>

看完上面的第一段代码,**kwargs会把多出的a=b这种类型的实参打印成字典的类型(要区分开与关键参数的区别,关键参数的实参有对应的形参),大家都能理解;但是第二段代码为毛下面把字典传入函数后,打印的**kwargs为空值呢?!  是这样的,传入的字典会被当成一个元素传入函数,所有被当成多余的实参传入到了*args里面,所以**kwargs的值才为空;那么有什么办法可以把字典传入到**kwargs呢?

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian def stu_register(name, *args, **kwargs): # **kwargs 会把多传入的参数变成一个dict形式
print(name, args, type(args)) # 打印args的类型
print(kwargs, type(kwargs)) #打印kwargs的类型 info_list=[18, "CN", "Python",] #定义列表
info_dict={"sex":"Male","province":"HeBei"} #定义字典
stu_register("lzl",*info_list,**info_dict) #传入列表和字典
##############打印################
#lzl (18, 'CN', 'Python') <class 'tuple'>
#{'sex': 'Male', 'province': 'HeBei'} <class 'dict'>

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

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

7、return 返回值

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian #ruturn 返回值
def func(name,age):
print(name)
print(age) result = func("lzl",18) #赋值变量result函数func执行的返回值
print(result) #函数不声明return,返回值为None
#函数在赋值变量result的时候也进行了打印
##############打印################
#lzl
#18
#None def func(name,age):
print(name)
return "best" #执行return返回值
print(age) result = func("lzl",18) #赋值变量result函数func执行的返回值
print(result) #函数返回值为best
#age没有打印,表明函数执行到return后,函数结束
##############打印################
#lzl
#best

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

8、局部变量

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian name = "Alex Li" #定义变量name def change_name(name):
print("before change:", name)
name = "金角大王,一个有Tesla的男人" #函数内部更改变量
print("after change", name) #打印更改后的变量name change_name(name)
print("在外面看看name改了么?", name) #现在看看name变量有没有被更改 ##############打印################
#before change: Alex Li
#after change 金角大王,一个有Tesla的男人
#在外面看看name改了么? Alex Li

结论:函数内部对变量进行更改后,生效范围仅限于函数内部,对外部变量没有影响,这种变量称为局部变量;函数内部也可以让变量全局生效,需要加参数global,这种情况很少用。

9、递归函数

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

递归特性:

  • 必须有一个明确的结束条件
  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  • 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian # def func(n1,n2): #获取斐波那契数列100之前的数字
# if n1 > 100:
# return
# print(n1)
# n3 = n1 + n2
# func(n2,n3)
# func(0,1)
#######打印#######
#0
#1
#1
#2
#3
#5
#8
#13
#21
#34
#55
#89 def func(count,n1,n2): #获取斐波那契数列第200个数字并返回给调用者
if count == 200:
return n1
n3 = n1 + n2
r = func(count + 1,n2,n3)
return r
ret = func(1,0,1)
print(ret) #######打印#######
#173402521172797813159685037284371942044301

10、函数式编程介绍 

函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。而函数式编程(请注意多了一个“式”字)——Functional Programming,虽然也可以归结到面向过程的程序设计,但其思想更接近数学计算。我们首先要搞明白计算机(Computer)和计算(Compute)的概念。在计算机的层次上,CPU执行的是加减乘除的指令代码,以及各种条件判断和跳转指令,所以,汇编语言是最贴近计算机的语言。而计算则指数学意义上的计算,越是抽象的计算,离计算机硬件越远。对应到编程语言,就是越低级的语言,越贴近计算机,抽象程度低,执行效率高,比如C语言;越高级的语言,越贴近计算,抽象程度高,执行效率低,比如Lisp语言。

函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。

函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。

简单说,"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。主要思想是把运算过程尽量写成一系列嵌套的函数调用。举例来说,现在有这样一个数学表达式:

 (1 + 2) * 3 - 4

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

    var a = 1 + 2;

  var b = a * 3;

  var c = b - 4;

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

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

这就是函数式编程。  

11、匿名函数

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

#这段代码
def calc(n):
return n**n
print(calc(10)) #换成匿名函数
calc = lambda n:n**n
print(calc(10))

你也许会说,用上这个东西没感觉有毛方便呀, 。。。。呵呵,如果是这么用,确实没毛线改进,不过匿名函数主要是和其它函数搭配使用的呢,如下

res = map(lambda x:x**2,[1,5,7,4,8])
for i in res:
print(i) #####打印#####
1
25
49
16
64 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])
for i in calc:
print(i) #####打印#####
# 10203
# 50203
# 70203
# 40203
# 80203

关于map更多-》》https://my.oschina.net/zyzzy/blog/115096

 

12、高阶函数

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

def add(x,y,f):
return f(x) + f(y) res = add(3,-6,abs)
print(res

  

13、内置函数

二、函数练习

1、做个累加程序(类似1+2+3+.......+99+100的和)

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#-Author-Lian
def cumulative(a=1,b=100):
n = 0
while a <=b:
n += a
a +=1
print(n) cumulative() #默认为1加到100
#5050
cumulative(1,1000)
#500500
cumulative(50) #50加到100
#3825

  

函数式编程和面向过程编程的区别

Python开发【第三章】:Python函数介绍的更多相关文章

  1. 路飞学城-Python开发-第三章

    # 数据结构: # goods = [ # {"name": "电脑", "price": 1999}, # {"name&quo ...

  2. Python自学:第三章 使用函数sort( )对列表进行临时排序

    # -*- coding: GBK -*- cars = ["bmw", "audi", "toyota", "subaru&qu ...

  3. [Python笔记][第三章Python选择与循环]

    1月28日学习 Python选择与循环 选择结构 多分枝选择结构 if 表达式 1: 语句块 1 elif 表达式 2: 语句块 2 elif 表达式 3: 语句块 3 ... else : 语句块 ...

  4. python 历险记(三)— python 的常用文件操作

    目录 前言 文件 什么是文件? 如何在 python 中打开文件? python 文件对象有哪些属性? 如何读文件? read() readline() 如何写文件? 如何操作文件和目录? 强大的 o ...

  5. 【神经网络与深度学习】【python开发】caffe-windows使能python接口使用draw_net.py绘制网络结构图过程

    [神经网络与深度学习][python开发]caffe-windows使能python接口使用draw_net.py绘制网络结构图过程 标签:[神经网络与深度学习] [python开发] 主要是想用py ...

  6. ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...

  7. ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇

    原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...

  8. javascript进阶课程--第三章--匿名函数和闭包

    javascript进阶课程--第三章--匿名函数和闭包 一.总结 二.学习要点 掌握匿名函数和闭包的应用 三.匿名函数和闭包 匿名函数 没有函数名字的函数 单独的匿名函数是无法运行和调用的 可以把匿 ...

  9. python自动化开发-[第三天]-编码,函数,文件操作

    今日概要 - 编码详解 - 文件操作 - 初识函数 一.字符编码 1.代码执行过程 代码-->解释器翻译-->机器码-->执行 2.ASCII ASCII:一个Bytes代表一个字符 ...

  10. Python开发(三):字符编码,文件操作,函数

    一:三级菜单 If len(choice) == continue # 判断输入的是否为空,为空就跳出这次循环进行下次循环, exit(“bye”) :退出程序显示,bye 二:编码 最早的编码是as ...

随机推荐

  1. BZOJ1946 : [Ceoi2006]ANTENNA

    首先通过随机增量法求出最小覆盖圆,作为答案的上界. 然后二分答案,检验的时候枚举每个点作为原点,求出其他每个点被包括在圆内的角度区间,然后扫描线即可. 时间复杂度$O(Tn^2\log n)$. #i ...

  2. maven 仓库地址:

    maven 仓库地址: 共有的仓库 http://repo1.maven.org/maven2/http://repository.jboss.com/maven2/ http://repositor ...

  3. bzoj3083 遥远的国度 题解

    题目大意: 给定一棵有根树,每个点有一个权值,提供三种操作: 1.将x节点变为根节点 2.将x到y路径上的点的权值全部改为v 3.询问x的子树中点权的最小值 思路: 用DFS序剖分,记录每个节点入栈出 ...

  4. ACM 疯牛

    疯牛 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小 ...

  5. ACM 字母统计

    字母统计 时间限制:3000 ms  |  内存限制:65535 KB 难度:1   描述 现在给你一个由小写字母组成字符串,要你找出字符串中出现次数最多的字母,如果出现次数最多字母有多个那么输出最小 ...

  6. ACM: Mr. Kitayuta's Colorful Graph-并查集-解题报

    Mr. Kitayuta's Colorful GraphTime Limit:1000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I6 ...

  7. Centos 下安装Docker 遇到的一些错误

    1.公司的服务器的内核版本:2.6.32-431.23.3.el6_x86_64 如何升级内核请参考前一篇文章 2.在这个地址上面下载 的 https://test.docker.com/builds ...

  8. Oracle中"行转列"的实现方式

    在报表的开发当中,难免会遇到行转列的问题. 以Oracle中scott的emp为例,统计各职位的人员在各部门的人数分布情况,就可以用"行转列": scott的emp的原始数据为: ...

  9. HTTP协议及其请求头分析

    HTTP协议及其请求头分析 HTTP协议及其请求头分析   众所周知,Internet的基本协议是TCP/IP协议,目前广泛采用的FTP.Archie Gopher等是建立在TCP/IP协议之上的应用 ...

  10. [LintCode] Submatrix Sum 子矩阵之和

    Given an integer matrix, find a submatrix where the sum of numbers is zero. Your code should return ...