函数

函数介绍

什么是函数

请看如下代码:

print "                            _ooOoo_  "
print "                           o8888888o  "
print "                           88  .  88  "
print "                           (| -_- |)  "
print "                            O\\ = /O  "
print "                        ____/`---'\\____  "
print "                      .   ' \\| |// `.  "
print "                       / \\||| : |||// \\  "
print "                     / _||||| -:- |||||- \\  "
print "                       | | \\\\\\ - /// | |  "
print "                     | \\_| ''\\---/'' | |  "
print "                      \\ .-\\__ `-` ___/-. /  "
print "                   ___`. .' /--.--\\ `. . __  "
print "                ."" '< `.___\\_<|>_/___.' >'"".  "
print "               | | : `- \\`.;`\\ _ /`;.`/ - ` : | |  "
print "                 \\ \\ `-. \\_ __\\ /__ _/ .-` / /  "
print "         ======`-.____`-.___\\_____/___.-`____.-'======  "
print "                            `=---='  "
print "  "
print "         .............................................  "
print "                  佛祖镇楼                  BUG辟易  "
print "          佛曰:  "
print "                  写字楼里写字间,写字间里程序员;  "
print "                  程序人员写程序,又拿程序换酒钱。  "
print "                  酒醒只在网上坐,酒醉还来网下眠;  "
print "                  酒醉酒醒日复日,网上网下年复年。  "
print "                  但愿老死电脑间,不愿鞠躬老板前;  "
print "                  奔驰宝马贵者趣,公交自行程序员。  "
print "                  别人笑我忒疯癫,我笑自己命太贱;  "
print "                  不见满街漂亮妹,哪个归得程序员?"

运行后的现象:

佛祖镇楼
Python3-函数初解03
想一想:

如果一个程序在不同的地方需要输出“佛祖镇楼”,程序应该怎样设计?

if 条件1:
    输出‘佛祖镇楼’

...(省略)...

if 条件2:
    输出‘佛祖镇楼’

...(省略)...

如果需要输出多次,是否意味着要编写这块代码多次呢?

小结:
如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数

函数的定义与调用

<1>定义函数

定义函数的格式如下:

  def 函数名():
        代码


# 定义一个函数,能够完成打印信息的功能
  def printInfo():
      print '------------------------------------'
      print '         人生苦短,我用Python'
      print '------------------------------------'

<2>调用函数

定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它

调用函数很简单的,通过 函数名() 即可完成调用

demo:

# 定义完函数后,函数是不会自动执行的,需要调用它才可以
printInfo()

函数的文档说明

 def test(a,b):
   "用来完成对2个数求和"
  print("%d"%(a+b))
 test(11,22)
33

当同事或者自己需要查看 函数(test)的说明时:
(也可以按住键盘CTRL 然后鼠标点击目标函数)

help(test)  #能够看到test函数的相关说明
Help on function test in module __main__:
test(a, b)
    用来完成对2个数求和

函数的参数

思考一个问题,如下:

现在需要定义一个函数,这个函数能够完成2个数的加法运算,并且把结果打印出来,该怎样设计?下面的代码可以吗?有什么缺陷吗?

 def add2num():
       a = 11
       b = 22
       c = a+b
       print c

没错,在我们想要调用这个函数的时候,发现根本无从下手,不知道怎么使用这个函数。

为了让一个函数更通用,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可以让函数接收数据,就解决了这个问题,这就是 函数的参数

<1> 定义带有参数的函数

示例如下:

  def add2num(a, b):  #a,b即这个函数的参数
        c = a+b
        print c

<2> 调用带有参数的函数

以调用上面的add2num(a, b)函数为例:

def add2num(a, b):
        c = a+b
        print c

    add2num(11, 22) #调用带有参数的函数时,需要在小括号中,传递数据

调用带有参数函数的运行过程:
Python3-函数初解03

<3> 调用函数时 参数的顺序

#定义函数==============
def test(a,b):
		print(a,b)
——————调用示例——————
 test(1,2)	#调用
1 2	#输出
——————调用示例——————
 test(b=1,a=2) #调用
2 1 #输出
 ——————调用示例——————
test(b=1,2) #调用后报异常
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

小结

定义时小括号中的参数,用来接收参数用的,称为 “形参
调用时小括号中的参数,用来传递给函数用的,称为 “实参

函数返回值(一)

<1>“返回值”介绍

现实生活中的场景:

去自动售货机买饮料,自动售货只卖3种价格的饮料,投币口只支持5元、10元、20元这3种规格的纸币

在这个例子中:
函数:售货机
形参:售货机投币口
实参:3种不同规格的纸币
返回值:对应价格的饮料
你往售货机里放不同面额的纸币,售货机的取货口会落下相应规格的饮料,这就完成了一个完整的函数调用。

开发中的场景:

定义了一个函数,完成了获取室内温度,想一想是不是应该把这个结果给调用者,只有调用者拥有了这个返回值,才能够根据当前的温度做适当的调整

综上所述:

  • 所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果

<2>带有返回值的函数

想要在函数中把结果返回给调用者,需要在函数中使用return

如下示例:

    def add2num(a, b):
        c = a+b
        return c

或者

    def add2num(a, b):
        return a+b

<3>保存函数的返回值

如果一个函数返回了一个数据,那么想要用这个数据,那么就需要保存

保存函数的返回值示例如下:

    #定义函数
    def add2num(a, b):
        return a+b

    #调用函数,顺便保存函数的返回值
    result = add2num(100,98)

    #因为result已经保存了add2num的返回值,所以接下来就可以使用了
    print result

结果:

    198

4种函数的类型

函数根据有没有参数,有没有返回值,可以相互组合,一共有4种

  • 无参数,无返回值
  • 无参数,有返回值
  • 有参数,无返回值
  • 有参数,有返回值

<1>无参数,无返回值的函数

此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数

    def printMenu():
        print('--------------------------')
        print('打印菜单栏')
        print('--------------------------')

<2>无参数,有返回值的函数

此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数

    # 获取温度
    def getTemperature():

        #这里是获取温度的一些处理过程

        #为了简单起见,先模拟返回一个数据
        return 24

    temperature = getTemperature()
    print('当前的温度为:%d'%temperature)

结果:

    当前的温度为: 24

<3>有参数,无返回值的函数

此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数

<4>有参数,有返回值的函数

此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数

    # 计算1~num的累加和
def sum1to100(a):
    if a==1: #出栈条件一定不能忘
        return 1
    else:
        a=a
        return a+sum1to100(a-1)

print('1~100的累积和为',sum1to100(100))

结果:

    1~100的累积和为: 5050

<5>小结

函数根据有没有参数,有没有返回值可以相互组合
定义函数时,是根据实际的功能需求来设计的,所以不同开发人员编写的函数类型各不相同

函数的嵌套调用

    def testB():
        print('---- testB start----')
        print('这里是testB函数执行的代码...(省略)...')
        print('---- testB end----')


    def testA():

        print('---- testA start----')

        testB()

        print('---- testA end----')

    testA()

结果:

    ---- testA start----
    ---- testB start----
    这里是testB函数执行的代码...(省略)...
    ---- testB end----
    ---- testA end----

小结:

  • 一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用 Python3-函数初解03
  • 如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次 函数A执行的位置

函数的简单应用:打印图形和数学计算

目标

  • 感受函数的嵌套调用
  • 感受程序设计的思路,复杂问题分解为简单问题

思考&实现1

  1. 写一个函数打印一条横线
  2. 打印自定义行数的横线

参考代码1

# 打印一条横线
def printLine():
    print('-'*10)
    
printLine()
—————华丽的分割线—————
# 打印自定义数量条横线
def printLines(num):
    for i in range(num):
        print('=' * 10)

printNumLine(3)

思考&实现2

  1. 写一个函数求三个数的和
  2. 写一个函数求三个数的平均值

参考代码2

# 求3个数的和
def sum3num(a,b,c):
    return a+b+c
print(sum3num(1,2,3)) 的后面可以是数值,也可是一个表达式
—————华丽的分割线—————
# 完成对3个数求平均值
def ave3num(a,b,c):
    print((a+b+c)/3)
    return int((a+b+c)/3) #int位置按照需求选择数据类型
print(ave3num(1,2,3))

LEGB原则(很重要)

LEGB是由4个英文单词缩写而来:Local-Enclosed-Global-Built in
Local #函数或类名的内部
Enclosed #嵌套函数,(一个函数包裹另外一个函数,闭包)
Global #指模块中的全局变量
Built in #Python为自己保留的特殊名称

如果在某个name映射在局部(local)命名空间中没有找到,接下来就会在闭包作用域中(Enclosed)中寻找,如果闭包作用域没有找到,就会在全局命名(Global)空间寻找,最后会在内建(Built in)命名空间寻找,如果一个名称在所有的命名空间都没有找到,就会报Nameerro错误


以下为LEGB寻找规则示例:

# LEGB
a=1
b=2
c=3
d=4
def waibu():
    a=5
    b=6
    def neibu():
        c=6
        print(a)#enclose  5
        print(b)#enclose  6
        print(c)#local    6
        print(d)#gloabl   4
        print(max)#built-in
    neibu()#函数内部调用
waibu()

函数使用注意事项

1. 自定义函数

<1>无参数、无返回值

    def 函数名():
        语句

<2>无参数、有返回值

    def 函数名():
        语句
        return 需要返回的数值

注意:

  • 一个函数到底有没有返回值,就看有没有return,因为只有return才可以返回数据
  • 在开发中往往根据需求来设计函数需不需要返回值
  • 函数中,可以有多个return语句,但是只要执行到一个return语句,那么就意味着这个函数的调用完成

<3>有参数、无返回值

    def 函数名(形参列表):
        语句

注意:

  • 在调用函数时,如果需要把一些数据一起传递过去,被调用函数就需要用参数来接收
  • 参数列表中变量的个数根据实际传递的数据的多少来确定

<4>有参数、有返回值

    def 函数名(形参列表):
        语句
        return 需要返回的数值

<5>函数名不能重复

Python3-函数初解03

2. 调用函数

<1>调用的方式为:

    函数名([实参列表])

<2>调用时,到底写不写 实参

  • 如果调用的函数 在定义时有形参,那么在调用的时候就应该传递参数

<3>调用时,实参的个数和先后顺序应该和定义函数中要求的一致

<4>如果调用的函数有返回值,那么就可以用一个变量来进行保存这个值

3. 作用域

<1>在一个函数中定义的变量,只能在本函数中用(局部变量)

Python3-函数初解03

<2>在函数外定义的变量,可以在所有的函数中使用(全局变量)

缺省参数*args **kwargs

调用函数时,缺省参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:

def printinfo( name, age = 35 ):
   # 打印任何传入的字符串
   print "Name: ", name
   print "Age ", age

# 调用printinfo函数
printinfo(name="miki" )
printinfo( age=9,name="miki" )

以上实例输出结果:

Name:  miki
Age  35
Name:  miki
Age  9

注意:带有默认值的参数一定要位于参数列表的最后面,否则程序报异常。

>>> def printinfo(name, age=35, sex):
...     print name
...
  File "<stdin>", line 1
SyntaxError: non-default argument follows default argument

2.不定长参数

2.不定长参数

有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。

基本语法如下:

    def functionname([formal_args,] *args, **kwargs):
       "函数_文档字符串"
       function_suite
       return [expression]

加了星号(*)的变量args会存放所有未命名的变量参数,args为元组;而加**的变量kwargs会存放命名参数,即形如key=value的参数, kwargs为字典。

>>> def fun(a, b, *args, **kwargs):
...     """可变参数演示示例"""
...     print "a =", a
...     print "b =", b
...     print "args =", args
...     print "kwargs: "
...     for key, value in kwargs.items():
...         print key, "=", value
...
>>> fun(1, 2, 3, 4, 5, m=6, n=7, p=8)  # 注意传递的参数对应
a = 1
b = 2
args = (3, 4, 5)
kwargs:
p = 8
m = 6
n = 7
>>>
>>>
>>>
>>> c = (3, 4, 5)
>>> d = {"m":6, "n":7, "p":8}
>>> fun(1, 2, *c, **d)    # 注意元组与字典的传参方式
a = 1
b = 2
args = (3, 4, 5)
kwargs:
p = 8
m = 6
n = 7
>>>
>>>
>>>
>>> fun(1, 2, c, d) # 注意不加星号与上面的区别
a = 1
b = 2
args = ((3, 4, 5), {'p': 8, 'm': 6, 'n': 7})
kwargs:
>>>
>>>

递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
简单来说,就是一个函数调用了他本身。

举个例子,我们来计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示,可以看出:

fact(n) = n! = 1 x 2 x 3 x … x (n-1) x n = (n-1)! x n = fact(n-1) x n

所以,fact(n)可以表示为n x fact(n-1),只有n=1时需要特殊处理。

于是,fact(n)用递归的方式写出来就是:

def fact(n):
    if n==1:
        return 1
    return n * fact(n - 1)

上面就是一个递归函数。可以试试:

>>> fact(1)
1
>>> fact(5)
120
>>> fact(100)
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

如果我们计算fact(5),可以根据函数定义看到计算过程如下:

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。

匿名函数

匿名函数

用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。

lambda函数的语法只包含一个语句,如下:

    lambda [arg1 [,arg2,.....argn]]:expression

如下实例:

    sum = lambda arg1, arg2: arg1 + arg2

    #调用sum函数
    print "Value of total : ", sum( 10, 20 )
    print "Value of total : ", sum( 20, 20 )

以上实例输出结果:

    Value of total :  30
    Value of total :  40

Lambda函数能接收任何数量的参数但只能返回一个表达式的值

匿名函数不能直接调用print,因为lambda需要一个表达式

应用场合

函数作为参数传递

  1. 自己定义函数
 def fun(a, b, opt):
    print "a =", a
    print "b =", b
     print "result =", opt(a, b)

fun(1, 2, lambda x,y:x+y)
   a = 1
   b = 2
   result = 3
  1. 作为内置函数的参数

示例

stus = [
    {"name":"zhangsan", "age":18},
    {"name":"lisi", "age":19},
    {"name":"wangwu", "age":17}
]

按name排序:

>>> stus.sort(key = lambda x:x['name'])
>>> stus
[{'age': 19, 'name': 'lisi'}, {'age': 17, 'name': 'wangwu'}, {'age': 18, 'name': 'zhangsan'}]

按age排序:

>>> stus.sort(key = lambda x:x['age'])
>>> stus
[{'age': 17, 'name': 'wangwu'}, {'age': 18, 'name': 'zhangsan'}, {'age': 19, 'name': 'lisi'}]

相关文章: