一、函数简介
函数也是一个对象
函数用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次调用。
# 定义一个函数
def fn():
print('这是我的第一个函数!!!')
print('哈哈哈')
print('嘿嘿嘿')
# print是函数对象 print()调用函数
print(fn)
# fn是函数对象 fn()调用函数
fn()
# 输出
<function fn at 0x00000280C2003E18>
这是我的第一个函数!!!
哈哈哈
嘿嘿嘿
二、函数的参数
1. 形参和实参
实际参数就是调用函数时候传给他的那个参数,而形式参数可以理解为函数内部定义用的参数。
2. 参数的类型
2.1 不可变类型
类似 C++ 的值传递,如整数、字符串、元组。
如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。
def change(a):
print(id(a)) # 指向的是同一个对象
a=10
print(id(a)) # 一个新对象
a=1
print(id(a))
change(a)
# 输出结果为:
4379369136
4379369136
4379369424
2.2 可变类型
类似 C++ 的引用传递,如列表、字典。
如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响。
# 可写函数说明
def changeme( mylist ):
"修改传入的列表"
mylist.append([1,2,3,4])
print ("函数内取值: ", mylist)
return
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)
# 传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果如下:
函数内取值: [10, 20, 30, [1, 2, 3, 4]]
函数外取值: [10, 20, 30, [1, 2, 3, 4]]
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
3. 参数的传递方式
以下是调用函数时可使用的参数传递方式:
3.1 默认参数
定义形参时,可以为形参指定默认值。调用函数时,如果没有传递参数,则会使用默认参数。默认参数必须放在最后面。
# 在定义函数的形参的时候,可以指定一个默认值
def fn(a,b,c = 20):
print('a =',a)
print('b =',b)
print('c =',c)
fn(1,2,3)
# 输出
a = 1
b = 2
c = 3
3.2 位置参数
参数须以正确的顺序传入函数,调用时的数量必须和声明时的一样。
# 定义一个函数 任意两个数的和
# 函数的参数
# 在定义函数的时候,可以在函数后面的括号中定义数量不等的形参
# 多个形参之间要用 ,隔开
# 简单来说你有几个形参就要赋值几个实参
def s(a,b):
print(a ,'+',b,'=',a+b)
s(8,6)
# 输出
8 + 6 = 14
3.3 关键字参数
关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
# 关键字传参
# 关键字传参可以不按照定义的顺序来传递,它是根据参数的名字来传递
# 可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print ("名字: ", name)
print ("年龄: ", age)
return
# 调用printinfo函数
printinfo( age=50, name="runoob" )
# 输出
名字: runoob
年龄: 50
3.4 不定长参数
加了星号 * 的形参会以元组(tuple)的形式导入位置参数;带*号的形参只能有一个,可以和其他参数配合使用。
加了两个星号**的形参会以字典的形式导入关键字参数;**形参只有⼀个,并且必须写在所有参数的后⾯。
def s(*a):
# 定义一个变量来保存结果
r = 0
# 遍历元祖,并将元祖中的数进行相加
for n in a:
r += n
print(r)
s(1,2,5)
# 输出
8
3.5 混合使用
混合使⽤位置参数和关键字参数的时候必须将位置参数写到关键字参数前⾯去。
def fn3(b,c,**a):
print('a =',a)
print('b =', b)
print('c =', c)
fn3(b=1,d=2,c=3,e=20,f=30)
# 输出
a = {'d': 2, 'e': 20, 'f': 30}
b = 1
c = 3
3.6 参数的解包
传递实参时,也可以在序列类型的参数前添加星号,这样它会⾃动的将序列中元素依次作为参数传递;
序列中的元素的个数必须和形参的个数⼀致。
# 参数的解包
def fn4(a,b,c):
print('a =',a)
print('b =',b)
print('c =',c)
t = (10,20,30)
fn4(*t)
d = {'a':1,'b':2,'c':3}
fn4(**d)
# 输出
a = 10
b = 20
c = 30
a = 1
b = 2
c = 3
三、函数的返回值
返回值就是函数执行以后返回的结果。
- return [表达式] 语句用于退出函数,选择性地向调用方返回一个表达式。
- 不带参数值的return语句返回None。
- return后面可以跟任意对象,返回值甚至可以是一个函数。
def s(*a):
# 定义一个变量来保存结果
r = 0
# 遍历元祖,并将元祖中的数进行相加
for n in a:
r += n
print(r)
s(1,2,5)
# 输出
8
可以直接使用函数的返回值 也可以通过一个变量来接收函数的返回值;
return后面可以跟任意的对象,甚至是一个函数。
def fn():
def fn2():
print('python')
return fn2
print(fn())
r = fn() # <function fn.<locals>.fn2 at 0x0000021F92F357B8>
print(r)
r()
# 输出
<function fn.<locals>.fn2 at 0x00000294137EA8C8>
<function fn.<locals>.fn2 at 0x00000294137EA8C8>
python
如果仅仅写一个return 或者没有写return 相当于 return None,return一旦执行,函数自动结束。
def fn3():
print('python')
return
print('abc')
r = fn3()
print(r)
# 输出
python
None
def fn4():
for i in range(5):
if i == 3:
# break
return # return可以用来结束函数
print(i)
print('循环执行完毕')
r = fn4()
print(r)
fn4()
# 输出
0
1
2
None
0
1
2
四、文档字符串
help()是Python中内置函数,通过help()函数可以查询Python中函数的用法;
在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明。
语法: help(函数对象)
# 通过help()函数可以查询其他函数的用法
# 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是对函数的说明。
def fn(a:int,b:str,c:bool)->int:
'''
这个函数的功能就是一个文档字符串在函数中的使用说明
参数
a,作用,类型,默认值...
b,作用,类型,默认值...
c,作用,类型,默认值...
返回值
'''
return 1
help(fn)
# 输出
Help on function fn in module __main__:
fn(a:int, b:str, c:bool) -> int
这个函数的功能就是一个文档字符串在函数中的使用说明
参数
a,作用,类型,默认值...
b,作用,类型,默认值...
c,作用,类型,默认值...
返回值
五、命名空间
命名空间实际上就是一个字典,是一个专门用来存储变量的字典。
- locals()用来获取当前作用域的命名空间
如果在全局作用域中调用locals(),则获取全局命名空间
如果在函数作用域中调用locals(),则获取函数命名空间
返回值是一个字典
六、函数作用域
作用域指的是变量生效的区域。
在Python中一共有两种作用域:
- 全局作用域
全局作用域在程序执行时创建,在程序执行结束时销毁;
所有函数以外的区域都是全局作用域;
在全局作用域中定义的变量,都是全局变量,全局变量可以在程序的任意位置进行访问。
a = 20
print('函数外部 a = ',a)
def fn3():
# 如果希望在函数内部修改全局变量,则需要使用一个关键字global,来声明变量
# a = 10
global a
a = 100
print('函数内部 a =',a)
fn3()
print('函数外部!!!! a = ',a)
# 输出
函数外部 a = 20
函数内部 a = 100
函数外部!!!! a = 100
- 函数作用域
函数作用域在函数调用时创建,在调用结束时销毁;
函数每调用一次就会产生一个新的函数作用域;
在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问。
b = 20
def fn():
a = 10 # a定义在了函数的内部,所以他的作用域就是函数的内部,函数外部是无法访问的
print('函数内部:','a =',a)
print('函数内部:', 'b =', b)
fn()
print('函数外部:','b =',b)
# print('函数外部:','a =',a) # NameError: name 'a' is not defined
# 输出
函数内部: a = 10
函数内部: b = 20
函数外部: b = 20
七、递归函数
递归是解决问题的一种方式,它的整体思想是将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题。
递归式函数有2个条件:
-
基线条件
问题可以被分解为最小问题,当满足基线条件时,递归就不执行了 -
递归条件
可以将问题继续分解的条件
递归式函数就是在函数中自己调用自己
例1:定义一个函数,求任意数的阶乘
# 定义一个函数 求任意数的阶乘
def fn(n):
# 参数n: 要求阶乘的数字
# 定义一个变量来保存结果
r = n
for i in range(1,n):
r *= i
return r
print(fn(10))
# 输出
3628800
例2:定义一个函数,来为任意数字做任意幂运算 n ** i
# 定义一个函数 来为任意数字做任意幂运算 n ** i
def fn4(n,i):
# 参数 n 做幂运算的数字 i 做幂运算的次数
# 1.基线条件
if i == 1:
# 求1次幂
return n
# 2.递归条件 10 * 10 ** 3
return n * fn4(n,i-1) # 10 ** 3
print(5 ** 3)
print(fn4(5,3))
# 输出
125
125