(入门)函数

所有笔记内容参考廖雪峰官网,需要详细了解大家可以去这个网站,我这里主要做笔记方便自己复习

调用函数

Python中内置了许多函数,我们可以直接调用,我们直接从Python官网查看文档以了解函数:http://docs.python.org/3/library/functions.html#abs

例如求一个数的绝对值:abs(-20);注意:在调用函数的时候,如果传参个数有问题,或者传入的参数类型不能为函数所接受,那么会有TypeError的错误。这里可能会涉及到一个数据类型转换的问题

数据类型转换

例如:int('123')是将123字符串转换为整数,类似的还有float,str,bool

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:

a = abs   # 变量a指向abs函数
a(-1)     # 所以也可以通过a调用abs函数

定义函数

定义函数用到的关键字是def语句,例如:

def my_fun(x):
    if x >= 0:
        return x
    else:
        return -x
print(my_fun(9))
空函数

一个什么事也不做的函数,可以使用pass语句:

def name():
    pass

pass语句什么也不做,但是我们可以用pass作为占位符,比如写函数时候,当还没有想好怎么写的时候,我们可以先放一个pass,使代码能先运行起来,还可以放在其他的语句中:

if age >=18:
    pass
参数检查

在调用函数的时候,如果参数个数不正确,那么Python解释器会自动检查出来,并抛出TypeError的错误;

当传入了不恰当的参数类型,内置函数会检查出参数错误,但是如果我们自己定义的函数没有进行参数检查,不会报类似于内置函数的错误,所以我们需要对参数类型进行检查。数据类型的检查可以使用内置函数isinstance()实现:那么之前定义的my_fun函数可以这么定义

def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x

注意:如果在函数中没有return语句,那么函数会自动return none

返回多个值

比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的新的坐标:

import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny
x, y=move(100,100,60,math.pi/6)

这样的话可以获得x,y的值,但是其实函数返回的仍然是单一的值,我们可以使用一个变量来接收函数的返回值,最后会发现返回的会是一个tuple,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。

函数的参数

位置参数

在上面的函数中,my_abs(x)其中的x就是一个函数,my_abs(8)就是对函数的一个调用,我们也可以使用类似于上面的move(x,y,step,angle=0)的多个参数,我们可以看到,在函数的参数列表中有一个angle=0的部分。这就是我们所说的默认参数

默认参数

如果我们在一个函数中有默认函数,我们在调用这个函数的时候,在参数列表中可以省略默认参数的出现,例如对上面move函数的调用,我们可以使用这种语法:move(0,0,100);当然,如果我们想改变默认参数的值,我们还是可以使用move(0,0,100,1)这样的语法。

设置默认参数的注意点

  1. 必选参数在前,默认参数在后
  2. 当函数有多个参数时,变化大的参数放前面,变化小的参数放后面,变化小的参数可以作为默认参数

    么默认参数有什么用处呢? 用处就是可以降低调用函数的函数。

注意:默认参数一定指向不可变对象,否则会出现bug;例如:

def add_end(L=[]):
    L.append('END')
    return L

#第一次调用

print(add_end())   #将会返回['END']

#第二次调用

print(add_end())   #将会返回['END', 'END']

#第三次调用

print(add_end())   #将会返回['END', 'END', 'END']

可见,原因解释如下:

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

我们可以通过none这个对象来修改上面的代码

def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L

这样的话,无论调用多少次,我们返回的都是[‘END’];

为什么要设计strNone这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。

可变参数

可变参数就是参数的个数是可以变化的;可以是0到任意个
当我们不知道参数的个数的时候,我们可以考虑将参数作为一个list或者tuple传进来,这样,函数可以定义为:

def cal(numbers):
    sum=0
    for n in numbers:
        sum=sum+n*n
    return sum
#调用函数为下面代码
cal([1,2,3])
#或者
cal((1,2,3))

当我们采用可变参数的时候,函数的调用可以简化成以下:

cal(1,2,3)

所以,我们把函数的参数改为可变参数:

def cal(*numbers):
    sum=0
    for n in numbers:
        sum=sum+n*n
    return sum

可以看出,定义可变参数和定义一个list和tuple参数相比,仅仅在参数前面加了一个*号。在函数的内部,参数numbers接收到的是一个tuple,因此,函数的代码没有改变,但是,当我们在调用函数的时候,我们可以传入包括0的任意个参数
还有一种情况就是已经有一个list或者tuple,需要调用一个可变参数,我们同样可以在函数的参数列表中加上一个*号,例如:

numbers=[1,2,3]
cal(*numbers)
关键字参数

关键字参数允许你传入0个或者任意个参数,这些可变参数在参数调用时自动组装成一个tuple。而关键字参数允许你传入0个或者任意个含参数名的参数,这些关键字参数在函数内部自动组装成一个dict,例如:

def person(name,age,**kw):
        print('name:',name,'age:',age,kw)
person('wan',18)
person('wan',18,city='beijing')
person('wan',18,city='bejing',gender='man')
info={'city':'beijing','gender':'man'}
person('wan',18,**info)

输出为:

name: wan age: 18 {}
name: wan age: 18 {‘city’: ‘beijing’}
name: wan age: 18 {‘city’: ‘bejing’, ‘gender’: ‘man’}
name: wan age: 18 {‘city’: ‘bejing’, ‘gender’: ‘man’}

注意:后面的可变参数可以使用一个dict来存储,在调用的时候可以在参数前面加上**完成调用

命令关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数,至于到底传入了哪些,就需要在函数内部通过检查,例如,还是上面的person函数,我们希望检查是否有citygender参数

def person(name,age,**kw):
    if 'city' in kw:
        pass
    print('有一个city')
    if 'gender' in kw:
        pass
        print('有一个gender')
    print('name:',name,'age:',age,kw)
person('wan',18)
person('wan',18,city='beijing')
person('wan',18,city='bejing',gender='man')
info={'city':'beijing','gender':'man'}
person('wan',18,**info) 
print('wam',18,city='bejing',gender='man',job='student')

下面是输出:

有一个city
name: wan age: 18 {}
有一个city
name: wan age: 18 {‘city’: ‘beijing’}
有一个city
有一个gender
name: wan age: 18 {‘city’: ‘bejing’, ‘gender’: ‘man’}
有一个city
有一个gender
name: wan age: 18 {‘city’: ‘beijing’, ‘gender’: ‘man’}
name: wam age: 18 {‘city’: ‘bejing’, ‘gender’: ‘man’, ‘job’: ‘student’}

如果我们需要限制关键字的名字,就可以使用命名关键字参数,例如,如果只接受citygender作为关键字参数,那么函数定义如下:

def person(name, age, *, city, gender):
    print(name, age, city,gender)
#调用
person('wan',18,city='beijing',gender='man')

和关键字参数**kw不同,命令关键字参数需要一个分隔符**后面的参数被视为命名关键字参数
如果函数定义已经存在一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了,例如:

def person(name,age,*args,city,job)
    print(name,age,args,city,job)
#调用
person('wan',18,'beijing','china',city='loudi',job='stu')

对于上面的函数调用,如果是这个语句person('wan',18,'beijing','china');这时候由于缺少参数city和job,调用会报错。
注意:当函数定义中存在一个默认参数值的时候,这个默认参数在调用的时候可以省略,即命令关键字参数可以有缺省值

参数组合

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数可以组合使用。但是,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数

递归函数

一个函数在内部调用自身,这个函数便是递归函数,例如计算n!:

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

与java语言中相同,递归函数的优点是定义简单,逻辑清晰,理论上,所有的递归函数都可以写成循环的方式,但是循环的逻辑没有递归清晰。
使用递归函数需要注意防止栈的溢出。在计算机中,函数调用是通过栈这种数据结构来实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层帧。由于栈的大小不是无限的,所以递归调用的次数过多可能会导致溢出。
我觉得学了数据结构这门课,对这个地方的理解还是相对比较简单的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值