目录
推导式
1、列表推导式(用得最多的)
给你一个列表,求所有数据的绝对值
列表推导式跟if运算
打印50以内能被3整除的数的平方(filter)(if的使用)
找到1000以内开平方的结果是整数的数(if的使用)
打印50以内如果被2整除的数的平方,否则打印自己(map)(if和else的使用)
打印名字中包含g的数据(双重for循环)
将二维数组转一维数据(双重for循环)
二维转一维,将名字包含g的数据直接输出,不包含g的数据转大写输出
2、集合推导式(在列表推导式的基础上去重) => set
3、字典推导式 => dict
构建一个字典: {'a':1,"b":2,"c":3,"d":4........."z":26}
迭代器
可迭代对象: 实现了__iter__方法,并且该方法返回一个迭代器
可以使用dir查看是否实现了__iter__方法,即可判断是否为可迭代对象
迭代器
判断是否为迭代器,或者是可迭代对象
可迭代对象 和 迭代器的区别:
迭代器实现列表内数据的平方
map函数使用了惰性求值的特点(map就是迭代器)
实现一个迭代器(类似range函数的迭代器=>返回0到num的数据)
实现一个可以无限生成的斐波拉契数列的迭代器
生成器:
生成器表达式:(返回的数据 for 临时变量 in 可迭代对象)
生成器函数:如果一个函数中包含了yield关键字,它是一个生成器函数
使用生成器函数 --》 创建了一个生成器:g (g = func_g())
用生成器函数实现,传递给函数一下列表,返回列表中每个元素的平方
生成器yield 和 yield from返回数据的区别
闭包:
什么是闭包?
闭包形成的条件
闭包的特点
闭包函数
装饰器:
例子:希望获取每一个函数运行时候的耗时
用装饰器来实现给函数添加记录运行时间的功能(runtime装饰器)
实现加记日志的功能:如函数XXX被调用了(log装饰器)
一个函数可以使用多个装饰器(多重装饰器)
模块化拆分装饰器:
创建 utils.py 文件,将我们的runtime和log装饰器写入文件中:
然后我们在父文件中调用 utils.py 文件中的装饰器
装饰器可以装饰普通的函数、也可以用来装饰类
作业:
# 列表推导式(用得最多的)
# 字典推导式
# 集合推导式
li1 = [1,2,3,4]
# [返回值 for 临时变量 in 可迭代对象]
result = [x*x for x in li1]
print(type(result), result)
# map和列表推导式都可以做到
# map => map object
# 列表推导式 => list
输出:
[1, 4, 9, 16]
# 给你一个列表,求所有数据的绝对值
li2 = [1,2 ,-1, 4, 6, -4]
result = [abs(x) for x in li2 ]
print(result)
输出:
[1, 2, 1, 4, 6, 4]
result = [x**2 for x in range(1,50) if x%3 == 0]
print(result)
result = [x for x in range(1,1000) if x**0.5%1==0 ]
print(result)
result = [x**2 if x%2 == 0 else x for x in range(1,50) ]
print(result)
names = [
['asdf', 'ag'],
['abg', 'abc'],
]
result = [name for lst in names for name in lst if 'g' in name]
print(result)
li = [[1,2,3,4],[5,6,7,8]]
result = [x for lst in li for x in lst]
print(result)
相当于:
# result = []
# for lst in li:
# for x in lst:
# result.append(x)
names = [
['asdf', 'ag'],
['abg', 'abc'],
]
result = [name if 'g' in name else name.upper() for lst in names for name in lst]
print(result)
与下面意思的一样:
result = []
for lst in names:
for name in lst:
if 'g' in name:
result.append(name)
else:
result.append(name.upper())
print(result)
输出:
['ASDF', 'ag', 'abg', 'ABC']
lst = [-1, 1, -4, 2, 4]
# 求数据的绝对值,去重
result = {abs(x) for x in lst}
print(result)
# for 临时变量 in 可迭代数据
d1 = {"a":2, "b":1}
# 将key转化为大小
# {key:value for 临时数据 in 可迭代对象}
result = {key.upper():value for key,value in d1.items()}
print(result)
输出:
{'A': 2, 'B': 1}
# 构建一个字典: {'a':1,"b":2,"c":3,"d":4........."z":26}
# ord => 字母转ASCII chr(ord('a')+i)
# chr => ASCII转字母 chr(97) => 'a'
result = {chr(97+i):i+1 for i in range(26)}
print(result)
输出:
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6, 'g': 7, 'h': 8, 'i': 9, 'j': 10, 'k': 11, 'l': 12, 'm': 13, 'n': 14, 'o': 15, 'p': 16, 'q': 17, 'r': 18, 's': 19, 't': 20, 'u': 21, 'v': 22, 'w': 23, 'x': 24, 'y': 25, 'z': 26}
迭代器(Iterator)是Python中的一种对象,它用于实现迭代(遍历)的机制,允许你逐个访问集合中的元素,而无需提前加载所有元素到内存中。迭代器提供了一种延迟获取数据的方式,这对于处理大量数据或需要逐步处理数据的情况非常有用。
迭代器需要实现两个方法:
__iter__()
:返回迭代器对象自身。通常该方法返回self
。
__next__()
:返回集合中的下一个元素。如果没有元素可返回,则引发StopIteration
异常,表示迭代已经结束。迭代器的特点:
惰性求值:需要用到数据的时候,再去计算结果(不会一次性占用很多的内存空间和cpu,十分的高效)
可迭代对象(Iterable)是指可以被迭代(遍历)的对象。它们通常用于循环结构,比如
for
循环。可迭代对象可以包含多个元素,每次迭代都返回其中的一个元素,直到所有元素都被访问完为止。
print(dir(1))
print(dir(list))
# for i in 1:
# pass
# 报错:'int' object is not iterable 表示 int 类型是不可迭代对象
# 常见的可迭代对象:
# set, tuple, dict, str, bool
str1 = "abc"
# 迭代器
# 获得一个迭代器
# 迭代器实现了__iter__(返回自己)和__next__(返回下一个数据)方法
str1_iter = str1.__iter__()
print(type(str1_iter), str1_iter)
print(str1_iter.__next__())
print(str1_iter.__next__())
print(next(str1_iter)) # 跟str1_iter.__next__()效果一样,只是写法不一样
# 当没有数据了的时候,会引发StopIteration错误
# print(str1_iter.__next__())
# 当使用for去循环的时候,会调用对象的__iter__方法获得一个迭代器
# 每次循环,都是获取迭代器的__next__方法
# 如果遇到StopIteration错误,循环结束
# 等同于:for i in str1:
输出:
a
b
c
报错:
Traceback (most recent call last):
File "D:\衡山-开发\python\pythonProject_day01\test.py", line 11, in
print(str1_iter.__next__())
StopIteration
from collections.abc import Iterator,Iterable
print(isinstance(str1_iter, Iterator))
#collections.abc模块的使用
输出:
True / False
可迭代对象:print => 直接打印所有的数据
迭代器:print打印对象本身,无数据 => 对象.__next__ 或next(对象)
可迭代对象=> 存10w个数据 => 占用很多内存
迭代器 => 惰性求值(next调用的时候,才会去计算数据)(可用于数据量比较大的时候)
=> 不会一次占用很多的内存和CPU资源
迭代器实现了__iter__(返回自己)和__next__(返回下一个数据)方法
如果只实现了__iter__方法,那么它只能是可迭代对象
li = [1,2,3,4,5]
result = map(lambda x:x*x,li)
print(type(result), dir(result))
# result => map => 迭代器
print(result.__next__())
print(next(result))
class MyRange():
def __init__(self,num):
self._start = -1
self.num = num
# 返回它自己
def __iter__(self):
return self
# 返回
def __next__(self):
self._start += 1
if self._start < self.num:
return self._start
else:
raise StopIteration #如果我们需要停止迭代器,直接raise StopIteration
for item in MyRange(10):
print(item)
如果我们需要停止迭代器,直接raise StopIteration
#0, 1,1,2,3,5,8,13....
class Fib(object):
def __init__(self):
self.cur = 0
self.next = 1
def __iter__(self):
return self
def __next__(self):
self.cur,self.next = self.next,self.cur+self.next
return self.cur
for i in Fib():
if i>=100:
break
print(i,end=' ')
"生成器"(Generator)通常指的是一种能够逐步产生数据、内容或事件序列的程序或模型。
生成器通常是指一种特殊类型的函数,它可以逐步产生数据流,而不是一次性生成所有数据并将其存储在内存中。这在处理大量数据或需要逐步生成结果的情况下非常有用,因为它可以减少内存占用。在Python中,生成器函数使用关键字
yield
来逐步生成值。
特殊的迭代器:不需要自己编写__iter__和__next__ 方法
生成器特点与迭代器一样。
数量大,不需要立刻计算出结果,而是需要的时候再计算。
li1 = [1,2,3,4]
# (返回值 for 临时变量 in 可迭代对象)
result = (x*x for x in li1)
print(type(result), dir(result))
print(next(result))
print(next(result))
print(next(result))
print(next(result))
def func_g():
print("start")
yield 1
print("No1")
yield 2
print("No2")
yield 3
迭代器\生成器 中能保存一些状态的。迭代器\生成器 中的数据只能取一次。
g = func_g()
print(g, type(g), dir(g))
result = next(g) # 执行函数代码, 遇到yield 返回yield后面的数据,停止执行
print(result)
result = next(g) # 接着之前的代码继续执行
print(result)
result = next(g) # 接着之前的代码继续执行
print(result)
输出:
['__class__', '__del__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__name__', '__ne__', '__new__', '__next__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw']
start
1
No1
2
No2
3
li1 = [1,2,3,4]
# func_g2(li1)
def func_g1(li):
for item in li:
yield item*item
g = func_g1(li1)
for i in g:
print(i)
输出:
1
4
9
16
yield 返回的数据
yield from 迭代器
def func_g3():
yield range(10)
g3 = func_g3()
print(next(g3))
def func_g4():
yield from range(10)
g4 = func_g4()
print(next(g4))
print(next(g4))
print(next(g4))
输出:
range(0, 10)
0
1
2
闭包是在函数内部定义的函数,它可以访问其外部函数的变量,即使外部函数已经执行完毕并且其作用域不再存在。这种机制允许变量的状态在函数调用之间得以保留。
# 1. 必须有内外函数(函数中嵌套函数)
# 2. 外部函数必须返回内部函数
# 3. 内部函数要使用外部函数的变量
变量不会随着外部变量执行完成而释放,数据会被保存下来。(有状态的)
def outer_function(x):
def inner_function(y):
return x + y
return inner_function
closure = outer_function(10)
result = closure(5) # result 等于 15
在这个例子中,
outer_function
返回了一个内部函数inner_function
,内部函数引用了外部函数的参数x
。即使outer_function
执行完毕后,我们仍然可以通过调用closure(5)
来使用内部函数,这是因为闭包捕获了x
的值。
装饰器:一种设计模式。
如果需要给函数或类添加一个功能,但不改变原来的调用方式,同时又不希望修改源代码或类的继承实现。
装饰器允许您在不修改原始函数代码的情况下,通过添加额外的行为来扩展或修改函数的行为。
import time
# 希望获取每一个函数运行时候的耗时
def func1():
print("this is func1")
time.sleep(1)
def func2():
print("this is func2")
time.sleep(2)
def func3():
print("this is func3")
time.sleep(3)
start = time.time()
func1()
print("func1 cost:", time.time()-start)
start = time.time()
func2()
print("func2 cost:", time.time()-start)
start = time.time()
func3()
print("func3 cost:", time.time()-start)
输出:
this is func1
func1 cost: 1.0075395107269287
this is func2
func2 cost: 2.010779619216919
this is func3
func3 cost: 3.002288579940796
以上缺点:存在重复代码
import time
# 希望获取每一个函数运行时候的耗时
# 装饰器接收的是一个函数, 返回值也需要是一个函数(才能保证调用方式不变)
def rumtime(func):
# func --> 被装饰的函数
# 因为被装饰的函数可能带参数也可能不带参数,因此这里使用可变长参数
# 目的是让代码更加灵活
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"函数运行时间为:{time.time() - start}")
return result
# 返回值需要是一个函数
return inner
# 在被装饰的对象上方加@装饰器名
@rumtime
def func1():
print("this is func1")
time.sleep(1)
# 当使用@runtime装饰func1时,相当于执行了:
# func1 = runtime(func1) => 内部runtime.inner函数
# 装饰器就相当于被装饰的函数func1()放到runtime()函数里面去了,运行完后,runtime装饰器会再返回一个函数放到func1()函数中去
@rumtime
def func2():
print("this is func2")
time.sleep(2)
# func2 = runtime(func2)
# 新函数:记录运行时间,其中的函数功能 =>runtime.inner函数的功能
@rumtime
def func3():
print("this is func3")
time.sleep(3)
func1()
func2()
func3()
输出:
this is func1
函数运行时间为:1.0070466995239258
this is func2
函数运行时间为:2.004884958267212
this is func3
函数运行时间为:3.0066428184509277
log => 实现日志功能的装饰器
import time
# 希望获取每一个函数运行时候的耗时
# 装饰器接收的是一个函数, 返回值也需要是一个函数(才能保证调用方式不变)
def rumtime(func):
def inner(*args, **kwargs):
start = time.time()
result =func(*args, **kwargs)
print(f"函数运行时间为:{time.time() - start}")
return result
return inner
def log(func):
def inner(*args, **kwargs):
print(f"{func.__name__}函数被执行了...")
result =func(*args, **kwargs)
return result
return inner
# 在被装饰的对象上方加@装饰器名
@rumtime
def func1():
print("this is func1")
time.sleep(1)
# 当使用@runtime装饰func1时,相当于执行了:
# func1 = runtime(func1) => 内部runtime.inner函数
@log
def func2():
print("this is func2")
time.sleep(2)
#调用装饰器
@log
def func3():
print("this is func3")
time.sleep(3)
func1()
func2()
func3()
输出:
this is func1
函数运行时间为:1.0148968696594238
func2函数被执行了...
this is func2
func3函数被执行了...
this is func3
实现的效果:
func3 =》 log(runtime(func3)) =》 log(runtime.inner)
因此当我们使用如下多个装饰器的时候log装饰器其实调用的函数是runtime内返回的inner函数,因此log装饰器上显示的函数名就是inner函数啦
# 双重装饰器 @log @rumtime def func3(): print("this is func3") time.sleep(3) 输出: inner函数被执行了... this is func3 函数运行时间为:3.0028884410858154
因此如果我们想要我们的log能调用到真正的func3函数,我们需要对runtime装饰器进行修改
import time import functools # 希望获取每一个函数运行时候的耗时 # 装饰器接收的是一个函数, 返回值也需要是一个函数(才能保证调用方式不变) def rumtime(func): # functools.wraps(func)装饰器的功能是将func的原数据复制到inner上,其中就包括了函数名 @functools.wraps(func) def inner(*args, **kwargs): start = time.time() result =func(*args, **kwargs) print(f"函数运行时间为:{time.time() - start}") return result return inner def log(func): @functools.wraps(func) def inner(*args, **kwargs): print(f"{func.__name__}函数被执行了...") result =func(*args, **kwargs) return result return inner # 在被装饰的对象上方加@装饰器名 @rumtime def func1(): print("this is func1") time.sleep(1) # 当使用@runtime装饰func1时,相当于执行了: # func1 = runtime(func1) => 内部runtime.inner函数 @log def func2(): print("this is func2") time.sleep(2) # 多重装饰器 @log @rumtime def func3(): print("this is func3") time.sleep(3) func1() func2() func3() 输出: this is func1 函数运行时间为:1.0131046772003174 func2函数被执行了... this is func2 func3函数被执行了... this is func3 函数运行时间为:3.0059847831726074
如上所示,我们添加了functools包,并在runtime和log装饰器里面调用了它,如@functools.wraps(func),它能将func的原数据复制到inner上,其中就包括了函数名
import time
import functools
# 装饰器接收的是一个函数,返回值也需要是一个函数(才能保证调用方式不变)
# 用闭包实现了一个装饰器
def runtime(func):
# print("runtime-this is :",func)
# func => 被装饰的函数
# 因为被装饰的函数可能带参数也可能不带参数,因此这里使用可变长参数
# 让代码更加灵活
# functools.wraps:将func函数的元数据复制到inner (函数名)
@functools.wraps(func)
def inner(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"函数执行花了:{time.time()-start}s")
return result
# 返回值需要是一个函数
return inner
# import logging
from inspect import isfunction
def log(func):
# print("log-this is :",func)
# func => 被装饰的函数
# 因为被装饰的函数可能带参数也可能不带参数,因此这里使用可变长参数
# 让代码更加灵活
@functools.wraps(func)
def inner(*args, **kwargs):
# logging.log()
# isfunction可以用来判断func是否为函数,输出Ture或者False
if isfunction(func):
print(f"{func.__name__}函数被执行了...")
else:
print(f"{func.__name__}创建了一个实例...")
result = func(*args, **kwargs)
return result
# 返回值需要是一个函数
return inner
from utils import log, runtime
@log
class A():
@log
def count(self):
pass
# log装饰器内可以判断它调用的到底是类还是函数
a = A()
a.count()
输出:
A函数被执行了...
count函数被执行了...
# 实现一个装饰器,login_required
# 如果需要调用被装饰的函数,你需要已经登录了
# @login_required
# def index():pass
# 1. 全局变量:user = None => 未登录:打印“请先登录再访问”,不调用index
# not None => 已经登录:调用index
# 2. 将用户数据保存到文件,从文件中读取用户信息。