python函数与函数式编程
1、介绍
1、面向对象:---> 类 ---> class定义 #编程的规范
2、面向过程:---> 过程 ---> def定义 --> 将一段段的逻辑和过程包含到由一个def定义的过程中,无return
3、函数式编程:---> 函数 ---> def定义,有return
函数的优点:代码重用、保持一致性、可扩展性
区别:面向过程实际上就是没有返回值的函数
2、函数
编程语言中函数的定义:函数式逻辑结构化和过程化的一种编程方法。
def test(x):
"The function definitions"
x+=1
return x
def: 定义函数的关键字
test: 函数名
(): 内可定义形参
"": 文档描述(非必要,但建议为函数添加描述信息)
x+=1: 泛指代码块或程序处理逻辑
return: 定义返回值
例子1、
def logger():
with open("a.txt","a+",encoding = "utf-8") as f:
f.write('end action\n')
def test1():
print("in the test1")
logger()
def test2():
print("in the test2")
logger()
def test3():
print("in the test3")
logger()
test1()
test2()
test3()
--->
in the test1
in the test2
in the test3
---> #cat a.txt
end action
end action
end action
例子2、加入时间模块
import time
def logger():
time_format = '%Y-%m-%d %X' #%Y-%m-%d(年月日),%X(时:分:秒)
time_current = time.strftime(time_format) #按照上面的时间格式调用
with open("a.txt","a+",encoding = "utf-8") as f:
f.write('%s end action\n'%time_current)
def test1():
print("in the test1")
logger()
def test2():
print("in the test2")
logger()
def test3():
print("in the test3")
logger()
test1()
test2()
test3()
--->
in the test1
in the test2
in the test3
---> #cat a.txt
2019-09-06 14:03:45 end action
2019-09-06 14:03:45 end action
2019-09-06 14:03:45 end action
例子3、关于函数的return
def test1():
print("in the test1")
return 0
x = test1() #x就代表test1函数体中return返回的结果
print(x)
--->
in the test1
0
例子4、有return和无return的区别
def test1():
print("in the test1")
def test2():
print("in the test2")
return 0
def test3():
print("in the test3") #返回值可以是任意的数据类型,多的话返回一个元组
return 1,['lishang','zhaoxiaomeng'],{'lishang':'zhaoxiaomeng'},'zxm love ls'
x = test1()
y = test2()
z = test3()
print(x) #test1没有return,返回值将为空(None)
print(y) #y=0
print(z) #z=(1, ['lishang', 'zhaoxiaomeng'], {'lishang': 'zhaoxiaomeng'}, 'zxm love ls')
--->
in the test1
in the test2
in the test3
None
0
(1, ['lishang', 'zhaoxiaomeng'], {'lishang': 'zhaoxiaomeng'}, 'zxm love ls')
总结:
返回值数=0,返回None
返回值数=1,返回object
返回值数>1,返回一个tuple
例子5、关键字参数不能在未知参数之前
def test(x,y): #x,y是形参
print(x)
print(y)
test(3,2) #位置参数调用,实参与形参一一对应
test(y=3,x=4) #关键字调用,与形参顺序无关
test(1,y=2) #两种混合,关键字调用必须在后面
test(x=1,2) #这种方式会报错,关键字参数不能在位置参数的前()
例子6、默认参数
def test(x,y=2):
print(x)
print(y)
test(1) #y不赋值,用默认的y=2赋给y
test(1,2) #全都赋值,引用手动赋值的1和2
test(1,3) #也可以改变,引用手动赋值的1和3
例子7、多个实参
*args接收N个位置参数,转换成元组的形式
**kwargs接收N个关键字参数,转换成字典的方式
def test(*args): #*args代表接收的实参数目不固定,转换成元组的形式
print(args)
test(1,2,3,4,5)
test(*[1,2,3,4,5,]) #也可以按照*[],*跟元组的方式传递
--->
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 5)
-----------------------------也可以 test1(x,*args混合接收)----------------------------
def test1(x,*args):
print(x)
print(args)
test1(1, 2, 3, 4, 5, 6, 7)
--->
1
(2, 3, 4, 5, 6, 7)
----------------------------还可以 test2(**kwargs)接收接收N个关键字参数--------------------
def test2(**kwargs):
print(kwargs)
test2(name='lishang',age=23,sex='man')
test2(**{'name':'xiaomeng','age':18,'sex':'girl'}) #也可以按照**{},**跟字典的方式传递
--->
{'name': 'lishang', 'age': 23, 'sex': 'man'}
{'name': 'xiaomeng', 'age': 18, 'sex': 'girl'}
-----------------------还可以 test3(name,**kwargs)位置参数与关键字参数混合接收----------------
def test3(name, **kwargs):
print(name)
print(kwargs)
test3('lishang',age=18,girlfriend='zhaoxiaomeng')
lishang
{'age': 18, 'girlfriend': 'zhaoxiaomeng'}
--->
lishang
{'age': 18, 'girlfriend': 'zhaoxiaomeng'}
-----------------------还可以 test4(name,age=18,**kwargs)字典与默认参数混合接收----------------
def test4(name,age=18,**kwargs):
print(name)
print(age)
print(kwargs)
test4('xiaomeng', sex='girl', hobby='lishang')
--->
xiaomeng
18
{'sex': 'girl', 'hobby': 'lishang'}
----------------最后可以 test5(name,age=18,*args,**kwargs)形参、默认参数、元组、字典混合接收:-----------
def test5(name,age=18,*args,**kwargs):
print(name)
print(age)
print(args)
print(kwargs)
test5('xiaomeng',24,'she likes Lishang',sex='girl',hobby='lishang')
--->
xiaomeng
24
('she likes Lishang',)
{'sex': 'girl', 'hobby': 'lishang'}
3、局部变量和全局变量
3.1、局部变量
#函数第三行的(name)就是局部变量,只在局部生效
def change_name(name):
print("before name:",name)
name = "LiShang" #这个函数是这个变量的作用域,这里改变的name只在函数中生效
print("after name:",name)
name = "lishang"
change_name(name)
print("name:",name) #因此哪怕函数中已经改为了大写,最后输出的还是小写
--->
before name: lishang
after name: LiShang #只改变了函数中的变量
name: lishang #输出与一开始一致
3.2、全局变量
#函数中的(school)是局部变量,只影响函数中他自己
#最外层定义的(school)是全局变量,函数中的school改变,它不会变
school = "old boy" #全局变量
def change_name(name):
school = "baoge edu" #局部变量
print("before name:",name,school)
name = "LiShang"
print("after name:",name)
name = "lishang"
change_name(name)
print("name:",name)
print(school)
--->
before name: lishang baoge edu #这里输出的是函数中局部变量(school)的值
after name: LiShang
name: lishang
old boy #这里输出的是最外层全局变量的值
3.3、如果要在局部改全局变量,添加---global------但是不要用这种方式
school = "old boy" #全局变量
def change_name(name):
global school #加上这个,在局部可修改全局变量
school = "baoge edu" #局部变量
print("before name:",name,school)
name = "LiShang"
print("after name:",name)
name = "lishang"
change_name(name)
print("name:",name)
print(school)
--->
before name: lishang baoge edu
after name: LiShang
name: lishang
baoge edu #这次就输出了局部变量中(school)的值
3.4、总结---局部改全局变量
字符串、数字、字母等数据类型不能在局部修改全局变量
列表、字典、集合、类都是可以再局部修改全局变量的
4、递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自己,这个函数就叫递归函数
def calc(n):
print(n)
return calc(n+1)
calc(0)``
--->
1
2
3
...
995
RecursionError: maximum recursion depth exceeded while calling a Python object
当调用python的时候,超出了最大的递归深度,内部保护机制,最大深度为999层
4.1实例、输入一个数字,每次除以2,知道小于1,就停止
def calc(n):
print(n)
if int(n/2) >0:
return calc(int(n/2))
print("+++++++>",n)
calc(10)
--->
10
5
2
1
+++++++> 1
递归的特性:
1、必须有一个明确的结束条件
2、每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3、递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个
函数调用,栈就会增加一层栈帧,每当函数返回,栈就会减一层栈帧.由于栈的大小不是无限的,所以,递归调用的次数过
多,会导致溢出)
5、函数式编程
函数是Python内建支持的一种封装,我们通过把大段的代码拆成函数,通过一层一层的函数调用,就可以把复杂的任务
分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的圣墟设计单元。
而函数式编程(多了一个'式'字)--Functional Programming,虽然也可以递归到面向过程的程序设计,但其思想更
接近数学计算,函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变
量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,
不论什么时候调用,调用几次,值都是不变的。
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);
这段代码再演进以下,可以变成这样
add(1,2).multiply(3).subtract(4)
这基本就是自然语言的表达了。再看下面的代码,大家应该一眼就能明白它的意思吧:
merge([1,2],[3,4]).sort().search("2")
因此,函数式编程的代码更容易理解。
要想学好函数式编程,不要玩py,玩Erlang,Haskell, 好了,我只会这么多了。。。
6、高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def add(x,y,f):
return f(x) + f(y)
res = add(3,-6,abs) #abs()函数是取绝对值函数
print(res)
--->
9