python函数 与 函数式编程

时间:2023-03-08 17:21:40

「函数」一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在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「高阶函数」

高阶函数就是把函数当做参数传递的一种函数。其与C#中的委托有点相似,个人认为。
 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()函数

reduce()函数也是Python内置的一个高阶函数。reduce()函数接收的参数和 map()类似,一个函数 f,一个list,但行为和 map()不同,reduce()传入的函数 f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。
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()函数

filter()函数是 Python 内置的另一个有用的高阶函数,filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
 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「递归函数」

「函数式编程」