python函数
文章目录
一、函数定义和调用
- 什么是函数?
- 如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数
- 定义函数的格式如下:
def 函数名():
代码部分
# 定义一个函数,能够完成打印信息的功能
def fun1():
print("--------------------------")
print(" ----i love china---- ")
print("--------------------------")
-
调用函数
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它
调用函数很简单的,通过 函数名() 即可完成调用
# 定义完函数后,函数是不会自动执行的,需要调用它才可以
fun1()
#--------------------------
# ----i love china----
#--------------------------
-
练习
# 定义一个函数 def fun2(a,b): #"2个数求和" print(f"{a}+{b}={a+b}") fun2(11,12)
11+12=23
二、函数参数
什么是函数参数
- 函数取得的参数是你提供给函数的值。
- 这些参数就像变量一样,只不过它们的值是在我们调用函数的时候定义的
参数的形式
- 参数在函数定义的圆括号对内指定,用逗号分割。
- 形参:函数中的参数名称为形参
- 实参:提供给函数调用的值称为实参
参数分类 (按定义)
- 必选参数 => 在调用时必须要填
- 默认参数 => 提供默认值,调用时可填可不填
- 可变位置参数
- 可变长关键字参数
参数分类 (按调用)
-
位置参数 => 按参数顺序依次传递
-
关键字参数 => 按key依次传递
-
# 调用的角度 # def sum(a, b):pass # sum(1,2) => 位置参数 => 按顺序依次传递 # sum(b=2, a=1) => 关键参数传递 => key:value
(1)缺省参数
-
调用函数时,缺省参数的值如果没有传入,则取默认值
。 -
# 为什么要使用默认参数 => 让用户调用的时候更简洁 def myinfo(name, age, sex="保密"): print(name, age, sex) # 位置参数方式调用 myinfo('cali', 18, "男") myinfo('cali', 18) # NO => age没有 # myinfo(name='cali', sex="男") # 关键字参数方式调用 myinfo(name="cali", age=18)
cali 18 男 cali 18 保密 cali 18 保密
-
注意
带有默认值的参数一定要位于参数列表的最后面,否者会报错
(2)可变长位置参数
-
有时可能需要一个函数能处理比当初声明时更多的参数, 这些参数叫做不定长参数,声明时不会命名。
-
def mysum(*args): # print(args) sum = 0 for item in args: sum += item print(sum) mysum(1, 2, 3, 4, 5)
15
(3)可变长关键字参数
-
def mysum(**kwargs): print(kwargs) sum = 0 for value in kwargs.values(): sum += value print(sum) mysum(a=1, b=2, c=3, d=4)
15
(4)总结
参数定义的先后
- 最佳方式:mysun(必选参数, *args, 默认参数, **kargs)
- 不是每项都需要,如果需要的话,要按上述顺序
参数的调用
- mysum(位置参数,关键字参数)
三、函数的return语句
所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果
- 一个函数中可以有多个return语句,但是只要有一个return语句被执行到,那么这个函数就会结束了,因此后面的return没有什么用处
# 没有return 语句时,默认返回 None
def mysun(b, a=10):
pass
print(mysun(10))
#None
# return => 返回函数结果
# 函数如果没有return语句,返回的是None
# 退出函数并返回结果
# return可以直接退出函数
def mysum():
for i in range(10):
print(i)
# return
return None
print(2)
print(3)
print(1)
print(1)
print(1)
mysum()
#0
函数中包含多个return语句
def mysum(x):
if x%2:
return "奇数"
else:
return "偶数"
for x in range(4):
print(mysum(x))
偶数
奇数
偶数
奇数
函数返回多个值
def myfun(*args):
sum = 0
for item in args:
sum+=item
return len(args), sum
result = myfun(1,2,3,4,5)
print(result)
count, sum = myfun(1,2,3,4,5)
print(count, sum)
(5, 15)
5 15
四、匿名函数
匿名函数的定义:
什么时候使用匿名函数
- 当函数只是实现非常简单并且一次性使用时,可以定义为匿名函数
- 当我们在传入函数时,不需要显式地定义函数,直接传入匿名函数更方便。
# 匿名函数的参数,匿名函数是默认返回的,不需要再加return
func03 = lambda x: x ** 3 # 传递一个x,然后给x三次方,并返回
print(func03(2)) # 打印2的三次方
func04 = lambda x, y: x + y # 传递一个x和y,然后给相加,并返回
print(func04(3,5))# 打印3+5
8
8
# sorted => 内建函数 => 排序
# sorted(要排序的对象,key=函数)
help(sorted)
mylist = [-1, 10, 8, -9, 6, 3]
#降序排列
print(sorted(mylist,reverse=True))
#升序排列
print(sorted(mylist,reverse=False))
# 按绝对值进行排序 (-1, 3, 6, 8, -9, 10)
print(sorted(mylist, key=lambda x:x if x>0 else -x))
# if x>0:
# return x
# else:
# return -x
# 不区分大小写排序
mystr = "AsdBcmG"
print(sorted(mystr, key=lambda x:x.lower() if x.isupper() else x))
print(sorted(mystr, key=lambda x:x.lower()))
[10, 8, 6, 3, -1, -9]
[-9, -1, 3, 6, 8, 10]
[-1, 3, 6, 8, -9, 10]
['A', 'B', 'c', 'd', 'G', 'm', 's']
['A', 'B', 'c', 'd', 'G', 'm', 's']
五、递归函数
实现递归的条件:
- 出口条件,即递归“什么时候结束”,这个通常在递归函数的开始就写好
- 可以通过递归调用来缩小问题规模,且新问题与原问题有着相同的形式
通过例子来加强理解;
def fun01(n:int)->int:
"""
:param n:输入一个正整数
:return: 返回阶乘
"""
if n == 1:
return 1
else:
return n*fun01(n-1)
print(fun01(4))
#24
- 递归限制
import sys
#获取最大递归次数
print(sys.setrecursionlimit())
#修改最大递归次数
sys.setrecursionlimit(9999999)
通过比较时间来看出 递归和循环之间的差异;
其中,递归的方式在调用的过程中一直在入栈。这是要耗费内存的,所以在参数值大到一定程度时,入栈 的数据太多就会导致栈溢出了。
import sys
import time
sys.setrecursionlimit(9999999)
def factorial1(n: int) -> int:
if n == 1:
return n
else:
return n * factorial1(n - 1)
n = 3000
# 获取开始时间
start = time.time()
# 递归
factorial1(n)
# 获取结束时间
cost = time.time() - start
print(cost)
0.003999233245849609
import sys
import time
sys.setrecursionlimit(9999999)
def factorial2(n: int) -> int:
result = 1
for i in range(1, n + 1):
result = result * i
return result
n = 3000
# 获取开始时间
start = time.time()
# 递归
factorial2(n)
# 获取结束时间
cost = time.time() - start
print(cost)
0.0020122528076171875
六、函数的参数传递
从动态类型看函数的参数传递, 函数的参数传递,本质上传递的是引用
1、传递不可变对象
def f(x):
x = 100
print("函数内的值:",x)
a = 1
f(a)
print("函数外的值:",a)
函数内的值: 100
函数外的值: 1
- 总结
• 参数x是一个新的引用,指向a所指的对象。
• 如果参数是不可变(immutable)的对象,a和x引用之间相互独立。对参数x的操作不会影响引用a。
• 这样的传递类似于C语言中的值传递。
2、传递可变对象
def func1(a:list)->list:
"""
:param a:接收一个list
:return: 返回一个list
"""
a.append(10)
return a
a = [1,2,3]
print("没有做任何操作的列表:",a)
func1(a)
print("经过一次func1():",a)
func1(a)
print("经过二次func1():",a)
没有做任何操作的列表: [1, 2, 3]
经过一次func1(): [1, 2, 3, 10]
经过二次func1(): [1, 2, 3, 10, 10]
- 总结
• 如果传递的是可变(mutable)的对象,那么改变函数参数,有可能改变原对象。
• 所有指向原对象的引用都会受影响,编程的时候要对此问题留心。
在定义参数时,尽量避免参数的默认值设置成一个可变对象
七、全局变量和局部变量
1、局部变量
局部变量,就是在函数内部定义的变量
def func01():
# 申明一个局部变量x,此x只有这个函数中生效
x = 10
print("改变之后:",x)
x = 5
func01()
print("在函数外部:",x)
函数内部: 10
在函数外部: 5
小结
- 其作用范围是这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的
- 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储
- 当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了
2、全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
(1)全局变量
# 定义全局变量
a = 100
def test1():
print(a) # 虽然没有定义变量a但是依然可以获取其数据
def test2():
print(a) # 虽然没有定义变量a但是依然可以获取其数据
# 调用函数
test1()
test2()
100
100
(2)修改全局变量
def func01():
global x
print("改变之前:",x)
# 申明x是全局变量,函数内部改变外部也会跟着一起改变
x = 10
print("改变之后:",x)
x = 5
func01()
print("函数外部:",x)
改变之前: 5
改变之后: 10
函数外部: 10
小结
- 如果在函数中出现global 全局变量的名字 那么这个函数中即使出现和全局变量名相同的变量名 = 数据 也理解为对全局变量进行修改,而不是定义局部变量
- 当函数内出现局部变量和全局变量相同名字时,
函数内部中的 变量名 = 数据
此时理解为定义了一个局部变量,而不是修改全局变量的值。
八、文档注释
类型注解-typehint
1、实现类型检查,防止运行时出现的类型不符合情况。
2、作为文档附加属性,方便开发者调用时传入传出的参数类型。
3、提升 IDE 的检查机制,在智能提示时更快给出提示和类型检查结果。
# 文档注释:方便使用函数的人查看函数的功能
# arg1:int => 说明参数期待的数据类型
# -> int => 函数的返回的类型
def func01(arg1:int) -> int:
"""
这个函数是用来测试的
:param arg1: 一个int类型的数据
:return: 返回2次方
"""
try:
return arg1**2
except TypeError:
return "你输入的有误!"
help(func01)
print(func01('a'))
print(func01(12))
Help on function func01 in module __main__:
func01(arg1: int) -> int
这个函数是用来测试的
:param arg1: 一个int类型的数据
:return: 返回2次方
你输入的有误!
144