part4
1.可迭代对象
通俗来讲就是可以被for循环的对象。
如何判断?
通过dir函数来查看类中定义好的所有方法. 在打印结果中. 寻找__iter__
如果能找到. 那么这个类的对象就是一个可迭代对象.(list, tuple, dict, set)
如何让一个对象变成可迭代对象?
在类中实现__iter__
方法且返回一个迭代器(生成器)
迭代器
迭代器最大的作用个就是统一了容器类型循环遍历的标准。
如果对象中有__iter__
函数. 那么我们认为这个对象遵守了可迭代协议. 就可以获取到相应的迭代器. 这里的____iter__
__是帮助我们获取到对象的迭代器. 我们使用迭代器中的__next__
来获取到一个迭代器中的元素.
s = "我爱北京天安门"
c1 = s.__iter__() # 获取迭代器
# c1 =iter(s) # 同上
print(c1.__next__()) # 使用迭代器进行迭代. 获取一个元素 我
print(c1.__next__()) # 爱
print(c1.__next__()) # 北
print(c1.__next__()) # 京
print(c1.__next__()) # 天
print(c1.__next__()) # 安
print(c1.__next__()) # 门
print(c.__next__()) # StopIteration
for循环:
lst = [1,2,3]
lst_iter = lst.__iter__()
while True:
try:
i = lst_iter.__next__()
print(i)
except StopIteration:
break
list可以一次性把迭代器中的内容全部拿空. 并装载在一个新列表中
s = "我要吃饭, 你吃不吃".__iter__()
print(list(s)) # ['我', '要', '吃', '饭', ',', ' ', '你', '吃', '不', '吃']
总结
Iterable: 可迭代对象. 内部包含__iter__
函数
Iterator: 迭代器. 内部包含__iter__
同时包含__next__
迭代器的特点:
-
节省内存.
-
惰性机制
-
不能反复, 只能向下执行.
生成器
生成器的本质就是迭代器. 在python中有两种方式来获取生成器:
- 通过生成器函数
- 通过生成器表达式来实现生成器
def func():
print("111")
return 222
ret = func()
print(ret)
将函数中的return换成yield就是生成器
def func():
print("111")
yield 222
ret = func()
print(ret)
由于函数中存在了yield. 那么这个函数就是一个生成器函数. 这个时候. 我们再执行这个函数的时候. 就不再是函数的执行了. 而是获取这个生成器. 可以直接使用__next__
来执行该生成器
def func():
print("111")
yield 222
print("333")
yield 444
gener = func()
ret = gener.__next__()
print(ret)
ret2 = gener.__next__()
print(ret2)
ret3 = gener.__next__() # 最后一个yield执行完毕. 再次__next__()程序报错, 也就是说. 和return无关了.
2.约束
class Message:
def send(self):
print("发信息")
class Foo:
pass
def func(arg):
arg.send()
if 1 == 1:
func(Message())
else:
func(Foo()) # 虽然运行不到这里,但是会有bug
# 改进
# 用一个基类进行约束,起规范代码的作用
class Interface:
def send(self):
raise NotImplementedError()
# 要求子类必须重写send方法,否则抛出NotImplementedError异常
class Message(Interface):
def send(self):
print("发信息")
class Email(Interface):
def send(self):
print("发邮件")
class Foo(Interface):
pass
def func(arg):
arg.send()
i = input()
if i == '1':
func(Message())
elif i == '2':
func(Email())
else:
func(Foo())
3.反射
根据字符串的形式,去某个对象中操作它的成员。
-
getattr(对象,‘字符串’)
根据字符串的形式去某个对象中获取对象的成员
-
hasattr(对象,‘字符串’)
根据字符串的形式去某个对象中判断是否有该成员
-
setattr(对象,‘变量’,‘值’)
根据字符串的形式去某个对象中设置对象的成员
-
delattr(对象,‘变量’,‘值’)
根据字符串的形式去某个对象中删除对象的成员
class Foo:
def __init__(self,name):
self.name = name
obj = Foo("a1")
v1 = obj.name
v1 = getattr(obj,'name') # 效果同上
obj.name = "b2"
setattr(obj,'name','b2') # 效果同上
class Foo:
pass
obj = Foo()
obj.k1 = 999
setattr(obj,'k1',123)
# obj.k1 = 123
print(obj.k1)
delattr(obj,'k1')
print(obj.k1)
class Foo:
def login(self):
print("login")
def register(self):
print("register")
obj = Foo()
obj.login()
# 效果同上
method_name = getattr(obj,'login')
method_name()
obj.register()
# 效果同上
method_name = getattr(obj,'register')
method_name()
# 因此可以实现通过用户输入的字符串进行对象的调用
func_name = input("请输入方法名:")
getattr(obj,func_name)()
class Foo:
def get(self):
pass
obj = Foo()
if hasattr(obj,post):
getattr(obj,'get')
# 或者
v1 = getattr(obj,'get',None)
print(v1)
# 存在get方法就会返回方法,否则返回none
# 目的:帮助判断类中是否真的存在该类方法。
补充
python一切皆对象
- py文件
- 包
- 类
- 对象
以后想要通过字符串的形式操作其内部成员都可以通过反射的机制实现。
4.模块
# # 传统:
# # import utils.mysql 同下
# from utils import mysql
# mysql.func()
import importlib
# 用字符串的形式导入模块
mysql = importlib.import_module('utils.mysql')
# 用字符串的形式去对象(模块)找到对应的成员
getattr(mysql,'func')()
# 优化一下
import importlib
path = 'utils.mysql.func'
module_path,func_name = path.rsplit('.',maxsplit=1)
module_object = importlib.import_module(module_path)
getattr(module_object,func_name)()
# 再升级一下
import importlib
middleware_classes = [
'utils.mongo.Mongo',
'utils.mysql.Mysql',
]
for item in middleware_classes:
module_path,class_name = item.rsplit('.',maxsplit=1)
module_object = importlib.import_module(module_path)
cls = getattr(module_object,class_name)()
cls.func()
# 开放封闭原则,对配置文件开放,对源代码封闭
# 尽量去改配置文件,降低耦合(代码的关联)
# 补充:
# 1.模块导入通过模块的名字进行成员的区分
# 2.多次导入重新加载
import xxx # 第一次加载:会加载一遍xxx中所有的内容
import xxx # 由于已经加载过了就不再加载
# 硬要重新加载
import importlib
import xxx
importlib.reload(xxx)