Python编程学习-基础笔记04

六、函数

6.1 函数基础

6.1.1 函数定义

''''
函数:复用
格式:
def 函数名([参数],...)
    代码

sample:
def get_name():
    pass
def search():
    pass

代码:
    封装重复内容
函数调用:函数名()
'''
import random
def gernerate_code():
    # 定义一个空字符串
    ver_code = ''
    # 准备一个字符串,包含字母和数字
    source = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890'
    for i in range(4):
        # 可以直接随机取一个字符
        r = random.choice(source)
        # 将每次获取到的值拼接为4为的字符串
        ver_code += r
    print(ver_code)

print(gernerate_code) #<function gernerate_code at 0x0000020BCFE3C2F0>
'''
定义一个login函数
用户名:admin,密码:123456
验证用户名和密码是否正确
'''
def login():
    while True:
        #输入用户名或手机号
        login_name = input("请输入用户名/手机号:")
        passwd = input("请输入密码:")
        if login_name == 'admin' and passwd == '123456':
            break
            print('登录成功')
        else:
            print('用户名或密码有误,请重新输入')

#验证函数是否可用?调用函数
gernerate_code()
login()

6.1.2 带参数的函数

'''
参数:
    1,无参数
    2,有参数
无参数:
def 函数名()
    代码
有参数:
def 函数名(参数1,参数2,...)
    代码
参数就是在调用函数时,往函数体内传值
默认值参数:在定义函数的时候,有一个或多个参数已经赋值好
    def 函数名(参数1,参数2,参数3=值,参数4=值):
        pass
    调用特点:
        函数名(值1,值2,值3)
    注意:
        定义函数时,普通参数要位于默认值参数前面
        调用时,默认参数顺序时定义时的顺序,可以指定关键字参数赋值,改变顺序
'''
#login 带参数,n表示允许输入的错误此次数
def login(n):
    m =0
    while m < n:
        m += 1
        #输入用户名或手机号
        login_name = input("请输入用户名/手机号:")
        passwd = input("请输入密码:")
        if login_name == 'admin' and passwd == '123456':
            break
            print('登录成功')
        else:
            print('用户名或密码有误,请重新输入')
#数字累加函数1 - n
def accumulation(n):
    sum = 0
    m = 0
    while m <= n:
        sum += m
        m += 1
    print(sum)

#带默认值的函数,number和school带默认值,不传入参数时,使用默认值
def borrow_book(bookname,username,number=1,school='天大'):
    print(f'欢迎进入{school}借书系统>>>>>>')
    print(f'{username}借阅了{bookname},共{number}本')
#函数调用
# login(3)
accumulation(10)
borrow_book('Forrest','红楼梦') #红楼梦借阅了Forrest,共1本
borrow_book(username='Forrest',bookname='红楼梦') #Forrest借阅了红楼梦,共1本
borrow_book('Forrest','红楼梦',2) #红楼梦借阅了Forrest,共2本
#普通参数也带上关键字后,默认参数不能直接给值
borrow_book(username='Forrest',bookname='红楼梦',number=2,school='北大') #SyntaxError: positional argument follows keyword argument

可变参数:参数类型为列表,元组和集合

'''
参数类型:
1,列表
2,可变参数:
    *args
    **kwargs
3,装包和拆包 --> 对应可变参数
    装包:函数装包的过程,定义函数是,参数加星*
    def 函数(*args): --> 此时函数会出现装包
        pass
    拆包:函数拆包的过程,调用函数时,参数加星*, 拆列表,元组和集合
    调用函数时:
        函数(*list) | 函数(*tuple) |函数(*set)
'''
#验证示例讲解
#参数和变量个数相等
a,b,c = 1,2,3
print(a)
print(b)
print(c)
#参数和变量个数不等,带星号的表示一个容器,多余的参数都给带星的
a,*b,c = 1,2,3,4,5,
print(a)
print(b) #[2, 3, 4]
print(c)
#参数和变量个数不等,带星号的表示一个容器,多余的参数都给带星的
*a,b,c = (1,2,3,4,5)
print(a) #[1, 2, 3]
print(b)
print(c)
#参数类型为列表
list1 = [1,5,66,34,22,7,77,89,100,25,50]
#从列表中删除小于50的数,list_1-->形参,可以随便定义
def del_from_list(list_1):
    n = 0
    while n < len(list_1):
        if list_1[n] < 50:
            list_1.remove(list_1[n])
        else:
            n += 1
    print(list_1)
#可变参数,重写求和函数,*星号是关键,装包,之后的变量名可以任意,但通常用args
def get_sum(*args):
    s = 0
    for i in args:
        s += i
    print(s)
#函数调用,list1 实参
del_from_list(list1)
get_sum(1,2) #参与会以元组的形式赋值给变量
get_sum(1,2,3,4,5)
#调用是加*,星号表示拆包
get_sum(*list1) #382

可变参数:带2颗星的情况, 同时有1颗星 和2颗星的情况

'''
可变参数:**kwargs, 关键字参数
在函数调用时必须传递关键字参数,才可以转换为key:value,装载到字典中
'''
#key word
def show_book(**kwargs):
    print(kwargs)

#同时带了*args 和 **kwargs
def show_story(*args,**kwargs):
    print(args) #()
    print(kwargs) #{}
#调用函数
show_book() #{}
# show_book('红楼梦') #TypeError: show_book() takes 0 positional arguments but 1 was given
#可以加多个关键参数
show_book(bookname='红楼梦',author='曹雪芹') #{'bookname': '红楼梦', 'author': '曹雪芹'}
#拆包,必须加2颗星
book = {'bookname': '红楼梦', 'author': '曹雪芹'}
show_book(**book) #{'bookname': '红楼梦', 'author': '曹雪芹'}

#带* ** 的情况
show_story('小红','小花') #('小红', '小花')
show_story('小红','小花', story='星际联邦')
'''
('小红', '小花')
{'story': '星际联邦'}
'''
#字符拼接,'-' 以此为分隔符
result = ''.join(['a','b','c'])
print(result) #abc
result = '-'.join(['a','b','c'])
print(result) #abc

6.2 函数应用

6.2.1 函数注释

'''
在函数体内加上注释,给使用函数的人以提示信息
'''

6.2.2 函数返回值

return 会结束函数调用,并返回值。return不仅会结束循环,还会结束函数

'''
参数:外界向函数内传值
返回值:函数里面的内容值向往传递
def function():
    ...
    return xx
当函数调用时,通过return向往返回值
注意: 只有函数有返回值,外部需要有变量来接收
     return 后可跟一个或多个值,逗号分隔
     如果时多个值,返回的是一个元组,多个值被封装在元组中
        示例: retur a,b,c
            结果 (a,b,c)
'''
#将计算结果作为返回值,返回一个值
def get_sum(*args):
    s = 0
    for i in args:
        s += i
    #返回计算结果
    return s

#返回多个值
def get_max_min(numbers):
    #先排序:冒泡排序
    for i in range(len(numbers)-1):
        for j in range(0,len(numbers)-1-i):
            if numbers[j]>numbers[j+1]:
                numbers[j],numbers[j+1] = numbers[j+1],numbers[j]
    #获取头和尾
    min = numbers[0]
    max = numbers[-1]
    #返回
    return min,max
#在外部定义一个变量total来接收函数的返回值
total = get_sum(1,2,3,5)
x = 100
x = x + total
print(x) #111

list1 = [3,8,6,11,25,43,66,89,36,77,99,66]
#return返回2个值(min,max),使用2个变量来接收
min,max = get_max_min(list1)
print(min,max)

6.3 函数高级

6.3.1 全局变量和局部变量

全局变量:声明在函数外部的变量
局部变量:声明在函数内部的变量,使用范围仅限于函数内部

'''
全局和局部变量:
    全局变量:声明在函数外部的变量
    局部变量:声明在函数内部的变量,使用范围仅限于函数内部
    注意:
        函数内部可以直接使用全局变量,但是不能直接修改全局变量
        如果想修改全局变量,则必须使用关键字 global
    global 关键字的添加:
'''
a = 100
def test1():
    #局部变量,函数优先使用
    a = 0
    b = 8
    print('a = ',a)
    print('b = ',b)
def test2():
    #局部变量,函数优先使用,如果函数体内定义的同名的变量
    b = 8
    #这里取到的a就是全局变量a
    print('a = ',a)
    print('b = ',b)
def test3():
    #声明a为全局变量
    global a
    #如果部声明a为全局变量,函数内部无权操作a
    a -= 10
    #这里取到的a就是全局变量a
    print('a = ',a)
#函数调用
test3()
test1()
test2()

6.3.2 可变和不可变类型

'''
全局和局部变量:
global 关键字的添加:
    只有不可变的类型,才需要添加关键字global
    可变类型,不需要添加关键字global
可变和不可变类型:
    不可变:当改变变量值时,地址发生了改变
        类型:int, str,float,bool, tuple
    可变:内容发生改变,但是地址没有发生改变
        类型:list, dict, set
'''
#可变变量
library = ['红楼梦','水浒传','西游记','三国演义']
print(id(library)) #2425797567112
library.append('窦娥冤')
print(id(library)) #2425797567112
#不可变变量
a = 100
print(id(a)) #140712806182832
a = 80
print(id(a)) #140712806182192
s = 'abc'
print(id(s)) #1698608322912
s = 'def'
print(id(s)) #1698608946848
t1 = (1,2,3)
print(id(t1)) #1908556126968
t1 = (1,2,3,4)
print(id(t1)) #1908556105112
#添加图书
def add_book(bookname):
    if bookname not in library:
        library.append(bookname)
        print(f'{bookname}添加成功')
    else:
        print('此书已经存在')
#展示全部图书
def show_books(books):
    for book in books:
        print(book)
#函数调用
add_book('西厢记')
show_books(library)

6.3.3 引用及参数值传递

'''
引用:
1,不是在函数中使用,可以通过sys.getrefcount(a)查看引用个数
    del 变量名 --> 表示删除了一个引用
2,函数的引用:
    必须要分清传递的值是可变还是不可变类型
    如果可变,里面发生改变,外层可以看到改变后的内容
    如果是不可变,里面发生改变,不会影响外部的变量值
'''
import sys

list1 = [1,2,3,4,5]
list2 = list1 #list1 将其引用地址给list2赋值
list3 = list1
#获取变量被引用的次数,这里查的是地址
print(sys.getrefcount(list1)) #4
del list2
print(sys.getrefcount(list1)) #3

def test(n1):
    #n1是局部变量
    for i in range(n1):
        print('--->',i)
    n1 += 1  # 这里改变的只是局部变量的值

n = 9
#调用test
test(n)
print(n) #9

def test1(l):
    #判断传入的是列表
    if isinstance(l,list):
        for i in l:
            print(i)
        #在第0个位置插入新的值
        l.insert(0,8) #可变参数,改变的是全局参数值
    else:
        print('不是列表类型')

#调用test1
test1(list1)
print(list1) #[8, 1, 2, 3, 4, 5]

6.3.4 练习:停车计费系统

'''
停车计费数据结果:
[{'车牌':[进入时间,0]},{'车牌':[进入时间,出场时间]}]
15分钟 1元
1小时 4 元

停车场变量--> 全局变量
'''
import  random
#初始化停车场数据
car_park = []
#记录车辆入场停车,车牌和时间
def veh_enter():
    print('欢迎进入AAA停车场')
    plate = input('请输入车牌号:').strip()
    #构建结构{'车牌':[0,5]}
    car = {}
    car[plate] = [0]
    #添加到car_park
    car_park.append(car)
    print(f'欢迎{plate}入场停车!')
#记录车辆出场,车牌和时间
def veh_exit():
    #出场扫描
    plate = input('请输入车牌号:').strip()
    #判断此车是否有入场记录
    for car in car_park:
        if plate in car:
            #记录出场时间
            time = random.randint(0,24)
            time_record = car.get(plate)
            time_record.append(time)
            #计算费用,退出循环
            total = time * 4
            print(f'{plate}停车{time}小时,应缴费:{total}元')
            break
    else:
        print(f'{plate}没有入场记录!')
#调用
veh_enter()
veh_exit()

6.4 闭包

函数只是一段可执行代码,编译后就固化了,每个函数在内存中只有一份实例,得到函数入口点便可执行。函数还可以嵌套函数,即函数内部可以定义另一个函数,这就会产生闭包的问题。

'''
函数嵌套:
变量查找顺序:内层函数 --> 外层函数 --> 全局 --> 系统 builtins
闭包:
1,是嵌套函数
2,内部函数引用了外部函数变量
3,返回值是内部函数
'''
#嵌套
def outer():
    a = 100
    def inner():
        b = 200
        # b += a  #内部函数可以使用外部函数的变量,但是不能改变外部变量
        #如果想修改外部变量,需要在内部函数中加上: nonlocal
        nonlocal a
        a += b #内部函数不能改变外部变量
        print('这是内部函数',b)
    result = locals() #locals()表示查看函数中的局部变量,以字典形式返回
    print(result) #{'a': 100, 'inner': <function outer.<locals>.inner at 0x000001E39698E730>}
    #调用inner
    inner() #这是内部函数 300
#函数调用
outer()

#闭包 = 函数块 + 引用环境
def outer1(n):
    a = 10
    def inner():
        b = a + n
        print('内部函数:',b)
    return inner

r = outer1(5)
print(r) #<function outer1.<locals>.inner at 0x0000020177D0E7B8>
r() #内部函数: 15

6.5 装饰器

6.5.1 装饰器基础

'''
装饰器:
遵循开放封闭原则,在不改变原函数的情况下,扩展了函数功能
定义:
def xxx(func):
    def xxx():
        ...
        func()
        ...
        return xxx
    return yyy
装饰:
@装饰器名  #原函数 = 装饰器名(原函数)
def 原函数():
    pass
功能:
1,引入日志
2,函数执行时间统计
3,执行函数前的预备处理
4,执行函数后的清理功能
5,权限校验等场景
6,缓存
'''
#定义一个装饰器
def decorator(func):
    print('------------->1')
    def wraper():
        func() # 先执行外部函数 house
        print('刷漆')
        print('铺地板')
        print('软装')
        print('精装房')
    print('------------->2')
    return  wraper

@decorator #开始调用decorator,house = decorator(house) 先执行打印 ------------->1 ------------->2
def house(): #将house作为变量传入,类似 func = house
    print('毛坯房')
#调用函数
house()
'''
执行结果:
------------->1
------------->2
毛坯房
刷漆
铺地板
软装
精装房
'''

6.5.2 带参数的装饰器

'''
带参数的装饰器:
如果原函数有参数,装饰器内部也要有参数
'''
#定义一个装饰器,*args,**kwargs 可以接任意变量
def decorator(func):
    def wraper(*args,**kwargs): #address = ’北京‘,*args是一个元组
        func(*args,**kwargs) # func 就是 house
        print('刷漆')
        print('铺地板')
        print('软装')
        print('精装房')
    return  wraper

@decorator #开始调用decorator
def house(address): #将house作为变量传入,类似 func = house
    print(f'位于{address}的毛坯房')

@decorator #开始调用decorator
def workplace(address,area):
    print(f'位于{address}的毛坯房,面积{area}平米')

@decorator #开始调用decorator
def hotel(name,address,area=40):
    print(f'{name}酒店,位于{address}的毛坯房,单间面积{area}平米')
#调用函数
house('北京') # house 就是 wraper

workplace("北京通州",1000)

hotel('全季',address='北京') #如果没有**kwargs 运行会报错

6.5.2 带返回值的装饰器

'''
装饰器修饰有返回值的函数:
原函数有返回值,装饰器内部函数也需要返回值
'''
#定义一个装饰器,*args,**kwargs 可以接任意变量
def decorator(func):
    def wraper(*args,**kwargs): #address = ’北京‘,*args是一个元组
        r = func(*args,**kwargs) # func 就是 house
        print(f'预计费用是:{r}元')
        print('刷漆')
        print('铺地板')
        print('软装')
        print('精装房')
        return 60000 # 原函数有返回值,wrapper也需要返回值
    return  wraper
@decorator #开始调用decorator
def house(address): #将house作为变量传入,类似 func = house
    print(f'位于{address}的毛坯房')
    return 50000
#调用函数
house('北京') # house 就是 wraper

6.6 递归函数

如果一个函数在内部不调用其他任何函数,而是自己本身的话,这个函数就是递归函数。

'''
如果一个函数在内部不调用其他任何函数,而是自己本身的话,这个函数就是递归函数
遵循:
1,必须要有出口
2,每次递归,要向出口靠近

'''
#
def test():
    print('----------test-----------')
    # 调用a()
    a()

def a():
    print('----------aaaa-----------')
    #调用a()
    a()


# 调用a()
# a()

#打印数字1-10,递归函数实现
def num(i):
    if i == 10:
        print(i)
    else:
        print(i)
        i += 1
        num(i)

#调用num(),从1开始
# num(1)

#数字1-10的累加和,递归函数实现
total = 0
def sum(i):
    global total
    if i == 11:
        print('over',total)
    else:
        total += i
        i += 1
        sum(i)
#使用返回值求累加
def sum1(i):
    if i == 10:
        return 10
    else:
        return i + sum1(i+1)  # 逐层向下递归,但是到最后i=10之后才有返回,然后再逐层返回值进行计算
#调用sum(),从1开始
# sum(1)

r = sum1(1)
print(r)

6.7 匿名函数

6.7.1 匿名函数定义

'''
用lamda关键词可以创建小型匿名函数,省略了def声明函数的标准步骤
匿名函数定义格式:
lamda 参数列表:返回值表达式
'''
#定义标准函数
def test(a):
    return a+1
#使用变量来接收函数返回值
result = test(5)
print(result)

#定义匿名函数,由于没有函数名,使用r来接收
r = lambda a:a+1
result = r(6)
print(result)

#定义匿名函数,多个参数
r = lambda x,y: x+y
result = r(6,7)
print(result)

6.7.2 匿名函数的使用场合

'''
匿名函数的使用场合:
匿名函数作为参数来使用
'''
#定义标准函数
def test():
    print('------test------')
def func(a,f):
    print('--------->',a)
    f()
#使用变量来接收函数返回值
func(5,test)

def func1(a,f): #lambda x:x**2
    print('>>>>>>>>>>',a)
    r = f(a)
    print('=====>',r)

#调用func1,因为f带返回值,这里用匿名函数来赋值,多数情况,匿名函数放在参数位置
func1(8,lambda x:x**2)

6.8 高阶函数

函数可以作为变量来使用。既然变量可以指向函数, 函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数。同样,可以把一个函数作为另一个函数的返回值。这种函数的使用方式,称之为高阶函数。

'''
高阶函数:
    一个函数的参数是另一个函数
系统高阶函数:
    max,min,sorted, filter,map,reduce
'''
#普通查找最大值
from functools import reduce

m = max(5,6)
print(m)

#列表内查找最大值
m = max([2,5,8,3,11,56,39,22])
print(m)

#匿名函数,找最大年龄
list1 = [('Lily',25),('Tony',19),('Jessy',21),('Tomas',28),('Lucy',26),('Rose',29)]
m = max(list1,key= lambda x:x[1])
print(m)

#找最小年龄
m = min(list1,key= lambda x:x[1])
print(m)

#按年龄排序
m = sorted(list1,key= lambda x:x[1])
print(m) #[('Tony', 19), ('Jessy', 21), ('Lily', 25), ('Lucy', 26), ('Tomas', 28), ('Rose', 29)]

#按年龄排序,倒序
m = sorted(list1,key= lambda x:x[1],reverse=True)
print(m) #[('Rose', 29), ('Tomas', 28), ('Lucy', 26), ('Lily', 25), ('Jessy', 21), ('Tony', 19)]

#过滤 大于20岁的,lambda 返回值是真或假,返回值必须是bool类型,结果为True才符合过滤条件
m = filter(lambda x:x[1]>20,list1)
print(m) #<filter object at 0x0000020A2EDED748>, 返回的是可迭代对象
#将m强转为list
print(list(m)) #[('Lily', 25), ('Jessy', 21), ('Tomas', 28), ('Lucy', 26), ('Rose', 29)]

#映射map,通过匿名函数指明提取内容,并对内容进行加工
ma = map(lambda x:x[1]+1,list1)
print(ma) #<map object at 0x000001FF6FCEE710>
print(list(ma)) #[26, 20, 22, 29, 27, 30]

ma = map(lambda x:x[0].title(),list1)
print(ma) #<map object at 0x0000013E7233E860>
print(list(ma)) #['Lily', 'Tony', 'Jessy', 'Tomas', 'Lucy', 'Rose']

#reduce,对一个序列进行压缩运算,最后得到一个值
r = reduce(lambda x,y:x+y,[1,2,3,4,5])
print(r) #15
posted @ 2022-06-27 20:03  逆流的鱼2016  阅读(236)  评论(0编辑  收藏  举报