Python中的函数

总结摘要
本文粗略的探讨python中的函数,包括调用函数,定义函数,参数,返回值等,为初学者提供一个简单的入门

cover

调用函数

如果我们要调用一个函数,我们要知道函数的参数值,比如 hex() 就是转化为 16进制的字符

1
2
>>> hex(1000)
'0x3e8'

你也可以在 help(hex) 查看它的更多用法。python的函数有很多,再比如使用 abs() 函数可以求出一个数的绝对值。

1
2
3
4
>>> abs(20)
20
>>> abs(-100)
100

不过如果你输入:

1
2
3
4
>>> abs(1, 2)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: abs() takes exactly one argument (2 given)

python会明确的告诉只能使用1个参数,你可以使用 help(abs) 查看其明确用法

数据类型的转换

Python的常用函数也包括数据类型转换函数,比如使用 int() 可以将数据转换为整数,以下是几个常用的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> int(10.1)
10
>>> float('12.1')
12.1
>>> str(20)
'20'
>>> bool(1)
True
>>> bool(0)
False

我们可以完全把一个函数赋给一个变量,那么它将是这个函数的别称:

1
2
a = abs
print(a(-1))

定义函数

在python中,定义一个函数要使用 def 语句,依次写出函数名,括号,括号中的参数和冒号,函数的返回用 retrun 我们来定义一个 my_abs 为例:

1
2
3
4
5
6
7
def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

print(my_abs(-99))

如果你已经将函数保存为 myabs.py,可以在文件中添加 form myabs import my_abs 来导入 my_abs() 函数,注意这里的 myabs 是不用添加 .py 后缀的。

空函数

如果你想定义一个函数,但是什么也不做,可以使用 pass 语句, 如下:

1
2
def nop():
	pass

pass语句可以充当占位符的作用,如果你没有想好函数要写什么,可以用它先放着

pass也可以用在其他语法里面:

1
2
if age >= 18:
	pass

缺少 pass 就会报错

参数检查

调用参数时,如果某个参数不对就会抛出 TypeError

1
2
3
4
>>> my_abs(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: my_abs() takes 1 positional argument but 2 were given

但是如果是参数类型不一样,python就无法帮助我们抛出

所以我们来修改函数:

1
2
3
4
5
6
7
def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x

我们可以使用 isinstance() 来检查参数类型

添加了参数检查之后:

1
2
3
4
5
>>> my_abs('A')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in my_abs
TypeError: bad operand type

返回多个值

如果我们要求 $$ a^{2} + bx + c $$,我们知道,$$ x = \frac{-b \pm \sqrt{b^{2} - 4ac}}{2a} $$ , 所以我们可以定义如下函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import math  #导入math函数,使用里面的math.sqrt求平方根
  
def quadratic(a, b, c):  
    o = b**2 - 4*a*c  
    if o < 0:  
        raise TypeError('根号要大于0')  
    else:  
        n1 = (-b + math.sqrt(o))/(2*a)  
        n2 = (-b - math.sqrt(o))/(2*a)  
        return n1, n2

我们来做一个测试看看是不是对的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 测试:  
print('quadratic(2, 3, 1) =', quadratic(2, 3, 1))  
print('quadratic(1, 3, -4) =', quadratic(1, 3, -4))  
  
if quadratic(2, 3, 1) != (-0.5, -1.0):  
    print('测试失败')  
elif quadratic(1, 3, -4) != (1.0, -4.0):  
    print('测试失败')  
else:  
    print('测试成功')

函数的参数

位置参数

如果我们要计算 x的平方,例如:

1
2
def power(x):
	return x * x

但是如果我们要计算x的3次方,4次呢?一直用 return x * x * x吗?在这里我们可以通过修改,如下:

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

这样我们只需要输入 power(4,5) 前者为常数,后者为幂。

默认参数

但是这样有一个问题,我只想求平方怎么办,我能不能直接使用前面的函数。如果我们直接使用肯定会报错,所以我们可以修改一下:

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

当我们输入 power(3)时,会默认设置我们的 n = 2,如果要求3次方可以 power(3,3) {% note info simple %} 默认参数必须为不可变的 {% endnote %}

可变参数

在python函数中,参数也可以是可变的,比如1个,2个,3个,也可以是0个。比如要计算 $$ a^{2} + b^{2} + c^{2} + …. $$的值,我们可以这样:

1
2
3
4
5
6
def c(num):
	sum = 0
	for n in num:
		sum = sum + n * n
	return sum
	

但是我们在调用的时候想要把a b c组装为一个list或tuple。如 c([1, 2, 3]),所以我们可以修改为 *num,比如:

1
2
3
4
5
def c(*num):
	sum = 0
	for n in num:
		sum = sum + n * n
	return sum

然后就可以简化了 c(1,2,3)

定义可变参数比定义一个list和tuple更容易,只需要在参数前面添加 *,对于已经存在的list,我们可以这样写:

1
2
num = [1,2,3,4]
c(*num)

关键字参数

关键字参数与可变参数最直观的区别就是,关键字参数是自动组成一个dict,而可变参数是list或tuple。例如:

1
2
3
# 一个简单的注册函数
def reg(usr, psd, **info):
	print('用户名:', usr, '密码:', psd, '其他信息:', info)

我们除了可以设置必填信息 usrpsd 外,还可以收集其他的信息,比如 email

1
2
reg('bob', 123456, email='[email protected]')
>>> 用户名: bob 密码: 123456 其他信息: {'email': '[email protected]'}

对于已经存在的关键字也可以像可变参数一样

1
2
3
info = {'email':'[email protected]', 'phone':123455677}  
reg('bob', 123456, **info)
>>> 用户名: bob 密码: 123456 其他信息: {'email': '[email protected]', 'phone': 123455677}

命名关键字参数

对于关键字的调用者可以传入很多的关键字参数,但是如何检查这些呢?我们可以通过函数内部的 info 进行检查,例如我们只想要 phoneemail

1
2
def reg(usr, psd, *, email, phone):
	print(usr, pasd, email, phone)

和关键字参数**info不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。

如果函数中存在一个可变变量就不需要在添加 *

参数组合

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

递归函数

在函数内部可以调用其他函数,但是在函数内部调用自身,那么就是递归函数。

如果我们要计算阶乘:

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

比如计算 fact(5) 它的计算过程就是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
=> 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

这样的好处是使函数简单,但是也会导致栈溢出

参考资料 廖雪峰的Python教程 PDF 下载链接