Python入门学习(七)

本文深入探讨了Python中的函数,包括函数的定义、调用、返回值、递归、参数使用等核心概念。通过实例展示了如何定义函数、如何处理函数参数、如何返回函数结果以及如何使用默认参数、可变参数和关键字参数。此外,还讨论了递归函数的工作原理和注意事项。最后,强调了函数在简化代码和提高代码复用性方面的重要性。
摘要由CSDN通过智能技术生成

目录

什么是函数

Python调用函数

Python定义函数

Python函数返回值

Python递归函数

Python函数参数

Python函数使用默认参数

Python函数使用可变参数

Python函数使用可变关键字参数


什么是函数

对于什么是函数,其实在前面的学习过程当中,已经多次接触到函数了,比如在set里面,使用remove()函数进行元素的删除,使用add()函数添加元素,使用update()函数批量添加元素,但是至今为止,我们都没有对函数有个充分的认识。本章,我们将具体学习函数。

接下来举个例子:

想必大家都知道圆的面积计算公式为:

S = πr²

当我们知道半径r的值时,就可以通过公式计算出面积,假设我们需要计算3个不同大小的圆的面积:

r1 = 12.34
r2 = 9.08
r3 = 73.1
s1 = 3.14 * r1 * r1
s2 = 3.14 * r2 * r2
s3 = 3.14 * r3 * r3

可以看到,在上述代码中,出现了几乎完全重复的代码,每次计算圆的面积的时候我们都是通过3.14*x*x(其中x是圆的半径)的方式计算出来的,这样写不仅非常麻烦,而且,当我们需要提高圆周率的精度时,把3.14改成3.14159265359的时候,我们需要修改涉及到的三行代码。

因此,我们可以使用函数,把重复的逻辑代码封装起来,这样子,我们就不需要每次计算的时候,都写3.14*x*x这样的代码了;当我们使用函数的时候,我们只需要定义一次,就可以多次使用。

我们把封装重复逻辑代码的过程就做抽象,抽象是数学中非常常见的概念。虽然博主数学学习不太好,但是该科普还要科普,哈哈哈。。。。

举例:以下网上摘抄的,我也不太会。。。。。out了out了!!


比如:计算数列的和,比如:1 + 2 + 3 + ... + 100,写起来十分不方便,于是数学家发明了求和符号∑,可以把1 + 2 + 3 + ... + 100记作:

这种抽象记法非常强大,因为我们看到∑就可以理解成求和,而不是还原成低级的加法运算。
而且,这种抽象记法是可扩展的,比如:

还原成加法运算就变成了:

(1 x 1 + 1) + (2 x 2 + 1) + (3 x 3 + 1) + ... + (100 x 100 + 1)

可见,借助抽象,我们才能不关心底层的具体计算过程,而直接在更高的层次上思考问题。这里我又发现新大陆了,学一下,记一下。。。。。
写计算机程序也是一样,函数就是最基本的一种代码抽象的方式。
Python不但能非常灵活地定义函数,而且本身内置了很多有用的函数,可以直接调用。

Python调用函数

Python内置了很多有用的函数,我们可以直接调用。比如前面求list的长度len()函数等等,都是Python内置的函数,我们经常会使用到它们。

在这个文档里面,列举了Python内置的大部分函数,有兴趣可以参考看看。Python内置函数

要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数 abs(),它接收一个参数。
对于abs()函数,abs就是函数的名称,括号()内,就是函数的参数,当函数没有参数时,默认就是一个空括号。abs接收一个参数,这个参数就是需要求绝对值的数,这个参数可以是整数,也可以是浮点数

abs(-100) # ==> 100
abs(20) # ==> 20
abs(-3.14159) # ==> 3.14159

需要注意的是,传递的参数数量一定要和函数要求的一致,不然将会引起错误,比如,如果在abs()函数中传入两个参数

abs(1, 2)
# 报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)

在错误提示中,清晰的说明了abs()函数只接收一个参数,但是却传递了两个参数,所以引起了错误。
其次,如果传入的参数数量是对的,但是参数的类型不能被函数所接受,也会引起错误,比如:求绝对值的函数abs(),只有数字才拥有绝对值,如果传递一个字符串进去,将会引起错误。

abs('3.1415926')
# 报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bad operand type for abs(): 'str'

这里错误提示说,str类型是错误的参数类型。
除了abs()函数,还有很多常见的函数,比如cmp()函数,可以比较两个数的大小,这个时候,cmp()函数就接收两个参数。
对于cmp(x, y),如果x < y 返回 -1,如果x == y 函数返回0,如果x > y函数返回1。

cmp(1, 2) # ==> -1
cmp(2, 1) # ==> 1
cmp(3, 3) # ==> 0

还有基础数据类型的转换函数,int()函数可以将合法的其它类型数据转换为整数,str()函数可以将其它类型的数据转换为字符串。

int('123') # ==> 123
int(12.34) # ==> 12

str(123) # ==> '123'
str(1.23) # ==> '1.23'

以上举例的内置函数,大家可以动手试一下,还有很多文档,在这里在重复提示一下,可以去官方文档   Python内置函数   中学习,在这里就不一一介绍学习了。

Python定义函数

除了使用Python内置的函数以外,在编程过程中,我们也会定义自己需要的函数。

在Python中,定义一个函数要使用def语句,依次写出函数名、括号()、括号中的参数和冒号;

然后,在缩进块中编写函数体,函数的返回值用 return 语句返回。

举例:定义一个求绝对值的函数my_abs函数为例:

def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

请注意,return表示返回的意思,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

Python函数返回值

我们在函数里面使用return返回了计算的结果,在外部调用这个函数的时候,就可以接收到结果。

有时候函数是没有返回结果的,这个时候从函数获取到的是一个空值None。

def list_sum(l):
    result = 0
    for num in l;
        result = result + num
    print('result is {}'.format(result))
    return

l = [1,3,5,7,9,11]
result = list_sum(l) # 调用定义的sum_list函数并获得return返回的结果

# 获得return返回的结果
print(result) # ==> None

在print(result)中,我们得到None的结果,只是合理的,因为在函数内部,我们把结果打印出来了,但是没有把结果返回。

除了返回None,一个值以外,函数也可以返回多个值,在函数中,如果需要返回多个值,多个值之间使用逗号分隔即可,但是需要注意顺序。

比如,定义一个函数data_of_square,接收边长一个参数,同时返回正方形的周长和面积。

def data_of_square(side):
    C = 4 * side
    S = side * side
    return C,S

C,S = data_of_square(16)
print('周长 = {}'.format(C)) # ==> 周长 = 64
print('面积 = {}'.format(S)) # ==> 面积 = 256

也可以使用一个值存储函数返回的多值结果。

result = data_of_square(16)

print(result) # ==>(64,256)

注意打印的result,其实它是tuple类型,如果我们需要取出结果中的周长或者面积,使用对应位置的下标就可以获得对应的结果。

result = data_of_square(16)
C = result[0]
S = result[1]
print('周长 = {}'.format(C)) # ==> 周长 = 64
print('面积 = {}'.format(S)) # ==> 面积 = 256

Python递归函数

在函数内部,还可以调用其他函数,比如实现函数data_of_square的时候,它接收边长一个参数,同时返回正方形的周长和面积,而求周长和求面积是完全独立的逻辑,可以定义成两个新的函数,然后在data_of_square函数中再调用这两个函数,得到结果并返回。

def square_area(side):
    return side * side

def square_perimeter(side):
    return 4 * side

def data_of_square(side):
    C = square_perimeter(side)
    S = square_area(side)
    return C, S

在函数内部调用其他函数,是非常常见的,通过合理拆分逻辑,可以降低程序的复杂度。如果在一个函数内部调用其自身,这个函数就是递归函数。
举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可以看出:

fact(n) = n! = 1 * 2 * 3 * 4 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n

所以,fact(n)可以表示为n*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(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

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

使用递归函数需要注意防止栈溢出。计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。可以试试计算fact(10000).

Traceback (most recent call last):
RecursionError: maximum recursion depth exceeded in comparison

Python函数参数

函数参数是需要传递给函数内部的数据,在前面,我们已经简单接触了函数的参数,现在我们正式来认识它。
函数参数可以是任意的数据类型,只要函数内部逻辑可以处理即可。

def print_param(param):
    print(param)

对于print_param函数,由于函数的逻辑是直接打印参数,并没有做任何别的逻辑,所以这个函数可以接受整数、浮点数、list、tuple、dict等等的数据类型。

print_param(1)
print_param('3.1415926')
print_param([1, 2, 3, 4, 5])

但是,有时候由于函数的实现关系,需要特定的参数,就比如前面实现的求绝对值的函数my_abs(),如果传递一个字符串,就会引起错误。

def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

my_abs('str param')
# 报错
TypeError: '>=' not supported between instances of 'str' and 'int'

为了保证函数的正常运行,有时候需要对函数入参进行类型的校验,Python提供isinstance()函数,可以判断参数类型,它接收两个参数,第一个是需要判断的参数,第二个是类型。

isinstance(100, int) # ==> True
isinstance(100.0, int) # ==> False
isinstance('3.1415926', str) # ==> True

有了isinstance,就可以优化my_abs函数,不在里面运行出错了。

def my_abs(x):
    if not isinstance(x, int) or not isinstance(x, float):
        print('param type error.')
        return None
    if x >= 0:
        return x
    else:
        return -x

Python函数使用默认参数

定义函数的时候,还可以有默认参数,默认参数的意思是当这个参数没有传递的时候,参数就使用定义时的默认值。
例如Python自带的 int() 函数,其实就有两个参数,我们既可以传一个参数,又可以传两个参数:

int('123') # ==> 123
int('123', 8) # ==> 83

int()函数的第二个参数是转换进制base,如果不传,默认是十进制 (base=10),如果传了,就用传入的参数。
可见,函数的默认参数的作用是简化调用,你只需要把必须的参数传进去。但是在需要的时候,又可以传入额外的参数来覆盖默认参数值。
我们来定义一个计算 x 的N次方的函数:

def power(x, n):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

假设计算平方的次数最多,我们就可以把 n 的默认值设定为 2:

def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

这样一来,计算平方就不需要传入两个参数了:

power(5) # ==> 25

另外需要注意的是,由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面,否则将会出现错误。

# 错误的定义
def power(n=2, x):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

Python函数使用可变参数

除了默认参数,Python函数还接收一种参数叫做可变参数,可变参数即任意个参数的意思,可变参数通常使用*args来表示。

def func(*args):
    print('args length = {}, args = {}'.format(len(args), args))
func('a') # ==> args length = 1, args = ('a',)
func('a', 'b') # ==> args length = 2, args = ('a', 'b')
func('a', 'b', 'c') # ==> args length = 3, args = ('a', 'b', 'c')

注意,在使用上,Python会把可变参数定义为一个tuple,所以在函数内部,把可变参数当作tuple来使用就可以了,比如可以通过位置下标取出对应的元素等。
定义可变参数的目的也是为了简化调用。假设我们要计算任意个数的平均值,就可以定义一个可变参数:

def average(*args):
    sum = 0
    for item in args:
        sum += item
    avg = sum / len(args)
    return avg

这样,在调用的时候,我们就可以这样写:

average(1, 2) # ==> 1.5
average(1, 2, 2, 3, 4) # ==> 2.4
average()
# 报错
Traceback (most recent call last):
ZeroDivisionError: division by zero

在执行average()的时候,却报错了,这是因为在使用可变参数时,没有考虑周全导致的,因为可变参数的长度可能是0,当长度为0的时候,就会出现除0错误。因此需要添加保护的逻辑。

Python函数使用可变关键字参数

可变参数在使用上确实方便,函数会把可变参数当作tuple去处理,tuple在使用上有一定的局限性,比如有时候想找到特定位置的参数,只能通过下标的方式去寻找,如果顺序发生变化得时候,下标就会失效,函数逻辑就得重新修改实现。

Python函数提供可变关键字参数,对于可变关键字参数,可以通过关键字的名字key找到对应的参数值,想想这和我们之前学习过的什么类似?是的没错,dict,Python会把可变关键字参数当作dict去处理;对于可变关键字参数,一般使用**kwargs来表示。

例如,想要打印一个同学的信息,可以这样处理:

def info(**kwargs):
    print('name: {}, gender: {}, age: {}'.format(kwargs.get('name'), kwargs.get('gender'), kwargs.get('age')))

info(name = 'Alice', gender = 'girl', age = 16)

对于一个拥有必需参数,默认参数,可变参数,可变关键字参数的函数,定义顺序是这样的:

def func(param1, param2, param3 = None, *args, **kwargs):
    print(param1)
    print(param2)
    print(param3)
    print(args)
    print(kwargs)

func(100, 200, 300, 400, 500, name = 'Alice', score = 100)
# ==> 100
# ==> 200
# ==> 300
# ==> (400, 500)
# ==> {'name': 'Alice', 'score': 100}

当然,这么多类型的参数,很容易导致出错,在实际使用上,不建议定义这么多的参数。

到这篇文章的结尾,我们就已经了解并学习了Python基础的东西,回想一下,有数据类型以及对应数据类型的方法、变量常量、控制流程语句(if、else、for、while、break、continue、嵌套循环)、List容器、Tuple元组、Dict容器、Set容器、函数。

如果跟着我的文章学习的朋友们,相信已经掌握也初步了解了Python是什么以及如何使用。大家在学习,博主也在学习。 到这里,Python的基础入门学习就到此结束。接下来我会持续的更新Python进阶文章以及疑难问题文章,喜欢学习的朋友们,帮忙转发或者分享一下,给博主点点赞,关注博主不迷路,博主带你学Python!!!

作者:筱白爱学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

筱白爱学习

你的鼓励将是我写作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值