python之函数

一、函数

1、函数定义:函数是逻辑结构化和过程化的一种编程方法

函数构成:

 1 python中函数定义方法:
 2 def test(x):
 3     "The function definitions"
 4     x+=1
 5     return x
 6 def:定义函数的关键字
 7 test:函数名
 8 ():内可定义形参
 9 "":文档描述(非必要,建议为函数添加描述信息)
10 x+=1:泛指代码块或程序处理逻辑
11 return:定义返回值
12 
13 函数调用运行:可以带参数也可以不带参数

2、函数和过程

过程:就是没有返回返回值的函数,严格意义上说,在python中没有过程,因为python中没有值会直接返回一个None!

3、使用函数的好处

(1)、代码重用

(2)、保持一致性,易维护

(3)、可扩展性

4、函数的参数

(1)、形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量

(2)、实参可以是常量、变量、表达式、函数等,无论实参是何种类型的变量,在进行函数调用时,他们必须有确定的值,以便把这些值传送给形参。因此应预先用赋值、输入等办法使参数获得确定值

def chengji(x,y): # x,y 为形参
    res = x**y
    return res
a = chengji(3,4) # 3,4为实参
print(a)

(3)、位置参数和关键字(标准调用:实参和形参位置一一对应;关键字调用:位置无需固定)

a、位置参数,参数必须一一对应,缺一不行,多一也不行

b、关键字参数,无需一一对应,缺一不行,多一夜不行

c、位置参数和关键字参数混用的时候,位置参数必须卸载关键字参数左边不然会报错

def xianxin(x,y,z):
    res = x+3*y-2*z
    return res
a = xianxin(8,1,2.3)  
print(a) #6.4
 
def xianxin(x,y,z):
    res = x+3*y-2*z
    return res
#TypeError: xianxin() takes 3 positional arguments but 4 were given
#形参为3个x,y,z,调用函数的时候实参为4个,就出现上述报错
# a = xianxin(8,1,2.3,1)
#TypeError: xianxin() missing 1 required positional argument: 'z'
#形参为3个x,y,z,调用函数的时候实参为2个,就出现上述报错
a = xianxin(8,1)
print(a)

(4)、默认参数

 1 def handle(x,oraclename='orcl'):
 2     print(x,oraclename)
 3 a = handle('hello world') #oraclename在调用的时候赋值,默认为orcl
 4 print(a)  #输出结果:hello world orcl     None
 5 #为什么会hello world orcl后会接着输出一个None呢?因为在定义handle函数的时候没有return返回值,在python中没有定义返回值
 6 #就会默认返回None;
 7 
 8 
 9 
10 def handle(x,oraclename='orcl'):
11     print(x,oraclename)
12     return True
13 #Welcone to: Python   #True
14 print(handle('Welcone to:',oraclename = 'Python'))  

(5)、参数组

def test(x,*y):
    print(x) #1
    print(y)#(2, 3, 4, 5, 6)
    print(y[0]) #2
print(test(1,{2,3,4,5,6}))

def test(x,*y):
    print(x)  #1
    #如果传入的是一个列表或者字典,直接将列表或者字典作为一个元素放入元组中
    print(y) #([2, 3, 4, 5, 6],)
    print(y[0])[2, 3, 4, 5, 6]
print(test(1,[2,3,4,5,6]))

备注:上面是将整个列表或者字典作为一个元素传值给形参那如果我传入的是个列表,我只想将列表里面的元素传给形参呢

1 def test(x,*y):
2     print(x)  #1
3     print(y) #(1, 2, 3, 4)
4 test(1,*[1,2,3,4])

直接在传入的列表实参前面加一个“*”,就可以将列表里面的元素传值给形参

备注: **kwargs:**{},可以将字典里面的元素传值给形参

 1 def test(x,**kwargs):
 2     print(x)#x
 3     print(kwargs)#{'y': 2, 'z': 3}
 4 test(1,y = 2,z = 3)
 5 
 6 def test(x,**kwargs):
 7     print(x)#1
 8     print(kwargs)#{'z': 2, 'y': 3}
 9 test(1,**{'z':2,'y':3})
10 
11 def test(x,**kwargs):
12     print(x)
13     print(kwargs)#TypeError: test() takes 1 positional argument but 2 were given
14 test(1,{'z':2,'y':3})

       *args:*[],可以将列表里面的元素传值给形参;接收可变长度的值,主要的作用是用于后期的扩展,及不确定调用的接口到底有多少个参数

1 def test(x,*y):
2     print(x)  #1
3     print(y) #(1, 2, 3, 4)
4 test(1,*[1,2,3,4])

备注:那两个混用呢,不能违背一个大的前提,位置参数必须要在关键字参数的左边,不然后报错, *args和**kwarg混用也是遵循这个原则的

def test(x,*args,**kwargs):
    print(x)#1
    print(args)#
    print(kwargs)#('a', 'b')
test(1,'a','b',y=1,z=1) #{'y': 1, 'z': 1}

def test(x,*args,**kwargs):
    print(x)#1
    print(args)#(1, 2, 3, 4, 5)
    print(kwargs)#{'z': 1, 'y': 2}
test(1,*[1,2,3,4,5],**{'z':1,'y':2})

 二、局部变量与全局变量

1、全局变量:全局作用域

在函数中修改全局变量修饰词语:global

1 name = 'zhuliye'
2 def change_name():
3     global name
4     name = 'zhuyintai'
5     print('My name is ',name) #My name is  zhuyintai
6 change_name()
7 #在调用了change_name函数后,全局变量name的值为"zhuyintai"
8 print(name) #zhuyintai

2、局部变量:局部作用域

nolocal修饰的是上一级变量

3、函数即变量——前向引用

三、函数递归

1、死循环

首先来看下列代码:运行下列代码,报错:“进入了死循环”,因为在函数调用自身的时候没有一个明确借结束的条件,所以出现死循环,造成内存溢出

1 def calc(n):
2     print(n)
3     calc(n)
4 calc(10) #RecursionError: maximum recursion depth exceeded while calling a Python object

2、函数递归的特点:

(1)、函数递归

在函数内部,可以调用其他函数,如果在调用一个函数直接或间接调用自身就是函数递归

(2)、函数递归的特点

a、必须要有一个明确的结束条件,不然就会出现死循环

b、每次进入更深一层递归时,问题规模相比上次递归都应有所减少

c、递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

堆栈详解:http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html 

尾递归优化:http://egon09.blog.51cto.com/9161406/1842475

 四、匿名函数lambda

1、lambda函数格式:lambda 形参:表达式

例如:lambda x :x+1

1 func = lambda x :x**2
2 func(10)
3 #lambda函数在未调用的时候就是一串内存地址;
4 #lambda函数一般是不会单独存在的;
5 print(func) #<function <lambda> at 0x000001641C1029D8>
6 print(func(10)) #100

2、多个形参的lambda函数

 1 # print(lambda name:'name'+'_sb')
 2 # res = lambda name: name+'_sb'
 3 # print(lambda name:'name'+'_sb') #<function <lambda> at 0x0000019A8F812D90>
 4 # print(res('zhangssn')) #zhangssn_sb
 5 
 6 
 7 # res1 = lambda x,y,z:2*x+3*y-z
 8 # print(res1(10,2,-1)) #27 还是遵循的是函数位置参数的原则
 9 # print(res1(1,2,z=3))#5 位置参数和关键字参数
10 
11 res2 = lambda x,y,z :(x+1,y+2,z+3)
12 print(res2(10,2,4)) #(11, 4, 7)

五、函数式编程

编程的三种方法论

1、面向对象编程;

2、函数式编程;

3、面向对象编程;

1、面向过程

找到解决问题的入口,按照一个固定的流程去模拟解决问题的流程

例子:

a、搜索目标,用户输入(配偶要求),按照要求到数据结构(字典)内检索符合要求的人物

b、表白,表白成功进入3,否则进入2;

c、恋爱,恋爱成功进入4,否则返回1;

d、见家长,家长同意进入5,家长说他是你失散多年的妹妹,返回1;

e、结婚

1 def res(x,y):
2     res1 = 2*x #1
3     res2 = res1-y #2
4     res3 = res2*2#3
5     return res3
6 res(2,1)
7 print(res(2,1))

2、函数式编程:

函数式编程:函数式=编程语言定义的函数+数学意义的函数

函数式就是用编程语言去实现数学函数。这种函数内对象是永恒不变的,要么参数是函数,要么返回值是函数,没有for和while循环,所有  的循环都是由递归去实现的,无变量的赋值(即不用变量去保存状态),无赋值即不改变。

(1)、特点

a、不可变的数据——不用变量保存状态,不修改变量

b、第一类对象——函数名可以当做参数传递,返回值可以是函数名

c、尾调用优化(尾递归)

 3、高阶函数

a、函数接收的参数是一个函数;

b、函数的返回值是一个函数;

原文地址:https://www.cnblogs.com/tengjiang/p/9315249.html