有没有发现,在前面的那么多的教程当中,我们没有函数是不是也是可以写的出来的,似乎没有函数这个东西,我们变成也是可以实现的,但是,在实际的开发过程中,我们为什么需要函数呢,它到底能够给我们变成带来怎样的好处呢?
其实,函数这个东西我们可以把它想成是一个包装盒,我们没有包装盒的时候,其实也是可以把礼物送给相送的人手上的,但是,当我们用包装盒包装美化之后,我们首先会更好拿,其次,会更加的好看,更赏心悦目,当然,我们要达到的目的就是,让收到礼物的人开心,所以,我们买礼物的时候,通常都会很用心的买一个包装盒美美的包装一下。
而函数,就是这么个作用,我们需要把我们写的零零散散的代码包装起来,让它更好阅读,同时也能更好的管理我们的代码。
说了这么多,那么到底如何使用函数呢?下面一一道来。
二、如何定义函数这里,我们先把上面用很浅显的话说的函数更加正式的表达一下。函数是组织好的、可重复使用的、用户实现单一或者关联功能的代码段。函数能够提高应用的模块性和代码的重复利用率。
定义函数规则def 函数名([参数列表]): #参数列表可选项 函数体
举例
def printName():
print('我是 hello world!')
printName()注意几点
函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
任何传入参数和自变量必须放在圆括号中间。
函数内容以冒号起始,并且缩进。
是不是很简单,只要你学过一门编程语言,这些应该都是不值得一提。
现在我们定义好了函数,就相当于我们已经有了包装礼物的包装盒,那么我们如何用包装盒去包装礼物呢,也就是说我们如何去使用函数呢?
使用函数规则
函数名([参数列表])
举例
定义函数
def printName():
print('我是 hello world!')调用函数
printName()
其实就是这么简单!
好了,在我们包装礼物的时候,可能我们会想收礼物的人写封信或者写点东西递交给他,这个时候,我们可能会写个小纸条啦,而函数,我们也可以传信哦!
这时候,就要用到函数参数这个概念了。
三、函数参数函数参数就是说我们可以在定义函数的时候,在括号中定义变量,用于传给函数内部使用,已达到“传信”’的效果!
举例
def printName(name):
print('我是:', name)这个括号中的 name ,就是我们定义的函数参数了。
除了需要知道这个以外,我们还需要了解一个概念。
实参与形参那么什么是实参,什么是形参呢,通过下面这张图,你就知道了!
我们传信给对方的时候是不是也有很多的方式,比如,我们可以简单的拿张小纸条写写,也可以买个信封写封信。
同样,函数的参数也有一些不同的类型。
参数类型位置实参位置实参:函数定义中允许拥有多个形参,因此函数在调用的时候,也可能包含多个实参。向函数传递参数的方式有很多,通过实参和形参的顺序对应
关键字参数关键字实参是传递给函数的名称-值对。直接在实参中将名称和值关联起来,因此向函数传递实参时不会混淆。函数调用使用关键字参数来确定传入的值。所以,位置可以不用对应。
# 定义函数def printName(name, age):
print('我是:', name)
print('我:', age)# 调用函数printName(age=18, name='欧阳思海') # 名字跟形参对应,但是位置可以不对应参数默认值在很多语言都是有默认值这个特性的。
默认值:函数定义的时候,设置的参数是形参。那么也可以给每个形参指定一个默认值。当调用函数时,如果没有传入实参,就使用形参的默认值。如果调用的时候传入了实参,那么程序将使用传入的实参。
# 定义函数:使用默认值 age=15def printName(name, age=15):
print('我是:', name)
print('我:', age)# 调用函数printName(age=18, name='欧阳思海') # 名字跟形参对应,但是位置可以不对应printName(name='欧阳思海') # age有默认值,不赋值,默认15不定长参数不定长参数:你可能需要一个函数能处理比当初声明时更多的参数。
规则
def 函数名(*parameter,**parameter): 函数体
注意:加了*和**的就是不定长参数。
# 定义函数def printPara(*para, **para2):
print(para)
print(para2)# 调用函数printPara('one', 'two', 'three', four='4', five='5')由此可知:
加一个*的不定长参数,会接收没有命名的实参,且会转为元祖tuple。
加两个*的不定长参数,会接受有命名的实参,且转化为字典dictionary。
以上就是函数参数的内容了。
有时候,我们把信封放在礼物中送给对方之后,可能,她直接把礼物加信息拒绝了,这时候,就返回给你了。所以,把函数参数传过去之后,并不是一定就输出结果的,有时候,还会返回。所以就有返回值了
四、函数返回值换专业点的话说:函数其实并非我们想象的总是简单的将结果直接输出,相反,函数的调用者需要函数提供一些通过函数处理过后的一个或者一组数据,只有调用者拥有了这个数据,才能够做一些其他的操作。那么这个时候,就需要函数返回给调用者数据,这个就被称之为返回值,想要在函数中把结果返回给调用者,需要在函数中使用return。return 就是返回值的关键词。
下面,我们用一个例子直接看 return 怎么使用。
def sum(a, b): return a + b result = sum(1, 2) print(result)
通过这个例子我们可以看出,通过 return 语句 这样的方式,就可以把 我们想要返回的东西返回。
然后,通过 调用函数 可以用一个变量 接收函数返回的值,以便保存使用。
看了这个例子之后,我想,我们应该知道 return 有什么作用了。
return 作用
返回结果。
退出函数,return 语句后的函数内容将不会再执行。
在编程语言中,都有叫做变量域的东西。也就是,限制我们变量在哪个地方能用,哪个地方不能用。
变量分为局部变量和全局变量。
局部变量:在函数内定义的变量,局部变量只能在所定义的函数内使用,在不同函数内定义的相同的变量是不会相互影响的,如果在函数 A 中定义了变量 variable,在函数 B 中也定义了变量 variable,这两个是相互不影响的。
全局变量:在函数外定义的变量,任何地方都可以使用。
举例
c = 3 # 全局变量def sum(a, b): d = 5 # 局部变量 return a + b result = sum(1, 2) print(result) print(c) # 正确,全局变量处处可以访问print(d) # 错误,不能访问局部变量
下面,我们需要注意一个问题,当我们需要在函数内部修改一个全局变量时,我们需要用一个关键词 global 来声明,这样我们才能够改变。
举例
c = 3 # 全局变量print('全局变量id:', id(c))def sum(a, b):
global c
c = 5 # 局部变量
print('sum中全局变量id:', id(c)) return a + bdef sum2(a, b):
print('sum2中全局变量id:', id(c)) return a + b
sum(1, 2)
print('全局变量id..:', id(c))
sum2(2, 2)在这个例子中我们可以看到,当我们用 global c 声明之后,后面再使用变量 c 的时候,变量 c 已经改变了。
再用一个例子,当我们不用 global 声明直接修改时,后面的 变量 c 的 id的值是不会改变了。
c = 3 # 全局变量print('全局变量id:', id(c))def sum(a, b):
# global c
c = 5 # 局部变量
print('sum中全局变量id:', id(c)) return a + bdef sum2(a, b):
print('sum2中全局变量id:', id(c)) # c = 10
return a + b
sum(1, 2)
print('全局变量id..:', id(c))
sum2(2, 2)注:id 是用来展示变量唯一性的。
六、匿名函数匿名函数:定义函数的过程中,没有给定名称的函数就叫做 匿名函数;Python 中使用 lambda 表达式来创建匿名函数。
规则
lambda 参数列表: 表达式
下面我们先用一个例子来看看 lambda表达式 怎么使用。
举例
res = lambda a, b: a + b print(res(1, 2)) # 输出3
其中,a,b是参数,a + b 是执行表达式,可以是简单的表达式,也可以是函数等。
def sum(a, b): return a + b res = lambda a, b: sum(a, b) #执行表达式是函数print(res(1, 2))
在前面的我们已经学过 if-else 形式了,在这里,再学习一种不一样的形式。
条件成立的内容 if 条件 else 条件不成立的内容
举例
s = lambda x, y: x if x > 2 else y print(s(2, 4)) # 输出4七、递归函数
递归就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己。
形象点说就是一个黑洞一样,一层一层的往里走,走到最后,再往回走,直到走到出发点,这就是递归的整个过程。在走的过程中,我们就可以计算。
这里只是简单的说说递归函数的简单的用法。
例如:
阶乘 1 * 2 * 3 ··· * n
''' 阶乘 '''def jiechen(n): if n == 1: return 1 else: return n*jiechen(n-1) print(jiechen(10))
这个例子,就是函数自己再调用函数自己。
八、高阶函数map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
举例说明,比如我们有一个函数f(x)=x2,要把这个函数作用在一个list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就可以用map()实现如下:
现在,我们用Python代码实现:
>>> def f(x):... return x * x ...>>> map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) [1, 4, 9, 16, 25, 36, 49, 64, 81]
请注意我们定义的函数f。当我们写f时,指的是函数对象本身,当我们写f(1)时,指的是调用f函数,并传入参数1,期待返回结果1。
因此,map()传入的第一个参数是f,即函数对象本身。
像map()函数这种能够接收函数作为参数的函数,称之为高阶函数(Higher-order function)。
你可能会想,不需要map()函数,写一个循环,也可以计算出结果:
L = []for n in [1, 2, 3, 4, 5, 6, 7, 8, 9]: L.append(f(n))print L
的确可以,但是,从上面的循环代码,能一眼看明白“把f(x)作用在list的每一个元素并把结果生成一个新的list”吗?
所以,map()作为高阶函数,事实上它把运算规则抽象了,因此,我们不但可以计算简单的f(x)=x2,还可以计算任意复杂的函数。
再看reduce的用法。reduce把一个函数作用在一个序列[x1, x2, x3...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,其效果就是:
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
比方说对一个序列求和,就可以用reduce实现:
>>> def add(x, y):... return x + y ...>>> reduce(add, [1, 3, 5, 7, 9])25
当然求和运算可以直接用Python内建函数sum(),没必要动用reduce。
但是如果要把序列[1, 3, 5, 7, 9]变换成整数13579,reduce就可以派上用场:
>>> def fn(x, y):... return x * 10 + y ...>>> reduce(fn, [1, 3, 5, 7, 9])13579
这个例子本身没多大用处,但是,如果考虑到字符串str也是一个序列,对上面的例子稍加改动,配合map(),我们就可以写出把str转换为int的函数:
>>> def fn(x, y):... return x * 10 + y
...>>> def char2num(s):... return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
...>>> reduce(fn, map(char2num, '13579'))13579整理成一个str2int的函数就是:
def str2int(s):
def fn(x, y):
return x * 10 + y def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s] return reduce(fn, map(char2num, s))还可以用lambda函数进一步简化成:
def char2num(s):
return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]def str2int(s):
return reduce(lambda x,y: x*10+y, map(char2num, s))也就是说,假设Python没有提供int()函数,你完全可以
作者:程序员欧阳思海
链接:https://www.jianshu.com/p/c10aae0a8be5



