python函数 与 函数式编程
「函数」一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。
函数是一个能完成特定功能的代码块,可在程序中重复使用,减少程序的代码量和提高程序的执行效率。
定义:将一组语句的集合通过一个名字(函数名)封装起来,通过调用该函数名执行。
# 函数主要作用:
1. 减少重复代码
2. 方便修改 更易扩展
3. 保持代码一致性
1「函数的创建」
1.1 在python中,函数定义语法格式如下:
def function_name(arg1,arg2[,...]): #采用def 关键字 statement [return value] #返回值不是必须的,如果没有return语句,则Python默认返回值None。
1.2 函数名的命名规则
1. 函数名必须以下划线或字母开头,可以包含任意字母、数字或下划线的组合。不能使用任何的标点符号; 2. 函数名是区分大小写的。 3. 函数名不能是保留字。
1.3 形参和实参
形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收实参(实参个数,类型应与实参一一对应)
实参:实际参数,调用函数时传给函数的参数,可以是常量,变量,表达式,函数,传给形参
区别:形参是虚拟的,不占用内存空间,.形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存空间,数据传送单向,实参传给形参,不能形参传给实参
1.4 返回值
要想获取函数的执行结果,就可以用return语句把结果返回。
# 注意: a. 函数在执行过程中只要遇到return语句,就会停止执行并返回结果;因此,也可以理解为 return 语句代表着函数的结束。 b. 如果未在函数中指定return,那这个函数的返回值为None c. return多个对象,解释器会把这多个对象组装成一个元组或者字典,作为一个一个整体结果输出。
2「函数的参数」
2.1 参数类型
a. 位置参数 # (也称作:必备参数) b. 关键字参数 c. 默认参数 # (也称作:缺省函数) d. 不定长参数 # (也称作:可变长参数 有两种*args:接收的参数封装成一个元组,**kwargs:接收的参数封装成一个字典)
另外注意:*后边的args 和 **后边的kwargs 这两个字符是约定俗称的建议写法,这块是可以自定义的。
a. 位置参数:
位置参数,必须以正确的顺序传入函数;调用时的参数个数必须和声明时的一致。
def f(name,age): # 这里定义了nam,age 两个形参 print('I am %s,I am %d'%(name,age)) f('jesson',26) #实参输入的时候,有先后顺序,与形参上下对应 f('pitter',25,'sport') #这里调用,会报错;因为传入3个实参数量,超过了定义的两个形参数量;同时少了也不可以。
b. 关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
def f(name,age): print('I am %s,I am %d'%(name,age)) # f(26,'jesson') #报错 f(name='jesson',age=26) f(age=26,name='jesson') #两种写法都可以
c. 默认参数(缺省函数)
调用函数时,缺省参数的值如果没有传入,则被认为是默认值。
实例会打印默认的性别,如果sex没有被传入:
def print_info(name,age,sex='male'): print('Name:%s'%name) print('age:%s'%age) print('Sex:%s'%sex) return print_info('jesson',26) #这里不给sex参数传值的话,会获取默认的值 print_info('pitter',25,'male') print_info('张三',28,'female')
d. 不定长参数
在函数参数的引用时,有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。
加了星号(*)的变量名会存放所有未命名的变量参数;而加(**)的变量名会存放命名的变量参数,即传入的值要求是以键值对的形式。
def add(*args): sum=0 for v in tuples: sum+=v return sum print(add(1,3,5,7,9)) #这里一次传入多个值,形参*args 会将获取的多个值,封装成一个元组。 print(add(2,4,6,8,10))
def print_info(**kwargs): print(kwargs) for i in kwargs: print('%s:%s'%(i,kwargs[i]))#根据参数可以打印任意相关信息了 return print_info(name='jesson',age=26,sex='male',hobby='sports',nationality='Chinese',job='IT')
总结:
Python中函数的参数主要有以上四种,它们在定义时候,如果需要同时使用,注意写法有一个先后顺序;即:
位置参数 》 默认参数 》 *不定长参数(元组) 》 **不定长参数(字典)
这么做的目的是为了保证获取值的一致性,不出现错乱。
例如:
def print_info(name,sex='male',*args,**kwargs):
3「函数的作用域」
3.1 作用域介绍:
python程序执行的时候,查找引用函数的默认顺序,遵循LEGB原则。
即:引用函数的时候,在四个作用域中查找:先局部(Local),次之(Enclosing),再次之全局(Global),最后是内置(Build-in)。
- L:local,局部作用域,即函数中定义的变量;
- E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
- G:globa,全局变量,就是模块级别定义的变量;
- B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
x = int(2.9) # int built-in g_count = 0 # global def outer(): o_count = 1 # enclosing def inner(): i_count = 2 # local print(o_count) #print(i_count) #找不到 inner() outer() # print(o_count) #找不到 因为执行是从上往下,查找是有内往外,局部函数可以调用全局变量,外部的函数不能调用局部变量
当然,local和enclosing是相对的,enclosing变量相对上层来说也是local。
3.2 作用域产生
在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的,如下代码:
if 2>1: x = 1 print(x) # 1
这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。
def test(): x = 2 print(x) # NameError: name 'x2' is not defined 可以类比局部变量可以引用全局变量,全局变量不能调用局部变量。
def、class、lambda是可以引入新作用域的。
3.3 变量的修改
5「高阶函数」
def add(x,y,f): return f( x)+ f( y) print add(-18,11,abs)
它将这么执行:
abs(-18) + abs(11)
结果则会是:
29
map()函数
map()是 Python 内置的高阶函数,它接收一个函数 f 和一个list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回。
def f(x): return x* x print map(f,[1,2,3,4,5,6,7]) #list里的每个元素都会走一遍f(x)方法
结果将会是:
[1, 4, 9, 10, 25, 36, 49]
reduce()函数
def f(x ,y ): return x* y print reduce(f,[1,2,3,4]) #1*2*3*4
它的结果将会是这样:
24
如若想给初始值呢?需要这样:
def f(a,b): return a+ b print reduce(f,[1,2,3,4],10) #1+2+3+4+10.这里的第三个参数是做为初始值的。
结果会是:
20
filter()函数
def is_odd(x): return x%2==1 print filter(is_odd,[1,2,3,4,5,6,7])
结果是:
[1, 3, 5, 7]
自定义排序函数
Python内置的 sorted()函数可对list进行排序:
sorted([36, 5, 12, 9, 21])
结果是:
[5, 9, 12, 21, 36]
但 sorted()也是一个高阶函数,它可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
6 匿名函数
高阶函数是可以把函数当参数来传递的,那么当不需要显示传递的函数名称时应该怎么办呢?我们就可以用到匿名函数。
比如上面讲了Map()函数,当时的例子是这样:
def f(x): return x* x print map(f,[1,2,3,4,5,6,7]) #list里的每个元素都会走一遍f(x)方法
要将其改成匿名函数,匿名函数的话需要用到lambda关键字,后面跟参数,然后冒号,再后面就写表达式,也就是返回的结果,不用写return。那么这个匿名方法将会是这样:
print map(lambda x:x*x,[1,2,3,4,5,6,7])
最后将上面的reduce()函数改成匿名函数吧,略体会下匿名方法的写法。原本是这样:
def f(x ,y ): return x* y print reduce(f,[1,2,3,4]) #这里是写"f",而不是"f()"
匿名方法将是:
print reduce(lambda x,y:x+y,[1,2,3,4,5])
7「递归函数」
「函数式编程」