Python3(3) Python 函数
本系列主要学习Python的基本使用和语法知识,后续可能会围绕着AI学习展开。
Python3 (1) Python语言的简介
Python3 (2) Python语法基础
Python3 (3) Python函数
Python3 (4) Python高级特性
Python3 (5) Python 函数式编程
Python3 (6) Python 模块
Python3 (7) Python 面向对象编程
Python3 (8) Python 面向对象高级编程
Python3 (9) Python 错误、调试和测试
Python3 (10) Python IO编程
Python3 (11) Python 进程和线程
Python3 (12) Python 常用内建模块
Python3 (14) Python 网络编程
函数部分主要有函数的调用、函数的定义、函数的参数(参数部分比较难,相对于java增加了好多新的概念,参数可以各种组合)、函数的递归。
函数的调用
为什么先强调函数的调用呢,因为Python有好多内置函数,可以为我们解决各种问题。举几个例子:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
//abs() 获取绝对值,我们可以直接调用
x = abs(100)
//abs 赋值给a, 相当于a指向了abs函数,这也体现python赋值的强大之处
a = abs
y = a(-20)
// int、str ...数据转化函数,可以对数据进行转换,前提是可以相互转换的数据
z = int('123')
s = str(True)
print(x, y,z,s)
//数学类函数
print('max(1, 2, 3) =', max(1, 2, 3))
print('min(1, 2, 3) =', min(1, 2, 3))
print('sum([1, 2, 3]) =', sum([1, 2, 3]))
输出结果:
100 20 123 True
max(1, 2, 3) = 3
min(1, 2, 3) = 1
sum([1, 2, 3]) = 6
python内置函数的调用中,如果参数不匹配会出现 TypeError 错误:
Traceback (most recent call last):
File "F:/python/HelloWord/call_func.py", line 4, in <module>
x = a(100,200)
TypeError: abs() takes exactly one argument (2 given)
函数的定义
在Python中,定义一个函数要使用def
语句,依次写出函数名
、括号
、括号中的参数
和 冒号:
,然后,在缩进块中编写 函数体
,函数的返回值用return
语句返回,注意python中没有大括号。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import math
//自定义一个取绝对值的函数
def my_abs(x):
//自定义类型异常捕获机制,关键字 isinstance
if not isinstance(x, (int, float)):
raise TypeError('bad operand type')
if x >= 0:
return x
else:
return -x
n = my_abs(-20)
print(n)
# TypeError: bad operand type:
# my_abs('123')
输出结果:
20
- 在函数中,一旦执行到return时,函数就执行完毕,并将结果返回,如果没有return 函数执行完成后默认 return None , 函数中 return None 可以简写成 return。
- 自定义的函数,参数类型不会像内置函数抛出 TypeError 异常,可以自定义TypeError 异常,来保证函数的严谨性。
空函数
def no_fun():
pass
print(no_fun())
输出结果:
None
空函数的定义: 可以通过关键字 pass 来做函数体 意思很明显,直接通过
函数返回值
python 中支持多参数返回,实质上是返回一个tuple!
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)
// 单参数接收
n = move(100, 100, 60, math.pi / 6)
print(x, y,n)
输出结果:
151.96152422706632 70.0 (151.96152422706632, 70.0)
函数参数
函数的参数定义非常的灵活,支持必选参数、位置参数、默认参数、可变参数、关键字参数等、并且这些参数可以组合使用。
必选参数
def myPower(x):
return x * x
print("myPower (2)= ",myPower(2))
输出结果:
myPower(2) = 4
参数x
为必选参数,否则TypeError: myPower() missing 1 required positional argument: 'x'
。
位置参数
def myPower(x,n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
print("myPower = ",myPower(2,5))
输出结果:
myPower = 32
myPower(x, n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。
默认参数
默认参数相当于java的重载,一个函数传入不同个数的参数,没有传的参数,会有默认参数来代替
def myPower(x,n = 2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
print("myPower = ",myPower(2))
输出结果:
myPower = 4
- 注意定义函数时,必选参数在前,默认参数在后
- 变化大的的默认参数在前,变化小的默认参数在后,符合使用规则
- 默认参数代替了java 中因为参数个数引起的重载,减少了函数的定义
- 定义默认参数要牢记一点:默认参数必须指向不变对象!
比如定义一个函数,传入一个默认参数list:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def my_list(L=[]):
L.append('END')
return L
N = my_list([1,2,3,4,5])
print(N)
# 第一次调用参数
K = my_list()
print(K)
# 第二次调用参数
R = my_list()
print(R)
print('--------------------')
def my_list1(L = None):
if L is None:
L = []
L.append('END')
return L
# 第一次调用参数
K1 = my_list1()
print(K1)
# 第二次调用参数
R1 = my_list1()
print(R1)
输出结果:
[1, 2, 3, 4, 5, 'END']
['END']
['END', 'END']
--------------------
['END']
['END']
以上就可以看到,如果定义函数时,参数为list: L = [ ]
在多次使用默认参数时 就会出现 重复添加的情况,原因也很简单,我们定义了一个默认参数的值就会创建一个数据对象,函数执行完返回的值会存储在数据对象中,所以再次调用会呈现累加的情况,我们可以给参数定义一个None L = None
特殊的一个空对象(这个对象是不变的),这样就不会造成累加的情况了。
可变参数
可变参数指传入的参数是可变的,不同于默认参数,可变参数可以理解为传入一个list或tuple,具体的使用有两种方式
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 第一种
def my_calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#传入一个list
m = [1,2,3,4,5,6]
print(my_calc(m))
# 第二种
def my_calc1(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
# 直接将参数用逗号隔开,传进去
print(my_calc1(1,3,5,7,9))
# 接收一个list的写法
n = [2,4,6,8,10]
print(my_calc1(*n))
输出结果:
91
165
220
可以看出可变参数的写法有两种,一种是直接传入一个list,第二种是用*numbers
直接将参数传入,list 传入时用 *n
传入。
关键字参数
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。与java中传入一个map 集合类似,如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
return
# 通过name = value 形式传入
person('张三', 35, weight=55,height = 175)
##直接传入一个dict
others = {'weight': 65,'height': 185}
person ('李四',45,**others)
输出结果:
name: 张三 age: 35 other: {'weight': 55, 'height': 175}
name: 李四 age: 45 other: {'weight': 65, 'height': 185}
最后**others
传入的是others 的复制版本,others 的变化不会引起函数的变化。
命名关键字参数
命名关键字是与位置参数比较的,位置可以灵活,写法在位置参数前加一个可变参数*args
或者*
,命名关键字参数也可以有默认参数,如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def person(name, age, *, weight,heigth):
print('name=',name, 'age=',age,'weight=', weight,'heigth=', heigth)
person('张三', 24, weight=55, heigth=175)
def person(name, age, *args, weight,heigth):
print('name=',name, 'age=',age,'weight=', weight,'heigth=', heigth,args)
person('张三', 24,weight=55, heigth=175,*(1,2,3,4))
输出结果:
name= 张三 age= 24 weight= 55 heigth= 175
name= 张三 age= 24 weight= 55 heigth= 175 (1, 2, 3)
组合参数
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是他们是有顺序的跟运算符的级别一样。顺序如下:
- 必选参数
- 默认参数
- 可变参数
- 命名关键字参数
- 关键字参数
要注意的是不要同时使用太多的组合,否则函数接口的可理解性很差。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
args = (1, 2, 3, 4,5)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)
输出结果:
a = 1 b = 2 c = 3 args = (4, 5) kw = {'d': 99, 'x': '#'}
不可思议吧,看到这个结果,对照组合参数的级别不难理解。参数到这就介绍完了,只有多实践才能深入理解。
递归函数
递归函数在各种语言中都有,python的递归有啥特点呢?廖雪峰大神专门一节讲解,我们就来看看吧。
递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
递归函数的缺点是递归太深的话,因为python没有尾递归优化会导致栈溢出。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#n! n的阶乘
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
print(fact(10))
print(fact(20))
输出结果:
3628800
2432902008176640000
参考
https://www.python.org
http://www.runoob.com/python3/python3-tutorial.html
https://www.liaoxuefeng.com