Python基础3(迭代器 生成器 装饰器)
迭代器
迭代器,一种工具
可迭代对象:
list,dict,str,set,tuple -- 可迭代对象 使用灵活
查看是否可迭代
方式一:
list.__iter__()
方式二:
查看源码
方式三:
print(dir(list))
官方声明只要具有__iter__()方法的就是可迭代对象
优缺点
1.优点
1.1 使用灵活
1.2 直接查看值
2.缺点
2.1 消耗内存
迭代器
官方声明只要具有__iter__()方法 next()方法就是迭代器
句柄"f"是个迭代器
f = open("xxxx","w")
f.__iter__()
f.__next__()
lst = [1,2,3,4,6]
new_list = lst.__iter__() #将可迭代对象转换成迭代器
new_list.__iter__()
new_list.__next__()
s = "123434"
new_s = s.__iter__() #将可迭代对象转换成迭代器
print(new_s)
new_s.__iter__()
new_s.__next__()
new_s = s.__iter__() #将可迭代对象转换成迭代器
print(new_s)
new_s.__iter__()
print(new_s.__next__())
print(new_s.__next__())
print(new_s.__next__())
s = "12343" # 更改版for的本质
s = [1,2,3,4,5,7]
count = len(s)
new_s = s.__iter__()
while count:
print(new_s.__next__())
count -= 1
s = "12345"
new_s = s.__iter__()
while True:
try:
print(new_s.__next__()) # for真实本质
except StopIteration:
break
# except Exception:
# print("我是万能的!")
# break
递归
定义
1.自己调用自己 (不断调用自己本身) -- 死递归
2.有明确的终止条件
满足以上两个才是有效递归
递:一直执行直到碰到结束条件
归:从结束条件开始往回退
官方声明: 最大层次1000,实际测试 998/997
示例: 猜3
def age(n): # 1,2,3
if n == 3:
return "猜对了"
else:
return age(n+1)
print(age(1))
分解
def age2(n):
if n == 3:
return "猜对了"
def age1(n):
if n == 3:
return "猜对了"
else:
age2(n+1)
def age(n):
if n == 3:
return "猜对了"
else:
age1(n+1)
age(1)
总结
可迭代对象: 优点:使用灵活,可以直接查看值 缺点:占内存,不能迭代取值
迭代器: 优点:节省内存,惰性机制 缺点:使用不灵活,操作比较繁琐,不能直接查看元素
迭代器的特性: 1.一次性的(用完就没有了) 2.不能逆行(不能后退) 3.惰性机制(节省内存)
什么是可迭代对象: 具有很多私有方法,具有__iter__()方法的就是一个可迭代对象
什么是迭代器: 具有__iter__()和__next__()方法的就是迭代器
迭代器什么时候使用:当容器中数据量较多的时候使用迭代器
生成器
迭代器和生成器的区别:
迭代器是Python中内置的一种节省空间的工具
生成器的本质就是一个迭代器
迭代器是Python自带的
生成器是咱们(程序员)写得
定义一个生成器:
基于函数,
函数体中存在yield就是一个生成器
函数名() 就是产生一个生成器
def func():
print(123)
return "你好"
func()
def func():
if 3>2:
yield "你好" #停
if 4>2:
yield "我好"
yield "大家好"
g = func() # 产生一个生成器
print(g.__next__())
print(g.__next__())
print(g.__next__())
for i in g:
print(i)
for 循环的本质
while True:
try:
print(g.__next__())
except StopIterration:
break
生成器的优点和注意事项
节省空间 -- 惰性机制
不能逆行
一次性
一个next对应一个yield
yield 能够进行返回内容,还能够返回多次
yield能够临时停止循环
yield 能够记录执行的位置
输出方式
def foo():
for i in range(10):
pass
yield i
count = 1
while True:
yield count
count += 1
g = foo()
print(next(g)) # ---- 推荐使用
print(next(g))
print(next(g))
print(next(g))
print(next(g))
### 坑
如果不用变量接受,直接输出
print(foo().__next__())
print(foo().__next__())
一直循环输出#9
生成器应用场景
def func():
lst = []
for i in range(100000):
lst.append(i)
return lst
print(func())
# 一次性打印全部结果,数据过大时特别消耗内存
def func():
for i in range(100000):
yield i
g = func()
for i in range(50):
print(next(g))
# 每次打印可选的一部分,不用的部分不打印,节省空间
yield from
将一个可迭代对象的元素逐个返回
def func():
lst = ["牛羊配","老奶奶花生米","卫龙","瞎扯淡","米老头","老干妈"]
for i in lst:
yield i
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 牛羊配
# 老奶奶花生米
# 卫龙
# 瞎扯淡
# 米老头
def func():
lst1 = ["牛羊配","老奶奶花生米","卫龙","虾扯蛋","米老头","老干妈"]
lst2 = ["小浣熊","老干爹","亲嘴烧","麻辣烫","黄焖鸡","井盖"]
yield from lst1
yield from lst2
g = func()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 牛羊配
# 老奶奶花生米
# 卫龙
# 虾扯蛋
# 所以循环第一个列表直到全部打印再循环第二个
推导式
循环模式
lst = []for i in range(20):
lst.append(i)print(lst)
转换list推导式
print([i for i in range(20)])
[变量 for i in range(20)]
筛选模式
lst = []for i in range(20):
if i % 2 == 0:
lst.append(i)print(lst)
转换成list表达式
[print([i for i in range(20) if i % 2 == 0])]
[变量(加工后的变量) for循环 加工方式]
其他例子:
print([i for i in range(50)f i % 2 ==1])print([i for i in range(1,50,2)])
循环模式
生成器:
g = (i for i in range(20))
print(next(g))
print(next(g))
print(next(g))
# 0 1 2 转换成列表
print(list((i for i in range(20))))
字典推导式(了解)
print({i:i+1 for i in range(10)})
print({i:i+1 for i in range(10) if i % 2 == 0})
{键:值 for循环 加工条件}
集合推导式(了解)
print({i for i in range(10)})
print({i for i in range(10) if i % 2 == 0})
总结:
list:
[变量(加工后的变量) for循环]
[变量(加工后的变量) for循环 加工条件]
生成器表达式:
(变量(加工后的变量) for循环)
(变量(加工后的变量) for循环 加工条件)
字典推导式:
{键:值 for循环 加工条件}
集合推导式:
{变量(加工后的变量) for循环 加工条件}
闭包
def func():
a = 1
def f1():
def foo():
print(a)
return foo
return f1ret = func()
# 或者直接
func()()()a = ret()a()
# 在嵌套函数内,使用非全局变量(且不是本层变量) -- 就是闭包# print(foo()()().__closure__)判断是否闭包了解:print(ret.__code__.co_freevars)
# 获取的是自由变量print(ret.__code__.co_varnames)# 获取的是局部变量闭包的作用:1.保证数据的安全性2.装饰器
装饰器
定义:
用来装饰的工具
在不改变源代码及调用方式的基础上额外增加新的功能
开放封闭原则:
扩展是开放的(增加新功能)
修改源码是封闭的(修改已经实现的功能)
版一:
import time
start_time = time.time()
def func():
time.sleep(2)
print("asdf")
func()
print(time.time() - start_time)
start_time = time.time()
def foo():
time.sleep(3)
print("qwer")
foo()
print(time.time() - start_time)
版二:
def times(f):
start_time = time.time()
f()
print(time.time() - start_time)
def foo():
time.sleep(3)
print("asdf")
s = foo
foo = times
foo(s)
版三(初识版装饰器):
def times(f):
def inner():
start_time = time.time()
f()
print(time.time() - start_time)
return inner
def foo():
time.sleep(1)
print("asdf")
foo = times(foo)
foo()
版四(第二版装饰器):
def wrapper():
def inner():
print(1)
return innerprint(wrapper()())
def wrapper(f):
def inner():
f()
return inner
def func():
print("123456")
func = wrapper(func)
func()
low版
import timedef wrapper(f):
def inner(*args,**kwargs):
start_time = time.time()
f(*args,**kwargs)
print(time.time() - start_time)
return innerdef func(*args,**kwargs):
print(f"这是{args,kwargs}函数")
time.sleep(2)
func = wrapper(func)
func("alex","wusir")
高级版:
import timedef wrapper(f):
def inner(*args,**kwargs):
start_time = time.time()
f(*args,**kwargs)
print(time.time() - start_time)
return inner@wrapperdef func(*args,**kwargs):
print(f"这是{args,kwargs}函数")
time.sleep(2)
@wrapperdef
foo(*args,**kwargs):
print(f"这是{args,kwargs}函数,123456")
time.sleep(3)
func("alex","ahfe")
foo("alex1","faikewfhn")
标准版:
def func(a):
#a是要被装饰的函数名
def foo(*args,**kwargs):
"装饰之前的操作"
ret = a(*args,**kwargs)
"装饰之后的操作"
return ret
return foo
@funcdef
f1(*args,**kwargs):
print(f"这是一个{args}")
return "我可以返回了"f1(1,2,3,34,4,5)
语法糖
语法糖必须放在被装饰的函数正上方
@wrapper 就等于 func = wrapper(func)
@wrapper 就等于 foo = wrapper(foo)
1.有参装饰器
基本版
def auth(argv):
def wrapper(f):
def inner(*args,**kwargs):
f(*args,**kwargs)
return inner
return wrapper
示例:
login_dic = {"username": None, "flag": False}
msg = """请选择app:QQ微信抖音邮箱"""
chose = input(msg).upper()
def auth(argv):
def wrapper(f):
def inner(*args,**kwargs):
if login_dic["flag"]:
f(*args,**kwargs)
else:
if argv == "QQ":
print("欢迎登陆QQ")
user = input("请输入账号:")
password = input("请输入密码:")
if user == "alex" and password == "alex123":
login_dic["flag"] = True
login_dic["username"] = user
f(*args,**kwargs)
else:
print("账号或者密码错误")
elif argv == "微信":
print("欢迎登陆微信")
user = input("请输入账号:")
password = input("请输入密码:")
if user == "alex123" and password == "alex123456":
login_dic["flag"] = True
login_dic["username"] = user
f(*args, **kwargs)
else:
print("账号或者密码错误")
elif argv == "抖音":
print("欢迎登陆抖音")
user = input("请输入账号:")
password = input("请输入密码:")
if user == "alex456" and password == "alex456123":
login_dic["flag"] = True
login_dic["username"] = user
f(*args, **kwargs)
else:
print("账号或者密码错误")
else:
print("欢迎登陆邮箱")
user = input("请输入账号:")
password = input("请输入密码:")
if user == "alex@qq.com" and password == "alex123":
login_dic["flag"] = True
login_dic["username"] = user
f(*args, **kwargs)
else:
print("账号或者密码错误")
return inner
return wrapper@auth(chose)
def foo():
print("这是一个被装饰的函数")
foo()
# @auth(chose) 相等于以下两行代码的解构
# wrapper = auth(chose)# foo = wrapper(foo)
多个装饰器装饰一个函数
def wrapper1(func):
def inner1(*args,**kwargs):
print(1)
func(*args,**kwargs)
print(11)
return inner1
def wrapper2(func):
def inner2(*args,**kwargs):
print(2)
func(*args,**kwargs)
print(22)
return inner2
def wrapper3(func):
def inner3(*args,**kwargs):
print(3)
func(*args,**kwargs)
print(33)
return inner3
@wrapper3
@wrapper2
@wrapper1
def foo():
print("这是一个被装饰的函数")
foo()
# 3
# 2
# 1
# 这是一个被装饰的函数
# 11
# 22
# 33
元类type
type 获取对象从属于的类
python 中 一切皆对象, 类在某种意义上也是一个对象, python中自己定义的类, 以及大部分内置类, 都是由type元类(构建类)实例化得来的
type 与 object 的关系
print(type(object))
object类是type类的一个实例
object类是type类的父类
反射
程序对自己内部代码的一种自省方式
反射是什么
通过字符串去操作对象的方式
具体方法
hasattr
getattr
setattr
delattr
反射角度
实例对象
# obj = A('赵海狗',47)
class A:
country = "中国"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print("in A func")
obj = A("赵海狗", 47)
print(hasattr(obj,"name"))
print(hasattr(obj,"country"))
print(hasattr(obj,"func"))
print(getattr(obj,"name"))
print(getattr(obj,"country"))
f = getattr(obj,"func")
f()
print(getattr(obj, "sex", None))
obj.sex = "公"
setattr(obj, "sex", "公")
print(obj.__dict__)
delattr(obj,"name")
print(obj.__dict__)
类
class A:
country = "中国"
def __init__(self, name, age):
self.name = name
self.age = age
def func(self):
print(self)
print("in A func")
if hasattr(A,"country"):
print(getattr(A, "country"))
if hasattr(A, "func"):
obj = A("赵海狗", 26)
getattr(obj, "func")()
# 和下方方法一样 区别在于一个对象反射,一个类反射,一个不用传参, 一个需要传参
getattr(A, "func")(obj)
本模块
a = 666
def func1():
print("in 本模块这个对象")
import sys
print(sys.modules[__name__])
print(getattr(sys.modules[__name__], "a"))
getattr(sys.modules[__name__], "func1")()
练习题
1.使用反射依次调用所有函数
def func1():
print("in func1")
def func2():
print("in func2")
def func3():
print("in func3")
def func4():
print("in func4")
import sys
func_lst = [f"func{i}" for i in range(1,5)]
for func in func_lst:
getattr(sys.modules[__name__], func)()
2.使用反射做出一个注册登录系统
class User:
user_list = [("login", "登录"),("register", "注册"),("save", "存储")]
def login(self):
print("欢迎来到登录页面")
def register(self):
print("欢迎来到注册页面")
def save(self):
print("欢迎来到存储页面")
while 1:
choose = input("请输入序号: \n: 登录\n2: 注册\n3: 存储\n").strip()
obj = User()
getattr(obj, obj.user_list[int(choose)-1][0])()
其他模块
tbjx文件
name = "太白金星"
def func():
print("in tbjx func")
class C:
area = "北京"
def __init__(self, name):
self.name = name
def func(self):
print("in B func")
import tbjx
print(getattr(tbjx,"name"))
getattr(tbjx, "func")()
import tbjx
# 1. 找到tbjx对象 的C类,实例化一个对象.
obj = getattr(tbjx, "C")("太白金星")
print(obj.__dict__)
# 2. 找到tbjx对象 的C类,通过对C类这个对象使用反射取到area.
f = getattr(getattr(tbjx, "C"), "area")
print(f)
# 3. 找到tbjx对象 的C类,实例化一个对象,对对象进行反射取值.
print(getattr(obj, "name"))

浙公网安备 33010602011771号