当前位置: 首页 > news >正文

手撕Python之函数


1.函数

定义函数的语法

def 函数名 :

代码语句

函数的作用:我们把需要反复执行的程序封装起来,制作成一个可以反复调用的工具,这个工具在编程中就叫函数

对于不同情况我们就调用对应的函数,可以减少代码量

简单函数的创建:

#对于函数,函数内的代码前面要有一个缩进,表示这些代码是属于这个函数的
def test():print("存款")print("取款")print("查询")print("取卡")#def是函数创建的一个关键词

注意:函数不会主动进行编译的,需要我们手动进行调用的

下面就是如何对函数的调用

我们在使用函数的时候直接就是函数名()

比如说int()要加括号才能执行

#那么我们在创建好函数之后我们怎么进行函数的使用呢?#注意:函数不会主动进行编译的,需要我们手动进行调用的#使用函数(调用函数)---函数名()#对于这种调用的方法的话,我们之前的print() 和type()
#都是函数,只不过里面的代码我们是不需要写的,之前就写好了的,我们直接调用进行使用就行李科test()
#这里我们成功调用函数
'''
存款
取款
查询
取卡
'''

使用函数之后我们的代码量就不会出现冗余的现象了

对于用户登录的题目我们是可以用函数的

注册:

#用户注册---reg
def reg():name=input("请输入注册的用户名:")while True:p1=input("请输入密码:")p2=input("请再次输入密码:")if p1==p2:students.append({'name':name,'password':p1})#p1是字符串我们得进行转换print("注册成功")#那么我们就不用再输入密码了,我们就退出这个循环就行了breakelse:print("两次密码要一致")
#直到我们输入正确的密码之后我们就能跳出这个循环了

登录:

#用户登录---log
def log():name=input("请输入用户名:")for i in students:#i存在的是用户的信息字典if name==i['name']:#对输入的用户名进行判断for n in range(1,4):#循环3次进行输入密码的操作,如果输入正确直接跳出循环pwd=input("请输入密码:")if pwd==i['password']:print('登录成功')#exit()break#只能退出当前所在的循环,就是跳出了里面的循环,还是处于外部循环else:print(f'密码错误,还剩{3-n}次机会')if name==i['name'] and pwd==i['password'] :breakelse:print("用户名不存在,请先注册")

那么我们在实现用户的登录和注册时候的场景就是下面这样的:

如果我们输入的没有注册的话就会提示我们进行注册的操作

#对于用户登录和用户注册我们是可以封装为两个函数的
students =[
{'name':'张三','password':'123'},
{'name':'王五','password':'888'},
{'name':'赵六','password':'456'}
]
#用户登录---log
def log():name=input("请输入用户名:")for i in students:#i存在的是用户的信息字典if name==i['name']:#对输入的用户名进行判断for n in range(1,4):#循环3次进行输入密码的操作,如果输入正确直接跳出循环pwd=input("请输入密码:")if pwd==i['password']:print('登录成功')#exit()break#只能退出当前所在的循环,就是跳出了里面的循环,还是处于外部循环else:print(f'密码错误,还剩{3-n}次机会')if name==i['name'] and pwd==i['password'] :breakelse:print("用户名不存在,请先注册")
#用户注册---reg
def reg():name=input("请输入注册的用户名:")while True:p1=input("请输入密码:")p2=input("请再次输入密码:")if p1==p2:students.append({'name':name,'password':p1})#p1是字符串我们得进行转换print("注册成功")#那么我们就不用再输入密码了,我们就退出这个循环就行了breakelse:print("两次密码要一致")
#直到我们输入正确的密码之后我们就能跳出这个循环了while True:n=input('1.登录   2.退出   3.提出\n请输入你要操作的内容')if n =='1':log()elif n=='2':reg()elif n=='3':print("退出")breakelse:print("请输入正确的序号")

对于里面的while True

我们采用的是死循环,只要我们回答对了就跳出这个死循环

2.函数参数

位置参数

函数参数包括形参和实参

实参就是我们传到函数的参数就是叫实参

形参就是函数用来接受我们传来的实参而创建的参数就是形参

形参:变量名,写在定义函数时的括号里面

实参:数据,写在调用函数时的括号里

传参:实参的数据给到形参的变量名

实参是写在调用函数的括号里面的哦

加法函数的创建:

#现在我们定义一个加法的函数def Add(a,b):print(a+b)a=int(input("输入a:"))
b=int(input("输入b:"))Add(a,b)

如果我们不传实参的话是会报错的

对于参数的话,我们实参和形参必须一一对应

关键字参数

函数名(形参=实参)

#我们这里直接指定好参数
print(sep='\t',end='\n')#指定传参,这样就可以不用一一对应了
Add(b=100,a=10)

就是我们直接在调用函数的时候我们直接规定好参数的大小

那么我们就调用的时候就不需要参数一一对应上了

默认参数

作用:再调用函数时,默认参数没有传递值,就会使用我们设定好的默认值

'''
#默认参数
'''
def 函数名(形参=默认值,......):函数体'''
def func(name,sex='男'):print(f'我是{name},性别:{sex}')func("小黑")
#我是小黑,性别:男#我们在这个函数的调用的时候我们只传了name"小黑"
#并没有传性别,因为我们性别在这个函数体中已经是默认的了func("小美",'女')
我是小美,性别:女

对于默认参数的话,我们一开始在函数体里面已经设定好了他的值

后面我们调用这个函数的时候我们是不需要传这个默认参数的大小的

因为这个参数已经有值了,我们就不需要进行传递了

但是我们如果传了默认参数的值的话,我们就采用的是我们传的值

就像上面

小美是女生,我们的默认性别是男生,那么我们将性别女传上去,那么打印出来的就是“我是小美,性别:女”

对于函数中存在默认参数的看法

不传这个参数就是使用默认参数

但是如果传了参数的话,就是使用我们传的参数

对于函数参数的位置的话,我们需要先定义这个位置参数,然后定义默认参数

因为如果先定义默认参数的话,那么我们不传参的情况下位置参数就没有进行定义,就是会报错的

反正就是默认参数放在后面

 

不定长参数

不定长参数也叫可变参数,用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。

不定长参数 用于不确定调用时传递的实参个数

对于不定长参数的话,我们分为元组不定长和字典不定长

元组不定长---*args

#元组不定长---*args
def funa(*args):print(args)#传入的数据全部存放在args中funa()
#()
#我们不传参的话那么就是打印一个括号#我们这里args前面加上*,就像是之前的变量前面加上*就能接受所有剩余的数据
#就像拆包一样funa(1)
#(1,)
#我们传参1
#我们这里打印出来的就是一个元组类型的数据#我们这个就是将传入的实参全部接受,以元组的方式进行保存
#不管传多少都是不会进行报错的#这个不定长的参数就是保障了我们不知道参数个数的情况下降参数进行保存下来

那么数据是存储在元组里面

字典不定长---**kwargs

#字典不定长---**kwargs
#我们传入的数据以字典的方式进行存放
#字典{}
def funb(**kwargs):print(kwargs)funb()
#以关键字传参---形参(键)==实参(值)
funb(name="小敏",age=18)
#{'name': '小敏', 'age': 18}#格式就是函数名字(键1=值1,键2=值2)

格式就是函数名字(键1=值1,键2=值2)

 

参数顺序

参数顺序:必备参数、默认参数、不定长参数

我们是一点要按照这种顺序进行定义的

不然是会出现报错的

参数的拆包

参数的拆包存在两种形式的

一种就是通过变量依次进行赋值

第二种就是直接在元组的前面加上*直接对这个元组进行拆包的操作

然后将拆包的结果当做实参传到函数里面

#定义一个元组
t=(1,2,3)
def func(a,b,c):print(a,b,c,sep='\t')#我们现在想让这个元组内的数据以实参的形式传到函数里面,那么该怎么操作呢?#我们是可以使用拆包这个知识点
#拆包是存在两种形式的
#第一种:以变量的形式进行接收数据
'''
我们用变量的形式将这个元组内的数据依次进行接收
然后将这些变量以实参的形式传到这个函数里面
'''
x,y,z=t
func(x,y,z)
#1    2   3
#第二种:用*号进行接收
'''
在元组的名字前面加上*用于这个拆包,以实参的形式传到函数里面进行后续的操作
'''
func(*t)
#1    2   3print(t)
#(1, 2, 3)print(*t)
#1 2 3#我们对元组进行拆包的操作之后我们就得到元组内的每个数据了

3.return 

使用方式:

return 数据 返回一个数据

return 数据,数据--返回多个数据,以元组的方式进行返回

作用:将数据返回给到函数调用处

n='afasg'.upper()
print(n)
#AFASG
#那么这个就是这个函数的返回值
def testa():return  '返回一个数据'print(testa())
#返回一个数据#这个就是我们的函数返回值
#我们在函数里面设定好我们要返回的值
#那么这个函数在主函数里面的返回值就是我们设定的返回值

除了这个返回我们需要的值

return 还能结束函数

reutrn和print的区别,区别很大的

return 返回值 print输出值

return 只能执行一个函数

print可以执行多个

那么return该怎么使用呢?

4.函数作用域

函数的作用域详解

局部作用域:变量出了作用域就被销毁

如果没有返回的情况下,变量出函数就会被销毁的

"""def testb():num=10print(f'testb:{num}')
testb()
#testb:10def testc():print(f'testc:{num}')
testc()#这个是会报错的,因为我们这个函数里面的num对于这个函数是没有进行定义的#局部作用域:定义在函数里面的变量
#除了这个作用域的变量就会销毁的#就像这个testb里面的num是局部变量
#那么到testc里面就已经是被销毁的,#这个变量是在testb里面进行定义的
#那么只能够作用于testb里面#但是现在我就是想在test里面使用num该怎么做呢?#只要testb函数主动出来,那么我们就能在testc里面进行num的使用

在testc里面使用testb里面的num

利用到了return 进行数据的返回:

def testb():num=10print(f'testb:{num}')return num
testb()def testc():num=testb()print(f'testc:{num}')
testc()
#testb:10
#testb:10
#testc:10'''
我们在先在testb这个函数将num进行返回的操作
然后在testc里面进行调用testb然后得到了num的值
然后我们再重新为num进行复制
那么我们最后就在testc里面将num进行打印了
'''

使用return将值返回到函数调用处

全局作用域:整个py文件都可以进行使用的

局部作用域修改为全局作用域----global 局部变量名

通过这个方法将变量进行声明,那么这个变量在全局都能用

def testb():global num#对变量进行声明,变量num为全局作用域num=10print(f'testb:{num}')return num
testb()def testc():num=testb()print(f'testc:{num}')
testc()def testd():print(f'testd:{num}')testd()
#testd:10
#那么就说明num这个变量已经成为了个全局变量了

我们在1号函数内进行变量的全局声明,那么我们在后续的函数中都能对这个变量的使用了

全局作用域是定义在函数的外面的,整个py文件都能用

如果我们想要函数内的变量成为全局作用域的话就使用global来声明变量

对于函数来说

如果在函数调用的时候我们使用到某个变量的时候,函数通常会检查自己的空间内是否存在这个变量,如果没有的话那么就会在全局里面对这个变量进行寻找

s=100
print(f's:{s}')def set():s=10print(f'set:{s}')set()
print(s)'''
s:100
set:10
100'''#对于函数调用的时候,如果使用到某一个变量的时候
#函数会自己进行检查空间内是否存在这个变量
#如果自己有就会用自己的
#自己没有的互就用字节的

但是如果函数里面存在这个变量的话,那么函数是不会去外面找的,就直接用函数里面存在的变量上面的代码就能看的出函数里面的变量和外面的变量不是一个东西

在下面的代码中我们将函数内的变量s删除了

函数没有在自己的空间内找到这个变量,那么函数就去全局进行这个变量的寻找了

s=100
print(f's:{s}')def set():print(f'set:{s}')set()
print(s)'''
s:100
set:100
100
'''

对于这种事存在顺序的

函数通常是从里面到外面进行变量的寻找的

如果里面没有,那么就去外面找

使用global将s变为全局作用域

s=100
print(f's:{s}')def set():global ss-=10print(f'set:{s}')set()
print(s)
'''
s:100
set:90
90
这里的s我们在函数的开头进行了全局作用域的声明了
那么函数在被调用的时候使用的变量就是全局的s

global的补充使用:

name='小明'#全局作用域def test():name='小红'print(f'test:{name}')
test()
print(name)
'''
test:小红
小明
'''
#像这种打印就涉及到空间了
'''
这个小红是个局部变量,当函数结束之后这个变量占用的内存是会被回收的
这就是为什么这个变量只能在函数中进行作用
出函数就被销毁了函数被调用的时候是会被分配空间的
一但被执行完之后这个空间就会被销毁的
''''''
函数如果在被调用的时候会先检查自己的空间内是否存在这个变量
如果不存在的话那么这个函数就去全局进行变量的查找
'''name='小明'#全局作用域def test():global namename='小红'print(f'test:{name}')
test()
print(name)
'''
test:小红
小红
'''
#这里我们对name进行了声明了
#那么这个name 就是一个全局变量
#那么我们在函数里面进行该值的话就是对这个name进行一个重新赋值的操作

函数的嵌套(nonlocal的使用)

外部函数嵌套内部函数

我们不能直接进行内部函数的调用

我们这个内部函数是在外部函数中进行定义的

那么定义完成之后我们可以顺便进行内部函数的调用

那么我们在调用外部函数的时候会顺便调用内部函数的

def outer():print('外部函数')def inner():print('内部函数')
outer()
#外部函数
#这里仅仅只会执行外部函数的内容,并不会执行内部函数
#如果我们想调用这个内部函数我们该怎么操作呢?#inner
#如果我们直接调用内部函数的名字是会报错的,说我们没有定义这个内部函数'''
内部函数的空间在外部函数的里面
'''
#我们在外部函数中定义了一个内部函数,那么我们是否能直接在外部函数中直接写内部函数的调用
#那么我们调用外部函数的时候会连同内部函数一起进行调用呢?def outer():print('外部函数')def inner():print('内部函数')inner()#对内部函数的调用
outer()'''
外部函数
内部函数
'''
#理论存在,实践成立#内部函数只能在外部函数中进行调用,我们是不能在外面进行内部函数的调用的

除了上面的方法调用内部函数,我们还有一种方法进行内部函数的调用

我们就是要在函数外面调用内部函数

我们通过外部函数将内部函数进行返回

返回到函数调用处

然后通过进行变量进行接收这个返回值,然后我们就能通过这个变量进行这个内部函数的调用了

def outer():print('外部函数')def inner():print('内部函数')return inner#返回内部函数名,返回内部函数的位置#我们在外部函数将内部函数进行返回,那么我们在外面进行外部函数的调用的时候
#可以获取到内部函数的位置
#那么我们直接定义一个变量进行返回值的接受
i=outer()
i()
'''
外部函数
内部函数
'''#外部函数主动将内部函数的位置暴露出来了
#我们通过这个返回值就能对内部函数进行带调用了#那么这里的i里面存储的就是内部函数的信息
#相当与i等价于inner
#那么我们能通过这个n进行内部函数的调用#如果不创建变量我们进行内部函数的调用的话,我们可以通过使用返回值和两个括号进行操作
outer()()
#这个就是内部函数的调用了

不用变量的话我们直接在返回值后面加上括号

outer()()

对于嵌套函数中的变量进行讨论

def testa():a=10def testb():a=100print(f"内部函数:{a}")testb()print(f"外部函数:{a}")testa()
'''
内部函数:100
外部函数:10'''
'''
我们调用这个函数时,我们先创建变量a并且赋值
然后进行函数testb的创建
我们是没有进行函数testb的调用的
我们在定义完成之后我们就进行了这个函数的调用'''#对于这个函数里面的两个a
#我们创建的两个函数有自己对应的空间
#外部函数内部包含内部函数
#并且函数内部和外部函数的变量a是不会互相打扰的
#空间不是一个地方的
#所以这个a的值是不同的,本质上是不同的#如果想要两个a是一个a,那么就是内部函数引用外部函数中的a

内部函数和外部函数里面的变量是互不干扰的(在没有作用域的声明下)

如果想让内部函数引用的是外部函数的变量的话

我们应该怎么做呢?

我们可以使用nonlocal将内部函数的变量的是引用外部函数的

nonlocal的使用:

def testa():a=10def testb():nonlocal a#声明我们内部函数用的a引用的是外部函数的aa=100print(f"内部函数:{a}")testb()print(f"外部函数:{a}")#想在内部函数中的变量声明为外部函数的变量值---nonlocal
testa#既然我们在内部函数内已经声明了这个内部函数引用的a是外部函数的a
#那么我们在内部函数中对a进行更改的话,那么外部函数的a也会受到影响的

注意

nonlocal只能用来声明内部函数的变量来自外部函数

nonlocal只能用在嵌套函数中

5.匿名函数

在Python语言中,可以使用lambda来创建匿名函数。所谓匿名,是指不用def语句的形式来定义一个函数。

lambda 参数:语句(返回值)

#匿名函数简单的使用
#lambda 参数:语句
#语句会被作为返回值的#语句:执行语句内容,并将结果进行返回到调用处
#简单的加法操作
add=lambda x,y:x+y
print(add(1,4))
#5
#我们将这个匿名函数的返回值用add进行接收
#但是这个返回值就是后面语句的方法的地址
#我们需要对这个接收返回值参数的变量进行传参的操作#判断是否为偶数
even=lambda n:n%2==0#如果是偶数的话就会返回True
print(even(12))#匿名函数的格式
#lambda 变量 : 判断表达式

lambda 参数:语句

我们用变量接收这个返回值

然后对这个返回值传参就能调用这个匿名函数了

对于这个匿名函数来说我们还有一种使用方法:

匿名函数常用于函数作为参数的场景

li=['abcdef','123','abcd','12']
#按照元素的长度进行排序
li1=sorted(li,key=lambda w:len(w))
#['12', '123', 'abcd', 'abcdef']
print(li1)'''
key 参数:告诉sorted()在排序的时候使用哪个函数或属性来确定每个元素的排序顺序
对于这个sorted来说的话,我们的参数可以是降序或者是升序
同样也可以是长度
我们根据这个份key进行排序
我们的排序方法默认是升序
我们的这个临时排序sorted是依照li这个参数
从li这个列表中进行排序
然后根据key进行排序
'''
'''
w接收一个元素为参数,返回元素的长度
每次从列表中选择一个元素然后在这个匿名函数中进行计算,返回这个长度作为临时排序的参数'''

我们利用这个临时排序对列表中的元素以元素的长度进行排序

那么我们如何获取元素的长度呢

我们的临时【排序的第一个参数是列表的名字,

第二个参数是这个匿名函数

我们用这个key来接受这个匿名函数的返回值

我们这个匿名函数的作用就是返回这个元素的长度的

在Python中,sorted 函数可以接受一个 key 参数,该参数是一个函数,用于在排序过程中为每个元素提供一个用于比较的值。在你提供的代码中,使用了 lambda 函数作为 key 参数的值。

lambda 函数是一个小型匿名函数,它可以接受任意数量的参数,但只能有一个表达式。在你的例子中,lambda w: len(w) 定义了一个接受一个参数 w 的匿名函数,并返回 w 的长度。

这里的 w 代表列表 li 中的每个元素。当 sorted 函数对列表进行排序时,它会调用这个 lambda 函数为每个元素计算一个值(在这个例子中是元素的长度),然后根据这些值来对元素进行排序。

具体来说,len(w) 是内置的 len 函数,它返回对象 w 的长度。对于字符串来说,len 函数返回字符串中的字符数。

所以,当你执行以下代码:

li=['abcdef','123','abcd','12']
li1=sorted(li,key=lambda w:len(w))
print(li1)

sorted 函数会对列表 li 中的每个元素调用 lambda w: len(w),得到每个元素的长度,然后根据这些长度对元素进行排序。最终,你会得到一个按照元素长度排序的新列表 li1,即 ['12', '123', 'abcd', 'abcdef']

6.闭包

闭包:在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。

1.嵌套函数:在一个外函数中定义了一个内函数

2.内函数里运用了外函数的局部变量

3.外函数返回内函数名。

作用:

1.可以在外部函数修改函数内部的变量值,是函数内部与外界沟通的桥梁

2.将局部变量持久的保存在内存中

def counter():count=0def in_count():nonlocal count#每调用一次内部函数进行+1,实现计数count+=1print(f'第{count}次')return in_countc=counter()
c()
'''
我们调用的是内部函数,我们每次调用完内部函数之后这个内部函数的空间就会被回收
但是我们在交互模式一直进行内部函数的调用
然后回发现这个count并没有进行清零的操作
而是在上次的基础上进行+1的操作
这是为什么呢?因为我们调用的是内部函数,而内部函数中计数使用的是外部函数的变量
我们通过内部函数的调用使外部函数内的变量产生永久性的改变count就没有被回收掉
'''

闭包的三个条件

1.嵌套函数

2.内部函数使用的变量是外部函数的变量(nonlocal定义)

3.外部函数的返回值是内部函数的函数名

通过外包我们的这个变量是不会因为内部函数的销毁被清零

而是可以一直进行+1的操作

def outer_function(x):def inner_function(y):return x + yreturn inner_function# 创建一个闭包
closure = outer_function(2)# 使用闭包
result = closure(3)  # 输出 5
print(result)

在这个例子中,inner_function 是一个闭包,它记住了外部函数 outer_function 的变量 x。即使 outer_function 已经执行完毕,我们仍然可以通过调用 closure 来使用 x 的值。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 环保专包二级资质续期:了解必要的时间准备
  • 机器视觉-3 光学成像之明场与暗场
  • 微信小程序手写签名
  • Spring Boot 的Web项目如何直接显示html
  • Linux开发:在 VSCode 中配置 Linux C++ 项目的头文件路径
  • 嵌入式——什么是堆、什么是栈
  • 【Spring Boot 3】【Web】国际化
  • EasyCVR视频汇聚平台:巧妙解决WebRTC无法播放H.265视频的难题
  • 透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路
  • SOMEIP_ETS_088: SD_Answer_multiple_subscribes_together
  • DML、DQL、DCL的基础介绍
  • 【Java】ApiPost请求返回 `406` 状态码(jackson)
  • 解决linux云服务器ping不通另一台linux云服务器的问题
  • IP 协议详解
  • flutter之常用数据类型
  • @angular/forms 源码解析之双向绑定
  • [译]前端离线指南(上)
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • angular2开源库收集
  • CSS 专业技巧
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • ES6系列(二)变量的解构赋值
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • interface和setter,getter
  • JavaScript 奇技淫巧
  • JavaScript标准库系列——Math对象和Date对象(二)
  • Linux编程学习笔记 | Linux IO学习[1] - 文件IO
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • use Google search engine
  • WebSocket使用
  • 从零开始学习部署
  • 第2章 网络文档
  • 订阅Forge Viewer所有的事件
  • 给自己的博客网站加上酷炫的初音未来音乐游戏?
  • 记一次删除Git记录中的大文件的过程
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 聊聊flink的BlobWriter
  • 前端设计模式
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 最简单的无缝轮播
  • 国内开源镜像站点
  • 函数计算新功能-----支持C#函数
  • # 安徽锐锋科技IDMS系统简介
  • #Ubuntu(修改root信息)
  • (备忘)Java Map 遍历
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • (二)fiber的基本认识
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (六)Hibernate的二级缓存
  • (三分钟)速览传统边缘检测算子
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)、python程序--模拟电脑鼠走迷宫
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (自用)仿写程序
  • .net 7 上传文件踩坑