python基础—初识函数(一)
1.python中函数定义
函数是逻辑结构化和过程结构化的一种编程方法。
(1)、python中函数定义方法:
def test(x): '''The function definitions''' x+=1 return x
说明:
def :定义函数的关键字
test :函数名
():可定义形参
'''''':文档描述,非必要
x+=1: 泛指代码块或程序处理逻辑
return: 定义返回值
2.为什么要使用函数
背景摘要:现在需要写一个监控程序,当CPU,MEMORY,DISK等指标的使用量超过阈值时发送报警邮件
(1)、传统方式实现:
while1:
if cpu>90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭链接 if memory >90%:
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭链接 if disk >90%
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭链接
(2)、使用函数实现:
def 发送邮件(内容):
#发送邮件提醒
连接邮箱服务器
发送邮件
关闭链接 while 1:
if cpu>90%:
发送邮件('cpu报警')
if memory>90%:
发送邮件('memory报警')
if disk>90%:
发送邮件('disk报警')
总结使用函数的好处:
1.代码重用
2.保持一致性,容易维护
3.可扩展性
3.函数参数
(1)、形参
形参变量只有在调用时候才分配内存单元,在调用结束时,即刻释放所调用的内存单元。因此,形参只在函数内部有效,函数调用结束返回主调用函数后则不能在使用该形参变量。
(2)、实参
实参可以是常量,变量,表达式,函数等,无论实参是何种类型的量,在进行函数调用时,它们必须有确定的值,以便把这些值传给形参。因此应预先用赋值,输入等办法使参数获得确定值。
def calc(x,y): #x,y为形参
res=x**y
return res calc(a,b) #a,b为实参
print(calc(a,b))
(3)、位置参数和关键字
标准调用:实参和形参一一对应
关键字调用:位置无需固定
def test(x,y,z):
print(x)
print(y)
print(z) test(1,2,3) #位置标准调用
test(x=1,y=3,z=2)#关键字调用
注意:如果混合使用,位置参数一定要在关键字参数的左边
(4)、默认参数
def handle(x,type='mysql'):
print(x,type) handle('hello') #type默认值为'mysql'
handle('hello',1) #重新赋值,覆盖原本默认参数
>> hello mysql
hello 1
(5)、可变长参数
①、*args
能够接收列表或元祖
为了能让一个函数接受任意数量的位置参数。
def avg(first, *args):
return (first + sum(rest)) / (1 + len(args)) avg(1, 2) # 1.5
avg(1, 2, 3, 4) # 2.5
在这个例子中,args是由所有其他位置参数组成的元组。然后我们在代码中把它当成了一个序列来进行后续的计算。
②、**kwargs
为了接受任意数量的关键字参数
def test(**kwargs)
print(kwargs)
test(a=1, b=2) >>{'a': 1, 'b': 2}
如果希望某个函数能同时接受任意数量的位置参数和关键字参数,可以同时使用*和**。
def anyargs(*args, **kwargs):
print(args) # A tuple
print(kwargs) # A dict
使用这个函数时,所有位置参数会被放到args元组中,所有关键字参数会被放到字典kwargs中。
注意:
一个*参数只能出现在函数定义中最后一个位置参数后面,而 **参数只能出现在最后一个参数。 有一点要注意的是,在*参数后面仍然可以定义其他参数。
def a(x, *args, y): #此时y必须是关键字参数
pass def b(x, *args, y, **kwargs): # 此时y必须是关键字参数
pass
这种参数就是我们所说的强制关键字参数。
扩展:只接受关键字参数的函数
希望函数的某些参数强制使用关键字参数传递,只需将强制关键字参数放到某个*参数或者单个*后面就能达到这种效果。
def recv(maxsize, *, block):
'Receives a message'
pass recv(1024, True) # TypeError
recv(1024, block=True) # Ok
利用这种技术,我们还能在接受任意多个位置参数的函数中指定关键字参数。比如:
def minimum(*values, clip=None):
m = min(values)
if clip is not None:
m = clip if clip > m else m
return m minimum(1, 5, 2, -5, 10) # Returns -5
minimum(1, 5, 2, -5, 10, clip=0) # Returns 0
很多情况下,使用强制关键字参数会比使用位置参数表意更加清晰,程序也更加具有可读性。 例如,考虑下如下一个函数调用:
msg = recv(1024, False)
如果调用者对recv函数并不是很熟悉,那他肯定不明白那个False参数到底来干嘛用的。 但是,如果代码变成下面这样子的话就清楚多了:
msg = recv(1024, block=False)
另外,使用强制关键字参数也会比使用**kwargs参数更好,因为在使用函数help的时候输出也会更容易理解:
>>> help(recv)
Help on function recv in module __main__:
recv(maxsize, *, block)
Receives a message
(6)、局部变量和全局变量
规则:全局变量名大写,局部变量名小写
在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。
如果函数内无global关键字
#有声明局部变量,函数调用会调用局部变量
HOBBY = ['上网', '打游戏']
def test():
HOBBY = '泡妞'
print('我的爱好:', HOBBY) test() >>我的爱好:泡妞
#无声明局部变量,函数会调用全局变量
HOBBY = ['上网', '打游戏']
def test():
print('我的爱好:',HOBBY) test() >>我的爱好:['上网', '打游戏']
如果函数中有global关键字
a = 1
def test():
global a
a += 1 # 改变全局变量a的值
print('函数中的a:', a)
return a test()
print(a)
(7)、返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,所以也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
4、嵌套函数
def negan():
name = 'Negan'
print(name)
def alex():
name = 'Alex'
print(name)
def egon():
name = 'egon'
print(name)
print(name)
egon()
alex()
print(name)
说明:函数只有在被调用的时候才会被执行
5、递归函数
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
(1)、使用递归计算n的阶乘
计算阶乘n! = 1 x 2 x 3 x ... x n
,用函数fact(n)
表示,可以看出:
fact(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x n
所以,fact(n)
可以表示为n x fact(n-1)
,只有n=1时需要特殊处理。
于是,fact(n)
用递归的方式写出来就是:
def fact(n):
if n==1:
return 1
return n * fact(n - 1)
假如我们要计算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
(2)、递归问路
import time
person_list = ['Alex','Bob','Christian']
def ask_way(person_list):
print('_'*60)
if len(person_list) == 0:
print('没有人知道')
return '没有人知道'
person = person_list.pop(0)
if person == 'Christian':
return '%s说:我知道,路在脚下' %person
print('Hi,%s敢问路在何方?' %person)
print('%s说:我不知道,我可以帮你去问问%s' %(person,person_list))
time.sleep(1)
res = ask_way(person_list)
print('%s问的结果是:%res' %(person, res))
return res res = ask_way(person_list)
print(res)
____________________________________________________________
Hi,Alex敢问路在何方?
Alex说:我不知道,我可以帮你去问问['Bob', 'Christian']
____________________________________________________________
Hi,Bob敢问路在何方?
Bob说:我不知道,我可以帮你去问问['Christian']
____________________________________________________________
Bob问的结果是:'Christian说:我知道,路在脚下'es
Alex问的结果是:'Christian说:我知道,路在脚下'es
Christian说:我知道,路在脚下
(3)、递归计算列表中所有元素的和
item = [1,2,3,4,5,6,7]
def sum(item)
head, *tail = item
return head + sum(tail) if tail else head
递归特性:
a. 必须有一个明确的结束条件
b. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
c. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,
每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,
所以,递归调用的次数过多,会导致栈溢出,Python3中默认栈的大小是998)
6、匿名函数
Python中可以不用def关键字创建函数,使用lambda即可创建匿名函数,语法格式如下:
lambda = param1,param2,...,paramN:expression
匿名函数也是函数,与普通函数一样,参数也是可选的。
# 普通函数
def calc(x):
return x*x # 改成匿名函数
lambda x : x*x
扩展:
>>> x = 10
>>> a = lambda y: x + y
>>> x = 20
>>> b = lambda y: x + y
a(10)和b(10)返回的结果是什么?如果你认为结果是20和30,那么你就错了。
这其中的奥妙在于lambda表达式中的x是一个自由变量, 在运行时绑定值,而不是定义时就绑定,这跟函数的默认值参数定义是不同的。 因此,在调用这个lambda表达式的时候,x的值是执行时的值。例如:
>>> x = 15
>>> a(10)
25
>>> x = 3
>>> a(10)
13
如果你想让某个匿名函数在定义时就捕获到值,可以将那个参数值定义成默认参数即可,就像下面这样:
>>> x = 10
>>> a = lambda y, x=x: x + y
>>> x = 20
>>> b = lambda y, x=x: x + y
>>> a(10)
20
>>> b(10)
30
在这里列出来的问题是新手很容易犯的错误,有些新手可能会不恰当的使用lambda表达式。 比如,通过在一个循环或列表推导中创建一个lambda表达式列表,并期望函数能在定义时就记住每次的迭代值。例如:
>>> funcs = [lambda x: x+n for n in range(5)]
>>> for f in funcs:
... print(f(0))
...
4
4
4
4
4
>>>
但是实际效果是运行是n的值为迭代的最后一个值。现在我们用另一种方式修改一下:
>>> funcs = [lambda x, n=n: x+n for n in range(5)]
>>> for f in funcs:
... print(f(0))
...
0
1
2
3
4
>>>
7、高阶函数
满足下面两个条件即为高阶函数:
(1)、函数传入的参数是一个函数名
(2)、函数的返回值是一个函数
(1)、把函数当作参数传给另一个函数
def foo(n):
print(n)
def bar(name):
print('My name is %s'%name) foo(bar('alex')) >>My name is alex
None
(2)、返回值中包含函数
def foo():
print('from foo')
return bar def bar():
print('from bar') foo()() >> from foo
from bar
(3)、尾调用
在函数的最后一步调用另外一个函数(最后一行不一定是函数的最后一步)
尾调用的关键在于函数的最后一步调用别的函数,根据函数即变量的定义,定义a函数,a函数内调用b函数,b函数内调用函数c,在内存中形成一个调用记录,又称为调用栈,用于保存调用位置以及变量信息,即a->b->c,直到c返回结果给b,c的调用记录才会消失,b返回结果给a,b的调用结果消失,a返回结果,a的调用记录消失,所有的调用记录都是“”先进后出”,形成一个‘’调用栈‘’。
(4)、map()函数
num = [1,2,3,4] def add(x):
return x +1 def map_test(func, array)
ret = []
for i in array:
ret.append(func(i))
return ret print(map_test(add, num)) >> [2,3,4,5] # 使用普通函数
print(map_test(lambda x:x+1, num)) >> [2,3,4,5] # 配合匿名函数实现
使用map函数实现上面的功能
注意:调用map时候返回的是map类的实例,此时func的方法并没有执行,根据需要返回的类型,在map实例中调用list、tuple、set、dict等方法触发回调函数。
num = [1,2,3,4] print(list(map(lambad x: x+1, num)))
(5)、filter()函数
遍历序列中每个元素,判断每个元素得到一个布尔值,如果是True则留下来。
data = list(range(10)) def func(item):
if item % 2 == 0:
return item def filter_test(func, array):
ret = [0]
for i in array:
if func(i):
ret.append(func(i))
return ret
filter_test(func, data) >> [0,2,3,6,8]
使用filter()函数实现
list(filter(lambda x:x%2==0, list(range(10))))
(6)、reduce()函数
reduct方法有三个参数:
reduce(function, sequence, initial=None)
function:待执行的方法
sequence:序列
initial:初始值
在没有初始值的情况下,首次执行会从序列中取出来两个值,传入function得到一个结果,然后从序列中按照顺序取出下一个值,和该结果一起传入function,直到序列中把所有
num = [1,2,3,10] def multi(x,y):
return x*y def reduce_test(func,array,init=None):
if init is None:
res = array.pop(0)
else:
res = init
for i in array:
res = func(res,i)
return res
print(reduce_test(multi,num,10))
使用reduce()实现
from functools import reduce num = [1,2,3,10] reduce(lambda x,y: x*y, num)
带默认参数
from functools import reduce num = [1,2,3,10] reduce(lambda x,y: x*y, num) >>120
python基础—初识函数(一)的更多相关文章
- python基础 (初识函数&函数进阶)
函数基础部分 .什么是函数? 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率. 2.定义函数 定义:def 关键词开头,空格之后接函数名 ...
- python基础——匿名函数
python基础——匿名函数 当我们在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.还是以map()函数为例,计算f(x)=x2时 ...
- python基础——返回函数
python基础——返回函数 函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. 我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_ ...
- python基础——sorted()函数
python基础——sorted()函数 排序算法 排序也是在程序中经常用到的算法.无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小.如果是数字,我们可以直接比较,但如果是字符串或者两个d ...
- python基础——filter函数
python基础——filter函数 Python内建的filter()函数用于过滤序列. 和map()类似,filter()也接收一个函数和一个序列.和map()不同的是,filter()把传入的函 ...
- python基础——匿名函数及递归函数
python基础--匿名函数及递归函数 1 匿名函数语法 匿名函数lambda x: x * x实际上就是: def f(x): return x * x 关键字lambda表示匿名函数,冒号前面的x ...
- 八. Python基础(8)--函数
八. Python基础(8)--函数 1 ● 函数返回布尔值 注意, 自定义的函数也可以是用来作逻辑判断的, 例如内置的startswith()等函数. def check_len(x): ' ...
- Python基础初识
一.安装 暂时没空写,预留 二.python基础初识 2.1 注释 当行注释:# 被注释内容 多行注释:'''被注释内容''',或者"""被注释内容"" ...
- python基础之函数详解
Python基础之函数详解 目录 Python基础之函数详解 一.函数的定义 二.函数的调用 三.函数返回值 四.函数的参数 4.1 位置参数 4.2 关键字参数 实参:位置实参和关键字参数的混合使用 ...
- Python学习笔记(一)python基础与函数
1.python基础 1.1输入与输出 输出 用print加上字符串,就可以打印指定的文字或数字 >>> print 'hello, world' hello, world > ...
随机推荐
- Oracle客户端中文显示问号乱码问题
Oracle显示中文显示??乱码 问题如下图 解决方法 打开Oracle客户端,新建一个SQL Window 输入select userenv('language') from dual 复制搜索到的 ...
- mdn拾遗-- 纯html+css实现的input的验证
关于input的验证,其实从很古老的前端时代开始就一直采用一种比较可靠的方式,就是js操作dom,今天浏览mdn时发现了h5的验证方法,很是兴奋.感觉值得一记. 说在前面的话,着重就是配合h5 + c ...
- 解决VuePress中的”Error from chokidar : Error: EBUSY“问题
.title { padding: 10px; background-color: rgba(3, 169, 244, 1); font-size: 16px; color: rgba(255, 25 ...
- TCP协议详细介绍
TCP报文格式: 字段介绍: 源/目的端口:用来标识主机上的程序 序号(seq):4个byte,指当前tcp报文段中第一个字节的序号(tcp报文中每个字节都有一个编号) 确认号(ack):4个byte ...
- Netty源码—6.ByteBuf原理一
大纲 1.关于ByteBuf的问题整理 2.ByteBuf结构以及重要API 3.ByteBuf的分类 4.ByteBuf分类的补充说明 5.ByteBuf的主要内容分三大方面 6.内存分配器Byte ...
- BUUCTF---异性相吸(欠编码)
1.题目 ܟࠄቕ̐员䭜塊噓䑒̈́ɘ䘆呇Ֆ䝗䐒嵊ᐛ asadsasdasdasdasdasdasdasdasdasdqwesqf 2.知识 3.解题 很奇怪,不知道什么加密,借鉴网上参考,得知需将其转化为 ...
- AspNetCore Json序列化设置
AspNetCore 中的Json序列化处理已经默认使用Newtonsoft.Json库了... 比如像MVC中: public I 不过使用过程中会发现一些问题,其实这算默认设置吧: Json序列化 ...
- FastAPI中实现动态条件必填字段的实践
title: FastAPI中实现动态条件必填字段的实践 date: 2025/04/03 00:06:20 updated: 2025/04/03 00:06:20 author: cmdragon ...
- 线性探测法的查找函数 作者 DS课程组 单位 浙江大学
虽然但是,我真的讨厌c语言这样一大坨typedef命名来命名去的,很多时候其实我们会写,但是看不懂这个存储结构 函数的接口定义 Position Find( HashTable H, ElementT ...
- LeetCode1464. 数组中两元素的最大乘积-JAVA
题目 给你一个整数数组 nums,请你选择数组的两个不同下标 i 和 j,使 (nums[i]-1)*(nums[j]-1) 取得最大值.请你计算并返回该式的最大值. 示例 1: 输入:nums = ...