python三器一闭
前言:python三器一闭i 包含 迭代器、生成器、装饰器,闭包
迭代器
- 概念:迭代器是一种可以记录可迭代对象遍历的位置,迭代器从第一个元素开始访问,直到访问所有元素访问结束,迭代器只会往前,不会后退的访问
- 可迭代对象: 是一种可以通过for..in 循环的对象,称之为可迭代对象,通常有 字典、列表、字符串,元祖
如何判断一个数据类型是否是可以迭代的
# 可以导入模块 from collections.abc import Iterable
# 然后通过isinstance 来判断出 Iterable 的实例,正确返回True
# Iterator 是判断这个对象是否是迭代器 Iterable 是判断一个对象是否是可迭代的
from collections.abc import Iterable, Iterator
print(isinstance([], Iterable)) # 列表是可以迭代的
print(isinstance({}, Iterable)) # 字典是可以迭代的
print(isinstance("abc", Iterable)) # 字符串是可以迭代的
print(isinstance(100, Iterable)) # 数字是不能迭代的
nums = [11, 33, 22, 55, 66]
print(type(nums))
nums_iter = iter(nums) # 获取可迭代对象中的迭代器
print(type(nums_iter))
# Iterator 是判断这个对象是否是迭代器 Iterable 是判断一个对象是否是可迭代的
print("num is iterator ? {}".format(isinstance(nums, Iterator))) # False
print("num_iter is iterator ?{}".format(isinstance(nums_iter, Iterator))) # True
获取迭代器数据的方式
nums = [11, 33, 22, 55, 66]
print(type(nums))
nums_iter = iter(nums) # 获取可迭代对象中的迭代器
# 获取迭代器中的数据 方式一 使用 next
# 注意使用next获取迭代器的数据时,下标不能越界,否则会抛出异常StopIteration
print(next(nums_iter)) # 11
print(next(nums_iter)) # 22
print(next(nums_iter)) # 33
# 获取迭代器中的数据 方式二 使用 循环,因为它是可迭代的
for x in nums_iter:
print(x)
自定义迭代器类
- 在一个类中有 iter 方法称之为 可迭代对象, 有iter和next方法的称之为迭代器
# 在一个类中 有 __iter__ 方法 这个对象就是可迭代对象,但不是迭代器
# 在一个类中 既实现了 __iter__ 方法 和 __next__ 方法 的对象 既是可迭代对象 也是迭代器
from collections.abc import Iterable
from collections.abc import Iterator
class MyList(object):
"""自定义的一个可迭代对象"""
def __init__(self):
self.items = []
def add(self, val):
self.items.append(val)
def __iter__(self):
return MyIterator()
class MyIterator(object):
"""自定义的供上面可迭代对象使用的一个迭代器"""
def __init__(self):
pass
def __next__(self):
pass
def __iter__(self):
pass
mylist = MyList()
mylist_iter = iter(mylist)
print("mylist是否是可以迭代对象", isinstance(mylist, Iterable)) # True
print("mylist是否是迭代器", isinstance(mylist, Iterator)) # Flase
print("mylist_iter是否是可以迭代对象", isinstance(mylist_iter, Iterable)) # True
print("mylist_iter是否是迭代器", isinstance(mylist_iter, Iterator)) # True
# 可迭代对象不一定是迭代器, 但迭代器第一定是可迭代对象
案例
# 学生管理系统
class Students(object):
"""自定义迭代器"""
def __init__(self):
self.stus = []
# 记录迭代的位置
self.current = 0
def add(self):
"""添加学生信息"""
name = input("请输入学生的姓名:")
phone = input("请输入学生的手机号码")
address = input("请输入学生的地址:")
new_stu = dict()
new_stu["name"] = name
new_stu["phone"] = phone
new_stu["address"] = address
# 将字典添加到列表中
self.stus.append(new_stu)
def __iter__(self):
return self
def __next__(self):
if self.current < len(self.stus):
ret = self.stus[self.current] # 每调用一次,就通过下标访问一个数据
# print("11")
# print(ret)
self.current += 1
return ret
else:
self.current = 0
raise StopIteration
stu_sys = Students()
stu_sys.add()
stu_sys.add()
# stu_sys.add()
# 使用for循环,因为它是迭代器,也是可迭代对象,所以是可迭代的
# for stu in stu_sys:
# print(stu)
# 改列表推导式
x = [x for x in stu_sys]
print(x)
生成器
- 概念:生成器- 一边循环一边生成的机制称之为生成器
- 特点:存储的是生成数据的方式,而不是存储生存的数据,节约内存
创建生成器的方式一
- 将列表推导式中的中括号 改为 大括号[] --->()
# 创建生成器的方式一 将列表推导式中的中括号 改为 大括号
nums = [x for x in range(11)]
print(type(nums)) # <class 'list'>
print(nums) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 生成器
nums2 = (x for x in range(5))
print(type(nums2)) # <class 'generator'>
print(nums2) # 返回的是一个生成器对象(<generator object <genexpr> at 0x103289050>),如果想要获取里面的数据的话,可以使用next
# print(next(nums2)) # 0
# print(next(nums2)) # 1
# 也可以通过for循环来获取数据,生成器也是迭代器的一种方式,它自动实现了iter 和 next 方法
# for x in nums2:
# print(x)
创建生成器的方式二
- 在一个函数中 有 yield关键字 的称之为 生成器(generator)
- yield 在一个函数中称之为生成器,并且在函数中执行到了yield的时候会暂停这个函数,并且把返回值返回,然后在继续执行下一次
# 使用生成器完成斐波那契数列
# 斐波那契数列 是从数列中的第三项开始,往后就是每一项的数据等于前两项的之和
def fib(n):
a, b = 1, 0
for _ in range(n):
a, b = b, a + b
yield a
for x in fib(10):
print(x)
# 斐波那契数列
def fib(n):
num1 = 1
num2 = 1
# 记录访问的位置
current = 0
while current <= n:
temp_num = num1
num1, num2 = num2, num1+num2
current += 1
yield temp_num # 此时不能使用return,yield自带iter() next() 方法
# 生产数据,生成器每生产一个都会计算一次
for x in fib(5):
print(x) # 1 1 2 3 5 8
案例
"""
问题:
假如有一个的文件 test.txt 大小约为 10K,之前处理文件的,代码如下所示:
"""
# def get_lines():
# l = []
# with open('test.txt', 'rb') as f:
# for eachline in f:
# l.append(eachline)
# return l
#
#
# def process(temp_data):
# print(temp_data) # 用打印来模拟处理过程
#
#
# if __name__ == '__main__':
# for e in get_lines():
# process(e.decode("utf-8")) # 处理每一行数据
"""
现在要处理一个大小为 10G 的文件,但是内存只有 4G,如果在只修改 get_lines 函数而其他代
码保持不变的情况下,应该如何实现?需要考虑的问题都有哪些?
"""
# 使用生成器
def get_list():
with open("test.txt", "r") as f:
while True:
data = f.read(1000 * 1000) # 每次读取1兆数据
if data:
yield data
else:
return
if __name__ == '__main__':
for x in get_list():
print(x)
总结
# 生成器是一种一边循环一边生成的机制称之为生成器。
# 在一个函数中有 yield 关键字的称之为 生成器
# yield 关键字 的特点 1 能够保存程序的执行状态,并且在函数中执行到了yield的时候会暂停这个函数,
# 并且把返回值返回,然后在继续执行下一次
# 2 能够节省了内存的空间地址。使用yield的好处在于它不会一次性将所有数据计算计算,而是取一次然后就计算一个
# 这样节省了空间和计算的时间
# 生成器的主要一个特点就是,生成器是一种存储生成数据的方式,而不是存储生存的数据。
# return 和 yield 的区别
# 两者都是 返回程序的运行结果
# 不同的是,return 在返回结果后程序会立刻结束
# yield 在程序执行完结果后不会立刻结束,而是等待下一次执行,并且能被记录最后一次计算的数据结果。
闭包
概念:在一个函数中嵌套了另外一个函数,并且函数内部引用了外部函数的形参或局部变量的称之为闭包
引入闭包
def make_print(num1): # 外部函数
def inter(num2): # 内部函数
print(num1 + num2) # 300 return inter ret = make_print(100) # 该100 存入 外部函数中
ret(200) # 该200是传入内部函数中闭包中能够修改外部函数中的局部变量,闭包中可以使用 nonlocal 修改变量
def demo_out():
m = 100 # 局部变量 def inter():
# 内部函数修改外部函数 使用 nonlocal
nonlocal m
m = 300 print("3", m) # 300 print("1", m) # 100 inter() # 返回内部函数中的引用 print("2", m) # 300 demo_out()
案例一
# 下面应用案例是理解闭包的经典题目,模拟了一个人站在原点,然后向X、Y轴进行移动,每次移动后及时打印当前的位置
def create():
# 外部函数中定义一个局部变量
pos = [0, 0] # 坐标原点x,y
def inter(direction, step):
new_x = pos[0] + direction[0] * step
new_y = pos[1] + direction[1] * step
pos[0] = new_x
pos[1] = new_y
return pos
return inter
player = create() # 创建棋子player,起点为原点
print(player([1, 0], 10)) # 向x轴正方向移动10步
print(player([0, 1], 10)) # 向y轴正向移动20步
print(player([-1, 0], 10)) # 向x轴负方向移动10步
# [10, 0]
# [10, 10]
# [0, 10]
案例二
#
# 有时我们需要对某些文件的特殊行进行分析,先要提取出这些特殊行,就可以使用闭包, 在内部获取文件名,外部引入要在文件提取的关键字
#
# 例如,需要取得文件"result.txt"中含有"163.com"关键字的行,看如下代码
def make_file(keep): # 外部函数
# 内部函数
def file_name(file):
# 读取出文件
read_file = open(file)
ret = read_file.readlines()
read_file.close()
ret_list = [i for i in ret if keep in i]
return ret_list
return file_name
filter_file = make_file("163.com")
file_name = filter_file("result.txt")
print(file_name)
总结
闭包概念:在一个函数中嵌套了另外一个函数,并且函数内部引用了外部函数的形参、或局部变量,称之为闭包
闭包和普通函数的区别
闭包在函数中执行完结果后,函数外部的局部变量不会被释放,会给内部函数使用
普通函数在执行完结果后不会保存值
闭包是在函数内再嵌套函数 闭包可以访问另外一个函数的局部变量或形参, 闭包可以让参数和变量不会被垃圾回收机制回收,始终保持在内存中
python三器一闭的更多相关文章
- python三器
1.1 装饰器 1.装饰器的作用 1. 装饰器作用:本质是函数(装饰其他函数)就是为其他函数添加其他功能 2. 装饰器必须准寻得原则: 1)不能修改被装饰函数的源代码 2)不能修改被装饰函数的调用方式 ...
- Python - 三大器 迭代器,生层器,装饰器
目录 Python - 三大器 迭代器,生层器,装饰器 一. 容器 二. 可迭代对象(iterable) 三. 迭代器 四. 生成器 五. 装饰器 1. 定义 六. 闭包 Python - 三大器 迭 ...
- Python 入门之 Python三大器 之 装饰器
Python 入门之 Python三大器 之 装饰器 1.开放封闭原则: (1)代码扩展进行开放 任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代 ...
- Python 装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 1 2 3 4 5 6 7 8 # -*- c ...
- Python装饰器详解
python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...
- Python装饰器由浅入深
装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...
- Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试
摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...
- Python装饰器与面向切面编程
今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...
- Python修饰器的函数式编程
Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都 ...
随机推荐
- iOS -程序启动原理和UIApplication的介绍
一.UIApplication 简介 (1)UIApplication对象是应用程序的象征,一个UIApplication对象就代表一个应用程序. (2)每一个Application都有自 ...
- Android开发项目中常用到的开源库
圆形头像 https://github.com/hdodenhof/CircleImageView ButterKnife https://github.com/JakeWharton/butterk ...
- RabbitMQ系列之【CentOS6.5安装RabbitMQ】
环境准备 操作系统:CentOS 6.5 Final RabbitMQ: 3.1.5 Python: 2.7.11 ErLang: R16B02 安装预环境(少什么安装什么) yum -y insta ...
- kafka架构、基本术语、消息存储结构
1.kafka架构 kafka处理消息大概流程 生产者发送消息给kafka服务器 消费者从kafka服务器(broker)读取消息 kafka服务器依靠zookeeper集群进行服务协调管理 2.ka ...
- 循环语句&编码了解
循环语句&编码了解 用户交互 input: input接收的内容是str 循环语句 if语句 语法规则: if 条件判断: 代码块1 else ...
- Redis学习笔记(二十一) 事务
文章开始啰嗦两句,写到这里共21篇关于redis的琐碎知识,没有过多的写编程过程中redis的应用,着重写的是redis命令.客户端.服务器以及生产环境搭建用到的主从.哨兵.集群实现原理,如果你真的能 ...
- Bumped!【迪杰斯特拉消边、堆优化】
Bumped! 题目链接(点击) Peter returned from the recently held ACM ICPC World Finals only to find that his r ...
- TypeError: this.xxx.substring is not a function的解决办法
这是因为已经改变了xxx的值的类型,不再是字符串的话将不会拥有substring函数, 我当时这样写的时候,直接将number类型赋予了this.enter,所以导致了错误. 改为这样之后可以使用su ...
- 装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org 然后配置环境变量
- IDEA之maven配置详解
这两天被maven配置搞得焦头烂额,前后忙活了三天才彻底搞定. 下面我总结一下配置的步骤. 步骤 1. 首先去maven官网去下载maven,http://maven.apache.org/ 这里教大 ...