函数

函数

函数

字符串和列表内置方法的返回值

函数就是一段封装好的,可以重复使用的代码,它使得我们的程序更加模块化,不需要编写大量重复的代码。

函数定义方式:

#声明函数

def 函数名(参数):
    '''
    函数文档
    params:
    return:
    '''
	函数体
	return  函数结束语句
	
	
#函数调用:
函数名()

Python能够划分作用域的函数,类
流程控制语句不能开辟作用域

定义示例

#函数
#声明函数
def leiji():
    #1-100和
    ret = 0
    for i in range(1,101):
        ret += i
    print(ret)
#调用函数
leiji()

打印三角形

#函数声明
def ling():
    for  i in range(6):
        print((6 - i) * " " + (i * 2 + 1) * "*")
#函数调用:函数名()
ling()
print("ok")
ling()

生成器和生成器表达式

1.生成器和生成器函数
2.列表推导式

1.1生成器

什么是生成器:生成器实质就是迭代器

在python中有三种方式来获取生成器:

1.通过生成器函数
2.通过各种推导式来实现生成器
3.通过数据的转换也可以获取生成器

1.2 普通函数和生成器对比

普通函数

def func():
 print("111")
 return 222
ret = func()
print(ret)
结果:
111
222

将函数中的return换成yield就是生成器

def func():
 print("111")
 yield 222
ret = func()
print(ret)
结果:
<generator object func at 0x10567ff68>		#这个就是生成器

运行的结果和上面不一样。由于函数中存在了yield,那么这个函数就是一个生成器函数,这个时候,我们再执行这个函数的时候,就不再是函数的执行了,而是获取这个生成器,如果使用呢?想想迭代器,生成器的本质就是迭代器,所以,我们可以直接执行__next__()来执行以下生成器

def func():
    print("1111")
    yield 222
gener = func()	#这个时候函数不会执行,而是获取到生成器
ret = gener.__next__()	#这个时候函数才会执行,yield的作用和return一样,也是返回数据
print(ret)

结果:
1111
222

那么我们可以看到 yield和return的效果是一样的,有什么区别呢?yield是分段来执行一个函数,return呢?直接停止执行函数。

def func():
    print("1111")
    yield 222
    print("3333")
    yield 444


gener = func()
ret = gener.__next__()
print(ret)
ret2 = gener.__next__()
print(ret2)
ret3 = gener.__next__()     #最后一个yield执行完毕,再次__next__()程序报错,也就是说,和return无关了
print(ret3)

结果:
1111
222
3333
444
Traceback (most recent call last):
  File "D:/python资料/30s/代码/生成器.py", line 35, in <module>
    ret3 = gener.__next__()
StopIteration

当程序运行完最后一个yield,那么后面继续执行__next__()程序会报错。

1.3生成器作用

来看一个需求。该学校向JACK JONES订
购10000套学⽣服. JACK JONES就比较实在. 直接造出来10000套衣服.

def cloth():
    lst = []
    for i in range(0,10000):
        lst.append("衣服"+str(i))
    return lst
cl = cloth()
print(cl)

但是呢?问题来了,现在学校没有那么多学生,一次性给这么多衣服,学校放不下,这就很尴尬了,最好的效果是,我要1套,你给我1套,一共10000套,是不是很完美。

def cloth():
    for i in range(0,10000):
        yield "衣服"+str(i)

ret = cloth()
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())
print(ret.__next__())

结果:
衣服0
衣服1
衣服2
衣服3

区别:第一种是直接一次性全部拿出来,会很占用内存,第二种使用生成器,一次就生成一个,用多少就生成多少,生成器是一个一个的指向下一个,不会回去,next()到哪,指针就指到哪儿。下一次继续获取指针指向的值。

send()方法

send()方法,send()和__next__()一样都可以让生成器执行到下一个yield

def eat():
    print("吃什么")
    a = yield "馒头"
    print("a=",a)
    b = yield "大饼"
    print("b=",b)
    c = yield "火烧"
    print("c=",c)
    yield "羊汤"

gen = eat() #获取生成器
ret1 = gen.__next__()
print(ret1)
ret2 = gen.send("胡辣汤")
print(ret2)
ret3 = gen.send("狗粮")
print(ret3)
ret4 = gen.send("猫粮")
print(ret4)

send()和__next__()区别:

1.send和next()都是让生成器向下走一次
2.send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send()

生成器可以使用for循环来循环内部的元素:

def func():
    print(111)
    yield 222
    print(333)
    yield 444
    print(555)
    yield 666

gen = func()
for i in gen:
    print(i)

结果:
111
222
333
444
555
666

2 列表推导式,生成器表达式以及其他推导式

首先我们先看一下这样的代码,给出一个列表,通过循环,向列表中添加1-13:

lst = []
for i in range(1,14):
	lst.append(i)
print(lst)

替换成列表推导式:

lst = [i for i in range(1,14)]
print(lst)

列表推导式是通过一行来构建你要的列表,列表推导式看起来代码简单,但是出现错误之后很难排查。

列表推导式的常用写法:

	[结果 for 变量 in 可迭代对象]

例. 从python1期到python14期写入列表lst:

lst = ["python-%s" %i for i in range(1,15)]
print(lst)

结果:
['python-1', 'python-2', 'python-3', 'python-4', 'python-5', 'python-6', 'python-7', 'python-8', 'python-9', 'python-10', 'python-11', 'python-12', 'python-13', 'python-14']

还可以对列表中的数据进行筛选
筛选模式

[结果 for 变量 in 可迭代对象 if 条件]
#获取1-100内所有的偶数
lst = [i for i in range(1,101) if i % 2 == 0]
print(lst)

生成器表达式和列表推导式的语法基本是一样的,只是把[]替换成()

gen = (i for i in range(10))
print(gen)

结果:
<generator object <genexpr> at 0x000001D81F5D0DB0>

打印的结果就是一个生成器,我们可以使用for循环来循环这个生成器

gen = ("麻花藤爱你第%s次" %i for i in range(10))
for i in gen:
    print(i)

结果:
麻花藤爱你第0次
麻花藤爱你第1次
麻花藤爱你第2次
麻花藤爱你第3次
麻花藤爱你第4次
麻花藤爱你第5次
麻花藤爱你第6次
麻花藤爱你第7次
麻花藤爱你第8次
麻花藤爱你第9次

生成器表达式可以进行筛选:

#获取1-100内能被3整除的数
gen = [i for i in range(1,101) if i % 3 == 0]
print(gen)

#100以内能被3整除的数的平方
gen = [i*i for i in range(1,101) if i % 3 == 0]
print(gen)

#寻找名字中带有两个e的人的名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven','Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]

#不用推导式和表达式
ret = []
for first in names:
    for name in first:
        if name.count("e") >= 2:
            # print(name)
            ret.append(name)
print(ret)
#推导式
rel = [name for fir in names for name in fir if name.count("e") >= 2]
for name in rel:
    print(name)

生成器表达式和列表推导式的区别:

1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占用内容,使用的时候才分配和使用内存。
2.得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是一个生成器。
举个例子:
同样一篮子鸡蛋,列表推导式:直接那一篮子鸡蛋,生成器表达式:拿到一只母鸡,需要鸡蛋就给你下鸡蛋。

生成器的惰性机制:生成器只有在访问的时候才取值,说白了,你找他要值,他才会给你值,不找他要,他是不会执行的

def func():
    print(111)
    yield 222

g = func()  #生成器
g1 = (i for i in g) #生成器g1,但是g1的数据来源于g
g2 = (i for i in g1) #生成器g2,但是g2的数据来源于g1

print(list(g))  #获取g中的数据,这是func()才会被执行,打印111,获取到222,g完毕
print(list(g1))     #获取g1中的数据,g1的数据来源是g,但是g已经取完了,g1也就是没有数据了
print(list(g2))     #和g1同理

结果:
111
[222]
[]
[]

深坑== 生成器,要值的时候才能拿到值

字典推导式

dic = {'a':1,'b':'2'}

#取出字典中k值
new_dic = {key  for key in dic}
print(new_dic)
#取出字典中key:value值
new_dic = {key:value  for key,value in dic.items()}
print(new_dic)
#取出字典中的value值
new_dic = {dic[key]  for key in dic}
print(new_dic)
#把字典中的key和value互换
new_dic = {dic[key]:key  for key in dic}
print(new_dic)


#在以下list中,从list1中获取到的数据和list2中相对应的位置的数据组成一个新的字典
lst1 = ['jay', 'jj', 'sylar']
lst2 = ['周杰伦', '林俊杰', '邱彦涛']
dic = {lst1[i]:lst2[i]  for i in range(len(lst1))}
print(dic)

结果:
{'jay': '周杰伦', 'jj': '林俊杰', 'sylar': '邱彦涛'}

集合推导式

集合推到式可以帮我们直接生成一个结合,集合的特点:无序,不重复,所以集合推导式自带去重复功能

lst = [1, -1, 8, -8, 12]
# 绝对值去重
s = {abs(i) for i in lst}
print(s)

结果:
{8, 1, 12}

总结:

推导式有,列表推导式,字典推导式,结合推导式,没有元组推导式
生成器表达式:(结果 for 变量 in 可迭代对象 if 条件筛选)
生成器表达式可以直接获取到生成器对象,生成器对象可以直接进行for循环,生成器具有惰性机制。

⼀个⾯试题. 难度系数500000000颗星:

def add(a, b):
	return a + b
	
def test():
	for r_i in range(4):
		yield r_i
		
g = test()

for n in [2, 10]:
	g = (add(n, i) for i in g)
	
print(list(g))

结果:
[20, 21, 22, 23]

友情提⽰: 惰性机制, 不到最后不会拿值

迭代器

可迭代对象有

str		list tuple dict set
#正确的
for c in "abc":
    print(c)
	
#错误的
for i in 123:
    print(i)
#注意看报错信息中有这样⼀一句句话. 'int' object is not iterable . 翻译过来就是整数类型对象是不可迭代的. iterable表⽰示可迭代的. 表⽰示可迭代协议


查看类型是否可迭代的方法

dir()  #打印对象中的方法和函数,在打印结果中寻找__iter__如果能找到,这个类的对象就是一个可迭代对象。
print(dir('s'))

isinstence() 查看对象类型

l = [1,2,3]
l_iter = l.__iter__()
q = 123
from collections import Iterable
from collections import Iterator

print(isinstance(l,Iterable))
print(isinstance(q,Iterable))

print(isinstance(l,Iterator))
print(isinstance(l_iter,Iterator))
print(isinstance(q,Iterator))

迭代器

s = "我爱北京天安门"
c = s.__iter__()    #获取迭代器
print(c.__next__()) #使用迭代器进行迭代  获取一个元素 我
print(c.__next__()) #爱
print(c.__next__()) #北
print(c.__next__()) #京
print(c.__next__()) #天
print(c.__next__()) #安
print(c.__next__()) #门
print(c.__next__())  #StopIteration

for循环机制

s = "我爱北京天安门"
for i in s:
    print(i)

使用while循环+迭代器来模拟for循环

s = "我爱北京天安门"

c = s.__iter__()
while True:
    try:
        i = c.__next__()
        print(i)
    except StopIteration:
        break

总结

iterable:可迭代对象,内部包含__iter__()函数
Iterator:迭代器,内部包含__iter__()同时包含__next__()

迭代器特点

1.节省内存
2.惰性机制
3.不能反复,只能向下执行

我们可以把要迭代的内容当成⼦子弹. 然后呢. 获取到迭代器__iter__(), 就把⼦子弹都装在弹夹中. 然后发射就是__next__()把每⼀一个⼦子弹(元素)打出来. 也就是说, for循环的时候. ⼀一开始的时候是__iter__()来获取迭代器. 后⾯面每次获取元素都是通过__next__()来完成的. 当程序遇到StopIteration将结束循环.

高阶函数

一个高阶函数应该具备下面至少一个特点:

  • 将一个或者多个函数作为形参
  • 返回一个函数作为其结果

#一切皆数据,函数亦是变量

def foo():
    print("foo")

foo = 10
foo()
#会报错 'int' object is not callable,在执行foo = 10 之后,foo就变成了10,10为int类型,int类型加()会报错。

callable()

callable() 函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回False,调用对象ojbect绝对不会成功.对于函数, 方法, lambda 函式, 类, 以及实现了 call 方法的类实例, 它都返回 True。

返回值

可调用返回True,否则返回false

语法

callable(object)

示例

#定义函数
def foo():
    print("foo")

#判断是否可以被调用
print(callable(foo))

#重新复制变量
foo = 10

#判断函数是否可以被调用
print(callable(foo))

形参为函数的函数

def bar():
    print("bar")

def foo():
    print("foo")

def func(f):
    f()

func(bar)
func(foo)

计时案例,统计程序运行时间

方法一

import time		#调用时间模块

def bar():      #定义函数
    start = time.time()     #开始运行时间
    print("bar")            #输出内容
    time.sleep(2)           #睡眠2秒,增加实验效果
    end = time.time()       #运行结束时间
    print("花费时间:",end - start)      #结算运行时间

def foo():
    start = time.time()
    print("foo")
    time.sleep(2)
    end = time.time()
    print("花费时间:",end - start)

bar()	#调用bar统计运行时间
foo()	#调用foo统计运行时间

方法二

import time

#定义统计运行时间函数
def timer(func):

    def inner():
        start = time.time()
        func()
        end = time.time()
        print("花费时间: ",end - start)
    return inner

#定义函数
@timer	# foo = timer(foo)
def foo():
    print("foo")
    time.sleep(3)

# @timer
def bar():
    print("bar")
    time.sleep(2)

bar()
foo()

形参 实参

形参:声明函数的参数叫形参
实参:调用函数的参数叫实参

函数传参的过程就是变量赋值的过程

数字做累加

#函数声明
def lei(x):  #形式传参
    ret = 0
    for i in range(1,x+1):
        ret += i
    print(ret)
#函数调用
lei(100)  #实际传参  实参
lei(300)

传递两个参数

def login(user,pwd):
    '''
    可以做备注
    '''
    if user == "li" and pwd == 123:
        print("登录成功")
    else:
        print("用户名或密码错误")


#函数调用
login("ww",123)	 #ww,123分别是user,pwd的实参
login("li",123)

计算两个实参的和

def add(x,y):
    '''
    x:整数或者浮点数
    y:整数或者浮点数
    '''
    print(x+y)
add(3,5)
add(100,200)

传参的方式

位置参数
关键字参数(实参位置)
默认参数
可变长参数
混合参数

位置参数

不可以多传或者少传参数,是按照位置进行传递参数的

def add(x,y):
    '''
    x:整数或者浮点数
    y:整数或者浮点数
    '''
    print(x+y)
add(3,5)
add(100,200)
def print_stu(n,age,height,weight,id):
    print("name",n)
    print("age",age)
    print("height",height)
    print("weight",weight)
    print("id",id)

print_stu("alvin",23,140,180,110)

关键字传参(实参位置)

实参传递是可以不按照位置去写

def stu(name,age):
    print("name",name)
    print("age",age)
stu(name="li",age=23)
stu(age=24,name="wang")

混合传参(位置传参和关键字传参)

混合传参时关键字参数必须位于所有的位置参数之后。

def stu2(name,age):
    print("name",name)
    print("age",age)
stu2("li",age=23)

默认参数(形参)

设置默认参数,如果有新的参数传入则使用新的元素,没有新元素传入是由默认值

**默认值无参数传入**
def stu2(name,age,gender="male"):
    print("name",name)
    print("age",age)
    print("gender",gender)
stu2("li",23)

//默认值有参数传入
def stu2(name,age,gender="male"):
    print("name",name)
    print("age",age)
    print("gender",gender)
stu2("li",23,"man")

*args **kwars不定长参数

*args:位置参数,解释器在函数调用时候将所有的位置参数组织到一个元组复制给args
**kwargs :关键字参数,以字典形式存储元素,传输成对元素

*ages示例  解释器在函数调用时候将所有的位置参数组织到一个元组复制给args

def add(*ages):
    print(ages)
    print(type(ages))

add(2,3,4)

**kwars示例,解释器在函数调用的时候将所有关键字参数组织到一个字典中复制给kwargs

def add(**kwars):
    print(kwars)
    print(type(kwars))

add(name="li",age="23")

//接收传入的所有元素,传入单个元素使用*agrs接收,传入键值元素使用**kwargs接收

def foo(name,*agrs,**kwargs):
    print(name)
    print(agrs)
    print(kwargs)
foo("li",23,"male",height=180,weight=140)

return 函数结束语句

函数调用:返回值变量 = 函数名(参数)
return :函数结束语句,任何函数都会有一个返回值,默认返回None

示例

//使用return返回z的值
def ad(x,y):
    z = x + y
    return z  #函数结束语句
	
print(ad(2,3))

def ad(x,y):
    return x + y
print(ad(2,3))

//固定返回值

def ad(x,y):
    z = x + y
    return "偶"  #函数结束语句
print(ad(2,3))

//默认返回值 None
def ad(x,y):
    z = x + y
    return  #函数结束语句
print(ad(2,3))

//多个返回值
def ad(x,y):
    z = x + y
    return 11,22,33 #函数结束语句
print(ad(2,3))

//多个返回值案例

def login(user,pwd):
    
    flag = False	#定义flag等于False
    
    if user == "li" and pwd == 123:
        flag =True		#如果if成立,则flag等于true
        
    return flag,user		#返回flag和user的值

flag,user = login("li",123)

if flag:
    print("{}登录成功".format(user))
else:
    print("登录失败")

作用域

所谓作用域(Scope),就是变量的有效范围,就是变量可以在哪个范围以内使用。有些变量可以在整段代码的任意位置使用,有些变量只能在函数内部使用。

LEGB含义解释

字母 英语 释义 简称 作用空间
L Local(function) 当前函数内的作用域 局部作用域 局部
E Enclosing Functions Locals 外部嵌套函数的作用域 嵌套作用域 局部
G Global(module) 函数外部所在的命名空间 全局作用域 全局
B Built In(python) Python内置模块的命名空间 内建作用域 内置

Python的作用域遵循的标准LEGB

local    -->  enclosing ---> global ---> built-in
本级作用域		上层域		   全局	python内置

Pyhton能够划分作用域的只有函数,类,流程控制语句不能开辟作用域

def foo():  #local  同级(本地)有变量就是用本地变量
    x = 10
    print(x)
foo()

#local  同级(本地)有变量就是用本地变量,不会使用global变量
def foo():
    x =10
    print(x)  
x = 100
foo()

def foo():
    print(x) #local没有值,去上层找值,global有值,使用global值
x = 100
foo()

 #local global built-in  都没有w变量,所以报错,不可以跨域去找值
def fo():
    print(w)
    
def bar():
    w = 6
fo()

#local,本地找到数据后,不会再去别的地方找数据
x = 100
def foo():
    x = 10  #enclosing
    def bar():
        x = 5  
        print(x)
    bar()
foo()

#python中能有划分作用域的之后类和函数,流程控制语句不能开辟作用域
x = 100
if 3>2:   
    x = 10
print(x)

#for去循环每一个值,遇到pass不执行任何操作,继续走循环体,i=4是循环结束,所以i
for i in [1,2,3,4]:
    pass
print(i)

匿名函数

lambda

lambda 表达式,又称匿名函数,常用来表示内部仅包含 1 行表达式的函数。如果一个函数的函数体仅有 1 行表达式,则该函数就可以用 lambda 表达式来代替。

lambda 表达式的语法格式如下:

name = lambda [list] : 表达式

定义 lambda 表达式,必须使用 lambda 关键字;
[list] 作为可选参数,

#等同于定义函数是指定的参数列表,value 为该表达式的名称。

简单示例

    def add(x, y):
        return x+ y
    print(add(2,3))

    (lambda x,y:x+y)(2,3)

可以这样理解 lambda 表达式,其就是简单函数(函数体仅是单行的表达式)的简写版本。相比函数,lambda 表达式具有以下 2 个优势:

  • 对于单行函数,使用 lambda 表达式可以省去定义函数的过程,让代码更加简洁;
  • 对于不需要多次复用的函数,使用 lambda 表达式可以在用完之后立即释放,提高程序执行的性能。

filter()

filter()函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

语法: 
filter(function,iterable)
    filter函数返回一个list,但与map函数不同的是,filter函数只能有一个iterable作为输入.
    返回值:最后将判断函数返回 True 的元素放到新列表中。

示例

    # filter函数
    a = [1, 2, 3, 4, 5, 6]
    ret = list(filter(lambda x : x % 2 == 0, a))
    print(ret)
a = [1,2,3,4,5,6]

//第一种
def foo(x):
    return x % 2 ==0
print(list(filter(foo,a)))
#list 以列表的形式输出

//第二种
print((list(filter(lambda x:x%2 == 0,a))))
#list 以列表的形式输出

//不加list
print(filter(lambda x:x%2 == 0,a))

map()

map() 会根据提供的函数对指定序列做映射。

语法:
map(function, iterable1, iterable2, ...)

	返回值:第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

示例

    # map函数
    list(map(lambda x: x+2, [1,2,3,4]))
    #Output:[3,4,5,6]
    list(map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]))
    #Output:[3, 7, 11, 15, 19]
a = [1,2,3,4,5,6]
b = [7,8,9,10,11,12]

print(list(map(lambda x:x**2,a)))
print(list(map(lambda x,y:x + y,a,b)))

reduce()

reduce() 函数会对参数序列中元素进行累积。

语法: 
reduce(function,iterable[,initializer])

	返回值:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,返回最后得到一个结果。
from functools import reduce		#导入函数包

print(reduce(lambda x,y:x+y,(1,2,3,4,5,6)))

# reduce函数
reduce(lambda x, y: x+y, [1,2,3,4,5]) 
# Output:15

1.闭包与装饰器

首先看一下维基上对闭包的解释:

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。这样的一个函数我们称之为闭包。

闭包就是内层函数,对外层函数(非全局)的变量的引用,叫闭包
闭包需要满足一下三个条件:

1.必须是一个嵌套函数

2.必须返回嵌套函数

3.嵌套函数必须引用外部非全局的局部自由变量
def foo():
    x = 10	
    def inner():		
        print(x)	#x调用上层函数的值,python会给保留内存地址,供内部使用。所以inner的x会一致等于10,这个过程就叫做闭包
        print("bar 功能!")
    return inner

func = foo()
x = 14
func()

def bar(x):

    def inner():
        print(x)
        print("bar功能!")
    return inner

fun = bar(12)
fun()
#价值:能够动态灵活的创建以及传递函数,体现出函数式编程的特点。所以在一些场合,我们就多了一种编码方式的选择,适当的使用闭包可以使得我们的代码简洁高效。

closure 检测是否闭包

使⽤用函数名.__closure__返回cell就是闭包. 返回None就不是闭包
def fun():
    name = 'li'
    def fun2():
        print(name) #闭包
    fun2()
    print(fun2.__closure__)
fun()
print(fun.__closure__)

由于我们在外界可以访问内部函数. 那这个时候内部函数访问的时间和时机就不⼀一定了了, 因为在外部, 我可以选择在任意的时间去访问内部函数. 这个时候. 想⼀一想. 我们之前说过, 如果⼀一个函数执⾏行行完毕. 则这个函数中的变量量以及局部命名空间中的内容都将会被销毁. 在闭包中. 如果变量量被销毁了了. 那内部函数将不能正常执⾏行行. 所以. python规定. 如果你在内部函数中访问了了外层函数中的变量量. 那么这个变量量将不会消亡.将会常驻在内存中. 也就是说. 使⽤用闭包, 可以保证外层函数中的变量量在内存中常驻.

from urllib.request import urlopen

def but():
    content = urlopen("http://www.xiaohua100.cn/index.html").read()
    def get_content():
        return content
    return get_content
fn = but()  # 这个时候就开始加载校花100的内容
# 后⾯面需要⽤用到这⾥里里⾯面的内容就不不需要在执⾏行行⾮非常耗时的⽹网络连接操作了了
content = fn()  # 获取内容
print(content)
content2 = fn()  # 重新获取内容
print(content2)

2.装饰器

符合开放原则,对原有函数进行封装,在不改变原有函数逻辑的前提下,修改原有函数功能。
原理:原有函数赋值给一个函数,并在函数中构建装饰器函数,装饰器函数增功能。

2.1 方式一

打印类的运行时间

import time

def foo():
    print("foo功能")
    time.sleep(2)

def bar():
    print("bar功能")
    time.sleep(3)

def timer(target_func):

    def wrapper():
        start = time.time()
        target_func()
        end = time.time()
        print("时耗", end - start)

    return wrapper

foo = timer(foo)
foo()

bar = timer(bar)
bar()


方式二(方式一 的优化)


def timer(func):
    def weper():
        start = time.time()
        func()

        print("const timer:", time.time() - start)
    return weper
@timer
def foo():
    print("foo功能")
    time.sleep(1)

@timer
def bar():
    print("bar功能")
    time.sleep(2)

2.2 设计一个装饰器,能够计算某个函数被调用次数!

def timer(func):
    num = 0
    def weper():
        nonlocal num
        print("id:",id(func))
        func()
        num += 1
        print(f"{func.__name__}调用了{num}次!")
    return weper

@timer
def foo():
    print("foo功能")
    time.sleep(1)

@timer
def bar():
    print("bar功能")
    time.sleep(2)

foo()
foo()
bar()

repr() 函数将对象转化为供解释器读取的形式。

语法:

repr(object)

返回一个对象的 string 格式。

posted @ 2024-10-31 11:42  帅帅啊  阅读(18)  评论(0)    收藏  举报