python05- 函数、time

1、函数

1.1、函数的用处复用(一块业务需要反复的实现,每次使用这个业务都需要写一摸一样的代码框架,为了提到代码的简洁性跟提升编写速率,把这种需要使用多次的,相同逻辑业务的代码村放在函数中,如果要使用,直接点用这个函数,传递给这个函数不同之处的变量,即可实现,一段代码多次利用)

1.2、格式:

def 函数名()     # 无参函数
    代码

def 函数名([c参数,...])   # 有参函数
    代码

1.3、函数名命名规则,没有硬性要求,但建议如下:

一个单词,使用小写即可 search()
多个单词不需要大写,使用_分割  get_name()

1.4、定义函数名,相当于栈中定义一个变量。
在函数中定义代码,相当于在堆中定义一个(id value type) 。
所以打印函数名,就会显示函数跟那个堆中的id做绑定,而id是一个十六进制的数。

1.4、验证函数是否可用,调用函数

调用函数模板:函数名() 
解释:() 表示获取函数名绑定的 id 地址

用一个案例:封装生成4位二维码函数,作函数的调用

import random


def validation_code():
    s = '12334567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHKJLZXCVBNM'
    code = ''
    for i in range(4):
        r = random.choice(s)
        code += r
    print(code)


validation_code()

如何知道,我们是否执行了函数中的代码,通过在  函数代码 中加 断点

1.5、带参数函数

def validation_code(n):
    s = '12334567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHKJLZXCVBNM'
    code = ''
    for i in range(n):
        r = random.choice(s)
        code += r
    print(code)


validation_code(6)

1.6、多参数函数

def validation_code(a, b):
    if a == b:
        print('{}和{}是相等的'.format(a, b))
    else:
        print('{}和{}是不相等的'.format(a, b))


validation_code(7, 7)

1.7 、默认值参数

如果定义一个带有参数的函数,参数是几个,调用的实参就有几个,否则报错

需求:有一个参数非特殊情况,都是固定不变的,只有在特殊的情况才会不一样,由于调用的实参必须跟形参对等,所以这个默认数值每次都的写,如果简化?默认值参数 def 函数名(参数1,参数2,默认值) ,并且可以对默认值进行赋值,取消默认值,使用自定值。如下,我想对比 a b 是不是相等,而且a 是不是大于2 

def validation_code(a, b, c=2):
    if a == b and a > c:
        print('{}和{}是相等的,而且{}大于{}'.format(a, b, a, c))
    else:
        print('{}和{}是不相等的'.format(a, b))


validation_code(7, 7)

我想对比 a b 是不是相等,而且 a 是不是大于3 

def validation_code(a, b, c=2):
    if a == b and a > c:
        print('{}和{}是相等的,而且{}大于{}'.format(a, b, a, c))
    else:
        print('{}和{}是不相等的'.format(a, b))


validation_code(7, 7, 3)

注意:默认值参数可以定义多个,但是所有参数在,所有默认值参数之前,否则语法报错。

1.8 形参实参赋值

函数 () 括号中的参数叫做形参
调用函数() 括号中的参数叫做实参

默认不指定,形参1 = 实参1  形参2= 实参2  形参3= 实参3 .....

def validation_code(a, b):
    print("a=%s" % a)
    print("b=%s" % b)


validation_code(3, 1)

指定,实参1=形参2   实参2=形参1.....

def validation_code(a, b):
    print("a=%s" % a)
    print("b=%s" % b)


validation_code(b=3, a=1)

1.9 参数类型

参数可以是整型、字符型、浮点型、元组、列表、集合、字典等等

制作一个函数,通过外部传递一个列表,筛选出大于50的数字,并打印此列表

list = [12, 34, 14, 634, 123, 53]


def get_list(a):
    new_list = [i for i in a if i > 50]
    print(new_list)


get_list(list)

制作一个函数,通过外部传递一个列表,筛选出大于 50 的数字,并在原列表中移除

list = [12, 34, 14, 634, 123, 53]


def get_list(a):
    for i in a[::-1]:
        if i > 50:
            a.remove(i)
    print(a)

1.10 可变参数(一个*)

*args   **kwargs  这种的带有 * 叫做可变参数,比如  len 

 

可变参数有什么用,怎么用?

1、我们知道,形参跟实参必须对等,但如果形参中使用可变参数,代表实参不管是多少,统一用可变参数代替,可以理解为*后的元素代表是的是一个容器 ,其中可以存放任何元素,并将其存入元组中

list1 = [12, 34, 14, 634, 123, 53]


def get_list(*a):
    print(a)


get_list(1, 2)
get_list(list1)

2、参数+可变参数 搭配

python 支持按照逗号隔开赋值方法,其中*元素,可以按照格式匹配多数值,并存入列表中。注意a, *b, c = 1, 2, 3, 4, 5这种形式是存入列表中。而可变参数 *args  是转成成元组

a, b, c = 1, 2, 3
print(a)  # 1
print(b)  # 2
print(c)  # 3 
a, *b, c = 1, 2, 3, 4, 5
print(a)  # 1
print(b)  # [2, 3, 4]
print(c)  # 5

对于函数来说也是一样的,函数中也可以使用,参数+可变参数 搭配

list1 = [12, 34, 14, 634, 123, 53]


def get_list(a, *b):
    print(a)
    print(b)


get_list(1, 2, 3, 4)   # 按照顺序a = 1  随后使用 *b 去接收 2, 3, 4
get_list(list1) # 由于 list1 赋值给了 a ,导致 *b 接收了 空

1.11 拆包、封包

*a, b, c = 1, 2, 3, 4, 5
print(a)  # [1, 2, 3]
print(b)  # 4
print(c)  # 5

a, b, c = (1, 2, 3)
print(a)  # 1
print(b)  # 2
print(c)  # 3 

其中 *a = [1, 2, 3]  为封包,将 1 2 3 元素封装成一个列表,给*a
其中a, b, c = (1, 2, 3) 为拆包,将一个元组中的数据,拆开按照需求一一对应的赋值

a, b, *c = (1, 2, 3, 4)
print(a)  # 1
print(b)  # 2
print(c)  # [3, 4]

拆包、封包 同时进行

案例:求元素的和

def get_list(*sum):
    print(sum)
    s = 0
    for i in sum:
        s += i
    print("元素的和是%s:" % s)


get_list(1, 2, 3, 4, 5) 

案例:求列表中元素的和

将上述案例,换成列表,会发现报错,主要因为是将 get_list (list1)  ,传入的是一个列表,将这个列表整体存在元组中,列表不能进行 + 操作,所以我们要进行干预,对其拆包

python 函数中,定义函数中 def  get_list(*sum) ,一个*,代表对传入过来的数据,进行封包成一个元组。
在定义函数中 get_list(*list1) ,*list1  这个 * 代表的是对其拆包,拆的是原数据 list 。注意 * 拆的是列表、元组、集合等

还是上述的案例,我们可以使用get_list(*list1) ,将 list1 拆包成 12, 34, 14, 634, 123, 53 ,然后在通过def  get_list(*sum) 封装成元组(12, 34, 14, 634, 123, 53) 

list1 = [12, 34, 14, 634, 123, 53]


def get_list(*sum):
    print(sum)   #
    s = 0
    for i in sum:
        s += i
    print("元素的和是%s" % s)


get_list(*list1)

1.12 可变参数(二个*)

通过如下可知,** 代表不是元组了,而是{} ,大括号不是字典就是集合

def show_book(**kwargs):
    print(kwargs)

show_book()  # 返回 {} ,代表不是字典就是集合
show_book(1) # 报错
show_book('书') # 报错
show_book('书', 123) # 报错

通过上述,如果是集合,传入一个不重复的元素,就不会被报错,所以另一种可能就是传入的是字典,如下,传入key value,所以 ** 代表是字典 ,必须使用关键字参数赋值

def show_book(**kwargs):
    print(kwargs)


show_book(bookname='书', price=123)  # {'bookname': '书', 'price': 123}

既然是字典就可以用字典的形式打印

def show_book(**kwargs):
    print(kwargs)
    for k, v in kwargs.items():  # 使用 k ,v 形式获取key 或者 value,使用items遍历打印
        print(k, v)


show_book(bookname='书', price=123)  # {'bookname': '书', 'price': 123}

注意 * 拆的是列表、元组、集合等,** 是拆字典

book = {'bookname': '书', 'price': 123, 'num': 5}


def show_book(**kwargs):
    print(kwargs)
    for k, v in kwargs.items():  # 使用 k ,v 形式获取key 或者 value,使用items遍历打印
        print(k, v)


show_book(**book)

python 函数中,定义函数中 def  get_list(*sum) ,一个*,代表对传入过来的数据,进行封包成一个元组。** 代表对传入过来的数据,进行封包成一个字典
在定义函数中 get_list(*list1) ,*list1  这个 * 代表的是对其拆包,拆的是原数据 list 。注意 * 拆的是列表、元组、集合等,** 是拆字典

1.13 可变参数 (一个*二个*) 同时存在

同时存在,意义不变,* 就是元组 ,* 就是字典  ,可以传递空,打印空元组,空字典

def show_book(*args, **kwargs):
    print(args)  # 元组
    print(kwargs)  # 字典


show_book()

可以给一个传递,另一个不传递,则另一个打印空

def show_book(*args, **kwargs):
    print(args)  # 元组
    print(kwargs)  # 字典
    print("\n")


show_book('你好', '世界')
show_book(bookname='书', price=123)

可以随意组装,调用,结果都是一样的

def show_book(*args, **kwargs):
    print(args)  # 元组
    print(kwargs)  # 字典
    print("\n")


show_book('你好', '世界', bookname='书', price=123)

book = {'bookname': '书', 'price': 123}
show_book('你好', '世界', **book)

name = ['你好', '世界']
show_book(*name, bookname='书', price=123)

name = ['你好', '世界']
show_book(*name, **book)

*args[]  和**kwargs 统称为不定长参数

1.14 返回值

参数是指,外界往函数里面传递数值,而返回值,代表将函数执行的结果的某一个数值,返回给调用着。

默认格式(返回单一数值):

def get_sum(*args):    # 
    total = 12
    return total  # 定义要返回的元素

x = get_sum(1, 2, 3)  # 丁定义让x接收返回的元素

案例1:

def get_sum(*args):
    total = 0
    for i in args:
        total += i
    return total


x = get_sum(1, 2, 3)
print(x)

案例2:返回多个数值,如下可以得知 return min, max 返回的是两个数值,用 result 接收后,是一个元组

def get_maxadmin(numbers):
    for i in range(0, 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]
    print(numbers)
    return min, max


list1 = [12, 35, 21, 12, 63, 23, 63, 12]
result = get_maxadmin(list1)
print(result)

而我们知道,元组中的数据,可以通过  变量1,变量2 = ( 元素1,元素2)  ,进行赋值

进而将代码简写

def get_maxadmin(numbers):
    for i in range(0, 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]
    print(numbers)
    return min, max


list1 = [12, 35, 21, 12, 63, 23, 63, 12]
a, b = get_maxadmin(list1)
print(a)
print(b)

返回多个数值的格式为:

def get_sum(*args):
    a += 1
    b += 1
    return a, b

c, d = get_sum(1, 2)

1.15 一个函数体调用另一个函数体

案例:自定义登录功能islogin函数体,参数是username, password。自定义图书借阅系统功能boorrow_book函数体,其功能为,先通过islogin函数体正常登录,则可以图书借阅。
思路:通过定义boorrow_book函数体,先让用户输入账户、密码,后调用islogin函数体判断是不是为真,如果为真,则打印可以借阅。

def islogin(username, password):
    if username == 'admin' and password == '123456':
        print('登录成功')
        return True
    else:
        print('登录失败,请检查用户名密码')
        return False


def boorrow_book(book_name):
    username = input('输入用户名:')
    password = input('输入密码:')
    if islogin(username, password):
        print('借阅成功{}'.format(book_name))


book_name = '三国'
boorrow_book(book_name)  # 输入要借阅的书

1.16 全局变量、局部变量

如下,如果要多次借书,每次都需要登录一下,如何实现一次登录,后不需要在登录

改变代码:

islogin = False


def login(username, password):
    if username == 'admin' and password == '123456':
        print('登录成功')
        islogin = True
        return islogin
    else:
        print('登录失败,请检查用户名密码')
        return False


def boorrow_book(book_name):
    if islogin:
        print('借阅成功{}'.format(book_name))
    else:
        username = input('输入用户名:')
        password = input('输入密码:')
        status = login(username, password)
        if status:
            print('借阅成功{}'.format(book_name))


while True:
    book_name = input('请输入要借阅的书:')
    boorrow_book(book_name)  # 输入要借阅的书

思考:登录成功后,已经通过 islogin = True 修改了 islogin 数值,怎么还是需要重新登录。添加print(islogin) ,在每次循环的时候打印islogin 数值,会发现,每次循环都是False , 说名什么,在函数体中,变量为局部变量,在函数体外的变量,为全局变量,局部变量无法修改全局变量。函数体只有读全局变量的权限,没有修改的权限 。如果全局变量、局部变量都定义了一个变量,则执行局部变量

如何修改全局变量:函数体可以通过 global 命令修改全局变量

格式:在函数体中,先执行   global  全局变量

islogin = False


def login(username, password):
    if username == 'admin' and password == '123456':
        print('登录成功')
        global islogin
        islogin = True
        return islogin
    else:
        print('登录失败,请检查用户名密码')
        return False


def boorrow_book(book_name):
    if islogin:
        print('借阅成功{}'.format(book_name))
    else:
        username = input('输入用户名:')
        password = input('输入密码:')
        status = login(username, password)
        if status:
            print('借阅成功{}'.format(book_name))


while True:
    print(islogin)
    book_name = input('请输入要借阅的书:')
    boorrow_book(book_name)  # 输入要借阅的书

(  执行: 局部变量 > 全局变量    权限:默认全局变量只能读,不能改 。 全局变量:函数体可以通过 global 命令修改全局变量)

1.17 案例停车场计费

停车计费系统:
进入停车场记录进入时间,如果出去则记录出去的时间,停车的时间:出去 - 进入时间
停车长数据结构:
[ { ’车牌‘ : [  进入时间 , 0 ] } , { ’车牌‘ : [  进入时间 , 出去时间 ] }  , ........  ]
计费规则: 15 分钟 1块    1 个小时 4 块  

知识点:使用 for in 循环遍历字典,取出的是 key 数值。time 取出的是时间戳

import random

car_park = []


def enter():
    print("-----环境来到停车场-----")
    while True:
        a = int(input("请输入要进入还是退出系统,1为进入,2为退出:"))
        if a == 1:
            number = input('您要从停车场进来,输入车牌号:')
            car = {}
            car[number] = [0]
            car_park.append(car)
            print("此车已进入")
        elif a == 2:
            break
        else:
            print("请输入1或者2,重新输入")
    print("当前一共有{}多少车辆".format(car_park))


def go_out():
    print("-----您要从停车场出去------")
    number = input('输入车牌号:')
    for car in car_park:
        print(car)
        if number in car:
            time = random.randint(0, 24)
            time_record = car.get(number)
            time_record.append(time)
            total = time*4
            print("{}车已经出场,信息是{},停车{},花费{}".format(number, car, time, total))
            break
    else:
        print("此车未进入场")


enter()
print("\n")
go_out()

1.18 多个return

一个函数中,同级别的只能有一个return,遇到第一个 return 后退出函数,return后的代码不会执行,所以 return 可以实现终止和退出循环功能

def creaate_muns():
    print("1")
    return 1
    print("2")
    return 2
    print("3")
    return 3

a = creaate_muns()
print(a)

 一个函数中,不同级别的可以写多个return

def creaate_muns(i):
    if i == 'a':
        return 1
    elif i == 'b':
        return 2


a = creaate_muns('a')
print(a)

1.19、缺省参数

函数调用是,缺省参数的值如果没有传入,则取默认值

def printinfo(name, age=35):
    print(name, age)


printinfo(name="nihao")   # nihao 35
printinfo(age=9, name="nihao")  # nihao 9
printinfo(age=10)   # 报错

1.20、可变类型、不可变类型

1、所谓可变类型与不可变是指,数据能够直接进行修改,叫可变。不能修改叫不可变
2、可变类型(修改数据,内存地址不会发生变化),列表、字典、集合。理解为移除一个列表中的元素,这个列表对应的堆中,会将对应的堆下得到value数值进行改动,不会从新生成一个新的id、value
3、不可变(修改数据,内存地址发生变化),数字、字符串、元组。理解为 a = ‘123’,字符串移除一个元素,对应的堆下,会重新生成一个新的id,存入你移除后的字符串,然后在赋值给变量a

1.21、引用和函数参数引用

引用:

什么是引用:查看的是当前堆中指定的 id 有多少个变量在与他连接

sys.getrefcount  # 使用sys.getrefcount()函数查看引用次数
import sys

list1 = [1,2,3,4,5,6]
list2 = list1
list3 = list1

print(sys.getrefcount(list1))

解释:list1  list2 list 3 都引用了这个堆中的id,所以为3次,而sys.getrefcount函数本身也引用了一次

执行del list3 后是多少,结果是3,因为现在是list1  list2  引用了这个堆中的id,所以为2次,而sys.getrefcount函数本身也引用了一次

import sys

list1 = [1,2,3,4,5,6]
list2 = list1
list3 = list1

print(sys.getrefcount(list1))

del list3
print(sys.getrefcount(list1))  

是先定义的list1 = [1,2,3,4,5,6],如果删除 list1,list2 list3  是依旧存在数据的,因为 list1 是变量,list2 = list1 已经将堆中的id赋值给了list2,结果就是3,因为 list2 list3 引用了这个堆中的id ,而sys.getrefcount函数本身也引用了一次

import sys

list1 = [1, 2, 3, 4, 5, 6]
list2 = list1
list3 = list1

del list1
print(list2)
print(sys.getrefcount(list2))

python 的垃圾回收,如果堆中的id,无任何指针指向(任何变量进行指向赋值),则会触发垃圾回收,进行回收垃圾

函数参数引用:

def test(n1):
    for i in range(n1):
        print('------', i)
    n1 += 1
    print(id(n1))

n = 9
test(n)
print(n)
print(id(n))
n += 1
print(n)
print(id(n))

通过上述得知n还是9,理解:n = 9 , test(n) 执行后,是将堆中的 9 的 id 给到了 test(n) 中的n,然后执行def test(n1): 将 id 给到了 n1 ,而通过  n1 += 1 后,由于整型是不可变类型,所以9+1=10,10会重新产生一个id,而之前的 n = 9 ,还是指向原来的 id 。之前说过,堆中池子,对于不可变类型,一个value 只有一个id,所以现在n1 = 10 ,n += 1 后 n = 10 , 所以他们的 id 一样

 对于可变类型,是可以改变的

a = [1, 2, 3]


def list1(l):
    l.pop()
    print(l)
    print(id(l))


list1(a)
print(a)
print(id(a))

1.22、函数嵌套、闭包

函数是一段可执行的代码,编译后就固化了(加载到内存中),每个函数在内存中只有一份实例,就是一个地址,得到函数的地址,就能执行函数,而函数中,可以存在另一个函数,这种嵌套的结构,就会出现闭包问题。

函数嵌套:

def outer():
    print("out")
    def inner():
        print("in")
    inner()

outer()

locals()   在函数中,用来查看内部的局部变量的和对应的堆中的 value ,故返回一个字典,所以通过如下案例,inner()函数中存在两个局部变量。其中 <function outer.<locals>.inner at 0x000001F0BC5AB640> 代表  id =  0x000001F0BC5AB640 在outer函数下,而且是locals代表(局部变量

def outer():
    a = 100

    def inner():
        b = 200
        print("in")

    print(inner)   #  <function outer.<locals>.inner at 0x000001F0BC5AB640>
    result = locals()
    print(result)     # {'a': 100, 'inner': <function outer.<locals>.inner at 0x000001F0BC5AB640>}


outer()

1、函数中在嵌套一个函数,被嵌套的函数里 (成为内部),是可以使用外部(上一层的函数)变量,但不能修改,类似全局跟局部变量。
2、而 global 是修改全局变量的,并不适用于这种,这种函数嵌套函数需要用nonlocal。

def outer():
    a = 100
    c = 200

    def inner():
        b = 200
        b += a
        nonlocal c
        c = 20
        print("in", b)  # in 300

    print(a)   # 100
    print(c)   # 200
    inner()
    print(c)   # 20


outer()

3、注意nonlocal修改的是你上一层函数的变量。

def outer():
    a = 1

    def inner():
        a = 2

        def iiner():
            nonlocal a
            a = 3
            print("3层a", a)

        iiner()
        print("2层a", a)

    inner()
    print("1层a", a)


outer()

4、golabl 可以适用于任何层级的函数嵌套中,比如函数1嵌套函数2,函数2嵌套函数3,在函数3中使用golabl可以修改全局变量,但注意在函数3中不要起全局变量的名字,否则golabl修改的是变量

a = 100

def outer():
    a = 200

    def inner():
        global a
        a -= 50
        print("内部", a)

    print(a)
    inner()

outer()
print(a)

闭包:

闭包需要满足一下条件才称之为闭包,闭包就是函数中,声明一个的内部函数,而这个内部函数必须先引出到函数体外进行操作后,在由函数执行这个,内部函数。所以需要满足。因为后续装饰器就这种需求,闭包没什么太大的意义

1、有嵌套函数
2、内部函数引用的外部函数的变量
3、返回值是内部函数

def outer(n):
    a = 10


    def inner():  # 嵌套函数,条件1
        b = a + n  # 使用了外部函数的a,条件2
        print('内部函数:', b)

    return inner  # 返回值是内部函数,条件3


r = outer(5)    # r 接收的是 outer 函数的 return ,也就是 return inner,而inner代表的inner函数的地址,所以 r 是 inner 函数的地址
print(r)   #  返回的的是inner的地址 <function outer.<locals>.inner at 0x000002BFB6D0B640>

r()  #  既然r 是 inner 函数的地址,所以直接执行 r 函数,就是调用def inner(),他们都是连接一个内存地址


解释:上述可以实现,内部函数 outer,不在内部调用 inner(),在外部用r() 调用 ,因为inner() 和 r() 都是同一个地址

其中如下可以简写

r = outer(5)
r()
# 写成
outer(5)()

1.23、装饰器

搭配闭包使用,装饰器让开发效率增加。可以理解为,我有一些代码,无任何问题,现在由需求,需要在这个代码上进行增加功能。但是由于之前代码无问题,所以不想直接在原有的代码上修改,这些原有的代码,就可以做成闭包,将函数中的函数拿出来,在外部赋值调用,这些代码,不对原有的代码修改。函数的代码是拿出来了,但是如何让他跟我后写的函数进行结合,使用装饰器。

简单的装饰器:

# 定义装饰器
def decorater(func):
    def wrapper():
        func()
        print("刷漆")
        print("装修")
    return wrapper

@decorater
def house():
    print("毛坯房")

@decorater
def house2():
    print("毛坯房2")

house()
house2()

解释:有一个装饰器代码,你想对那些函数,跟装饰器中的代码进行合并操作。如上,要对house house2 做 decorater 装修操作,如何实现?

简单的装饰器解析:

不执行 house() 发现执行了decorater() 函数中的内容,按道理,除非是执行decorater(),否则只是将函数def decorater(func):加到内存中。既然执行了,没有decorater(),说明是@decorater就是执行调用的

# 定义装饰器
def decorater(func):
    print('-----------1')

    def wrapper():
        func()
        print("刷漆")
        print("装修")

    print('-----------2')
    return wrapper

@decorater
def house():
    print("毛坯房")

我们知道了@decorater就是decorater()的作用

# 定义装饰器
def decorater(func):
    print('-----------1')

    def wrapper():
        func()
        print("刷漆")
        print("装修")

    print('-----------2')
    return wrapper


@decorater
def house():
    print("毛坯房")


house()

简单的装饰器解析流程:

1、函数从上倒下,先将 def decorater(func):  def wrapper(): 加载到内存中

2、执行 @decorater , 就相当于执行了decorater(),但是函数是def decorater(func):带有func的参数,于是将@decorater下的 def house(): ,也就是house函数的地址,赋值给了func。所以现在是 func = house 地址

3、紧接着执行 def decorater(func): 函数,打印 print('-----------1')  print('-----------2'),在执行return wrapper ,也就是返回wrapper 的地址,返回给谁呢?@decorater也没接收,装饰器返回给函数house ,也就是将wrapper 的地址赋值给了house函数的。所以其实 @decorater 等价于  house = decorater(house)

 4、执行house,由于上一步将wrapper 的地址赋值给了house函数的,所以你现在执行的house是执行的 wrapper函数,进入wrapper函数,先执行一次func()函数

5、记得在第二步的时候,func = house 地址,所以加一个(),其实就是执行的是原house()函数,所以打印 print("毛坯房")

6、紧接着执行如下

def wrapper():
    print("刷漆")
    print("装修")

装饰器的用途:

1、可以监控谁调用了这个函数,在装饰器中记录
2、函数执行时间统计,比如这个函数执行了多久,装饰器执行前跟执行后的差值
3、执行函数前的准备、清理、权限校验、
4、缓存,将日志缓存到redis、monago

带参数的装饰器:

如果被修饰的函数 house ()有参数,func () 必须也要添加参数,因为 func = house 地址。而由于house = wrapper 地址 ,所以 wrapper  也要添加参数

# 定义装饰器
def decorater(func):
    print('-----------1')

    def wrapper(address):
        func(address)
        print("刷漆")
        print("装修")

    print('-----------2')
    return wrapper


@decorater   # house = decorater(house)
def house(address):
    print("房子的地址是{},是一个毛坯".format(address))

house('beijing')

如果存在多个参数呢?使用可变参数

# 定义装饰器
def decorater(func):
    print('-----------1')

    def wrapper(*args):
        func(*args) 
        print("刷漆")
        print("装修")

    print('-----------2')
    return wrapper


@decorater  # house = decorater(house)
def house(address):
    print("房子的地址是{},是一个毛坯".format(address))

@decorater
def dahouse(address, area):
    print("房子的地址是{},是一个毛坯,建筑面积{}".format(address, area))


house('beijing')
dahouse('beijing', 123)

那如果一个函数还有关键字参数?key:value,可变参数(二个*),所以万能模板

# 定义装饰器
def decorater(func):
    print('-----------1')

    def wrapper(*args, **kwargs):
        func(*args, **kwargs)
        print("刷漆")
        print("装修")

    print('-----------2')
    return wrapper


@decorater  # house = decorater(house)
def house(address):
    print("房子的地址是{},是一个毛坯".format(address))


@decorater
def dahouse(address, area, a=100):
    print("房子的地址是{},是一个毛坯,建筑面积{},a的数值{}".format(address, area, a))


house('beijing')
dahouse('beijing', 123)

带返回值的装饰器

# 定义装饰器
def decorater(func):

    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        print('预计装修费用:{}元'.format(r))
        print("刷漆")
        print("装修")

    return wrapper

@decorater
def house():
    print("我一个毛坯")
    return 50000

house()

 

注意: 此时的r = house(),是 r = wrapper ,所以没有返回数值

# 定义装饰器
def decorater(func):

    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        print('预计装修费用:{}元'.format(r))
        print("刷漆")
        print("装修")

    return wrapper

@decorater
def house():
    print("我一个毛坯")
    return 50000

r = house()
print(r)

# 定义装饰器
def decorater(func):

    def wrapper(*args, **kwargs):
        r = func(*args, **kwargs)
        print('预计装修费用:{}元'.format(r))
        print("刷漆")
        print("装修")
        return 10000

    return wrapper

@decorater
def house():
    print("我一个毛坯")
    return 50000

r = house()
print(r)

装饰器添加参数

# 定义装饰器
def decorater(func):
    print('-------1-------')

    def wrapper(action):
        print('-------3-------')

        def do_action(action):
            if func < 22
            return action

        print('-------4-------')
        return 10000

    print('-------2-------')
    return wrapper


@decorater(23)
def house():
    return 50000

执行流程:

1、执行 @decorater(23)  ,23 赋值给 func,随后打印print('-------1-------')   print('-------2-------')  return wrapper 将 warpper 的地址返回给谁呢?
2、此时的 return wrapper 返回地址,其实是继续调用wrapper() 函数,具体为什么这么写的,应该是底层写好的。随后执行def wrapper(action),而 action 参数是,@decorater(23)下的house对应的堆的地址,随后执行print('-------3-------') ,加载def do_action():  打印 print('-------4-------')
3、紧接着执行 return do_action ,然后将do_action的地址传递给了 house()。其中do_action (action): 下的 if func < 22 可以使用最外层的 def decorater(func):的func

总结:@decorater(23) 如何带参数,就会多了一轮调用

1.24、递归函数

反复调用自身函数,就是递归函数

要求:
1、必须有出口,否则会死循环
2、每次递归,就会向者出口靠近

def a():
    print('------a-------')
    a()

a()   

# 执行后,会反反复的打印------a-------,在n次数后,python 将会给你停止,因为已经触发最大的递归深度

案例:打印 1-10

# 打印 1-10
def test(i):
    if i == 10:
        print('10')
    else:
        print(i)
        i += 1
        test(i)

test(1)

案例:实现 1..10 相加之和

def test1(i):
    if i == 10:
        return 10
    else:
        return i + test1(i + 1)

r = test1(1)
print(r)   # 55

1.25、匿名函数

用 lambda 关键词能创建小型的函数,这个函数叫匿名函数,省略了def  函数名

格式:lamdba 参数列表 运算表达式
注意,匿名函数需要接收一下,为什么?因为函数用   函数()  就可以调用,但是匿名函数式省了函数名,那我怎么调用并获取返回数值

def test(a):
    return a + 1

可以写成

r = lambda a: a + 1

def test(a):
    return a + 1
result = test(5)
print(result)   #  6

r = lambda a: a + 1
result = r(5)
print(result)  #  6

---------------------------------------------------------

def test(a):
    return a + 1

r = lambda x, y: x + y
result = r(1, 2)
print(result)  # 6

场合:

作为参数使用,函数的参数能不能是一个函数

def test():
    print('----------test---------')


def func(a, f):
    print('------>', a)
    f()


func(5, test)  # 传递函数的名,就相当于传递函数的地址,所以 test 就是堆中的地址,传递给形参f,也就是f 等于test 的地址,执行f(),就是执行了test()

匿名函数作为参数使用 

def func(a, f):
    print('------>', a)
    r = f(a)
    print("r", r)  # 25


func(5, lambda x: x ** 2) 

a = 5     f = lambda x: x ** 2    然后执行r = f(a)  ,也就是r = lambda 5: 5 ** 2  ,也就是5^2,r = 25

1.26、高阶函数

函数对应的数据类型是 function ,可以把它当作是一个复杂的数据类型。既然同样都是一个数据类型,我们就可以把它当作数字或者字符串来处理。

既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,同样,我们还可以把一个函数当做另一个函数的返回值。这样函数的使用方式我们叫做高阶函数。

python提供的系统的高阶函数:sorted函数 filter类 map类 reducec函数  max  min

max 用法:

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

m = max([2, 4, 6])
print(m)

list1 = [('tom', 19), ('tony', 20), ('lily', 17),('daniel', 22)]
m = max(list1)
print(m)   # 返回的是('tony', 20) ,是因为max是按照一个元组中,整体的字符串之和做比较,怎么按年龄?需要key,是一个函数
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]
m = max(list1, key=lambda x: x[1])
print(m)  # 返回的是('daniel', 22),其中lambda x,将每一个元组传递给形参x,返回x[1], 也就是a = ('tom', 19) print(a[1]),取下标是1的元组数据,然后在给到max进行排序大小.所以key是一个排序的依据

list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]
m = min(list1, key=lambda x: x[1])
print(m)  # ('lily', 17) 

sorted 用法:

list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]
s = sorted(list1, key=lambda x: x[1])
print(s)  # [('lily', 17), ('tom', 19), ('tony', 20), ('daniel', 22)]
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]
s = sorted(list1, key=lambda x: x[1], reverse=True)
print(s)  # [('daniel', 22), ('tony', 20), ('tom', 19), ('lily', 17)]

filer 过滤:filter 返回的数值是布尔类型

找到年龄大约20岁的

list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]

rr = filter(lambda x:x[1] > 20 ,list1)   # 只有x[1] > 20的元组,返回True,才会使用
print(rr)   # <filter object at 0x000001950AA67610>  ,返回的是一个迭代器,需要强转成list,才会显示

rr = filter(lambda x: x[1] > 20, list1)
print(list(rr))  # [('daniel', 22)]

  等价于

list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]

list2 = []
for i in list1:
    if i[1] > 20:
        list2.append(i)
print(list2)

map 函数:将某一项数值映射出来,也就是提取出来,返回的是一个map对象,也是迭代器,计算函数使用的次数

list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]

ma = map(lambda x: x + 1, list1)
print(ma)  # <map object at 0x000001CEF4F47610>
print(list(ma))  # 报错,can only concatenate tuple (not "int") to tuple

这句话的意思是,提取x[1]的数值,然后对其+1的操作

ma = map(lambda x: x[1] + 1, list1)
print(list(ma))  # [20, 21, 18, 23]

提取列表的名字,并进行首字母大写(title  将每个单词首字母大写)

list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)]

ma = map(lambda x: x[0].title(), list1)
print(list(ma))  # ['Tom', 'Tony', 'Lily', 'Daniel']

reduce 函数:非系统的,必须导入functools,类似计算

from functools import reduce

取出 1 、2 ,分别赋值给x y ,然后通过 x + y 的数值,在赋值给x,然后将 2 后的 3 取出,赋值给 y,在进行x + y ,获取的数值,在赋值给 x 

from functools import reduce

r = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
print(r)  # ((((1+2)+3)+4)+5) 等于15 

zip函数:

zip() 函数是python内置函数之一,可以将多个序列(列表,元组,字典,字符串以及range()区间构成的列表)压缩成一个zip对象,就是将这些序列中对应的位置元素重新组合生成一个个新的元组

zip() 函数的语法格式为:

zip(iterable, ...)

其中 iterable,… 表示多个列表、元组、字典、集合、字符串,甚至还可以为 range() 区间。

test_list = [1,2,3]
test_tuple = (1,2,3)

# 返回的结果是对象
print('===object===>": ',zip(test_list,test_tuple))
#使用列表推导式转成列表
print('===list===>": ',[i for i in zip(test_list,test_tuple)])
#直接转成列表
print(list(list(zip(test_list,test_tuple))))
# 长短不一致,以短的一方为主
test_str = 'python'
test_str1= 'java'

test_dir = {'name':'jibu','age':30}
test_dir1 = {'name':'jibu','age':30}

#字符串压缩
print('===str===>: ',list(zip(test_str,test_str1)))
#这样好像没啥意义
print('===dir===>: ',list(zip(test_dir,test_dir1)))
#可以获取字典的key
print('===dir===>: ',list(zip(test_dir)))

结果
===str===>:  [('p', 'j'), ('y', 'a'), ('t', 'v'), ('h', 'a')]
===dir===>:  [('name', 'name'), ('age', 'age')]
===dir===>:  [('name',), ('age',)]

应用场景
先需要将A,B两个列表转换成字典

A = ["a", "b", "c", "d"]
B = [1, 2, 3, 4]

result = dict(zip(A,B))
print(result)

结果
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

2、time 关键字

import time

s = time.time()   # 注意 time.time() 返回的时间是时间戳
print(s)

s = time.time()
print(s)
time.sleep(3)    # 执行 time.sleep(3) 程序会卡住 3 s
e = time.time()  # 等 3 s 后在执行 time.time() ,对比 s 和 e 的时间戳 ,差 3 s 
print(e)

s = time.time()
print(s)
time.sleep(3)
e = time.time()
print(e)
print(e -s)   # 通过相减就可以获取 time 的时间差(s)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值