迭代器生成器面向对象

迭代器

迭代器介绍

迭代器指的是迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上一
次结果而来迭代提供了一种通用的 不依赖索引 的迭代取值方式

image.png

可迭代对象

可以用 for 循环遍历的对象都是可迭代对象。

  • str,list,tuple,dict,set 等都是可迭代对象。
  • generator (生成器 和 yield 的生成器函数) 也是可迭代对象。

判断是否可迭代

image.png
# 查看是否有__iter__()方法来验证其是否是一个可迭代对象
str()   # 可迭代对象
list()  # 可迭代对象
int()   # 不可迭代
float() # 不可迭代
# 通过 isinstance 来判断其是否是可迭代的对象
from collections import Iterable    # collections是内置的模块
print(isinstance('abc', Iterable))      # True
print(isinstance({1, 2, 3}, Iterable))  # True
print(isinstance(2.15, Iterable))       # Flase

迭代器

  • 有内置的__iter__()方法的对象,执行迭代器的__iter__()方法得到的依然是迭代
    器本身
  • 有内置的__next__()方法的对象,执行该方法可以不依赖索引取值
image.png
# 说明:可迭代的对象不一定是迭代器
# 1.看其是否含有__iter__以及__next__方法
# 2.看其是否属于Iterator
from collections import Iterator
li = [1, 2, 3, 4]
print(isinstance(li, Iterator)) # False

iter()

可以被 next() 函数调用并不断返回下一个值的对象称为迭代器:Iterator 。那我们可
以通过 iter() 方法将可迭代的对象,转为迭代器。

li = [1, 2, 3, 4]
print(type(li))     # <class 'list'>
li = li.__iter__()
lis = iter(li)      # iter()方法就可以将可迭代的对象转为迭代器
print(type(li))     # <class 'list_iterator'>
print(type(lis))    # <class 'list_iterator'>
li = [1, 2, 3, 4]
lis = iter(li)

# print(lis[0])             # 注意迭代器不能通过下表去取值
print(lis.__next__())       # 取 1
print(lis.__next__())       # 取 2
print(lis.__next__())       # 取 3
print(lis.__next__())       # 取 4
# print(lis.__next__())       # 超出长度,报错;StopIteration
li = [1, 2, 3, 4]
lis = iter(li)

print(next(lis))        # 取 1
print(next(lis))        # 取 2
print(next(lis))        # 取 3
print(next(lis))        # 取 4
print(next(lis))        # 报错  StopIteration
li = [1, 2, 3, 4]
lis = iter(li)

for i in lis:
    print(i)


while True:
    print(lis.__next__())   # 报错 StopIteration

注意:

  • 迭代器不可以通过下标取值,而是使用__next__() 或者 next() 。但是只要超出
    范围则直接报错 StopIteration
  • next() 只能顺延调用,不能往前。

可迭代对象与迭代器区别

  • 可用于 for 循环的都是可迭代类型
  • 作用于 next() 都是迭代器类型
  • list 、 dict 、 str 等都是可迭代的但不是迭代器,因为 next() 函数无法调用它们。可
    以通过 iter() 函数将它们转为迭代器
  • python 的 for 循环本质就是通过不断调用 next() 函数实现的

生成器

生成器定义
在 Python 中,一边循环一边计算的机制,称为生成器:generator

image.png

那么生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,
从而节省大量的空间。

image.png

如何创建生成器

生成器表达式
生成器表达式来源于 迭代列表解析组合,生成器和列表解析类似,但是它使用 () 而不是 []。

image.png
g = (i for i in range(5))
# print(g)        # generator
# print(g[0])     # 生成器不可通过下表取值
print(next(g))      # 取 0
print(next(g))      # 取 1
print(next(g))      # 取 2
print(next(g))      # 取 3
print(next(g))      # 取 4
print(next(g))      # 生成器也是可迭代的对象,超出长度则报错: StopIteration
g = (i for i in range(5))
for i in g:
    if i < 3:
        print(i)

如何创建生成器

生成器函数
实现 :

  • 生成一个自定义长度的列表
    需求:
  • 定义函数 yieldtest
  • 通过函数参数指定列表长度
# 在函数中加入yield,该函数就变为生成器函数
def yield_test(number):
    n = 0
    li = []
    while n < number:
        li.append(n)
        yield n
        n += 1
    print(li)


res = yield_test(20)
# print(res)        # generator
print(next(res))    # 取 0
print(next(res))    # 取 1
print(next(res))    # 取 2
print(next(res))    # 取 3
print(next(res))    # 取 4
print(next(res))    # 取 5   ////////.  6y5

如何创建生成器

生成器函数( yield )

当一个函数中包含 yield 关键字,那么这个函数就不再是一个普通的函数,而是一个 generator
调用函数就是创建了一个生成器对象。其工作原理就是通过重复调用 next() 或者 __next__() 方法,
直到捕获一个异常。

如何创建生成器

生成器函数( yield )

注意:
yield 返回一个值,并且记住这个返回值的位置,
下次遇到 next() 调用时,代码从yield 的下一条语
句开始执行。与 return 的差别是,return 也是返回
一个值,但是直接结束函数。

image.png
# 斐波那契数列:除了第一个与第二个以外,任何一个数都可以由前两个相加得到。
def createNums():
    print("----func start----")
    a, b = 0 , 1
    for i in range(5):
        # print (b)
        print('--1--')
        yield b
        print('--2--')
        a, b = b, a+b
        print('--3--')
    print('----func end----')


g = createNums()
print(next(g))  # 打印--1-- 1,veild将b给返回,返回给next(g)
print(next(g))  # 遇到第二个next(g),会接着下一次yeild下面的代码继续执行
print(next(g))

# return:函数的返回值,当函数代码执行到return时,就退出函数,也就是说return下面的代码都不会再执行。
# yield:是将函数变为生成器关键字,将值返回到next(g),只不过再遇到下一个next(g)的时候,会接着上一次执行的代码继续执行。

for i in g:
    print(i)

生成器函数( yield )

send() 和 next() 一样,都能让生成器继续往下走一步(遇到 yield 返回),但 send() 能传一个值,
这个值作为 yield 表达式整体的结果。

生成器函数( yield )

思考 : 右边代码输出
hello ?
world ?
hello world ?

image.png
# send讲解
def test():
    # 1.赋值运算符从右到左
    a1 = yield'hello'   # 2.a = "world"
    # 3.将a1返回到send处了
    yield a1


res = test()
# print(next(res))              # hello
# print(res.send('world'))      # world
# print(res.send('world'))      # 注意:如果yield已经返回完,那在使用next或者send的时候就会报错

# print(res.send('hello'))      # 非空的值不能作为启动生成器的对象
print(res.send(None))           # 相当与next()

迭代器与生成器

  • 生成器能做到迭代器能做的所有事
  • 因为生成器自动创建了 iter() 和 next() 方法,生成器显得简洁,而且高效。

面向对象编程

面向对象编程介绍

面向对象编程: Object Oriented Programming,简称OOP,是一种程序设计思想。
需要注意的是,与之对应的是面向过程编程思想。实际上,能够使用面向对象编程思想实现的程序,
也都能通过面向过程完成。只是看哪种思想更适合当前开发需求。
面向过程与面向对象区别:

  • 面向过程:根据业务逻辑从上到下写代码
  • 面向对象:将数据与函数绑定到一起,进行封装。减少重复代码的重写过程

面向对象概念及术语

image.png

类是抽象的概念,仅仅是模板。用来描述具有相同属性和方法的对象的集合。
比如:"人"是一个类。

对象

某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。 比如:"胡歌
"就是一个对象。

类与对象的关系

那么实际上,我们可以进行对象归类

image.png

类与对象的关系

小练习: 下面哪些是类,哪些是对象?

image.png

类的构成

类由3个部分构成

  • 类的名称:类名
  • 类的属性:一组数据
  • 类的方法:允许对类进行操作的方法

类的定义

Python 使用 class 关键字来定义类,其基本结构如下:

image.png

注意: 类名通常采用驼峰式命名方式,尽量让字面意思体现出类的作用。

创建对象
python 中,可以根据已经定义的类去创建出一个个对象

image.png
image.png

小练习

  • 创建类:学生类
  • 创建对象:张三
  • 在类中定义方法输出:张三学习Python
class LogicStudents:
    def study_python(self):
        print('张三学python')


LogicStudents()         # 创建对象
zs = LogicStudents()    # 将对象赋值给zs,也可以理解未创建了zs这个对象(实例)。实例化的过程
zs.study_python()       # 通过 对象 方法名()调用类中的方法

self 参数

在类当中定义方法时,会发现系统帮我们自动创建了self 参数,并且在调用
对象的该方法时,也无需传入 self 参数。那这个 self 是什么?

实际上,我们需要明确 self 的两个概念

  • self 本身是 形参
  • self 就是 对象本身
image.png

小练习
ü 定义类为:学生类
ü 创建对象:李四
ü 在类中定义方法:打印李四信息

class LogicStudent:
    def test_one(self):
        print(self)


# self就是对想本身,也就是说,当创建的对象是谁时,self就是谁
N_stu = LogicStudent()
# 体现了 self 与N_stu 是同一个对象
print(N_stu)        # <__main__.LogicStudent object at 0x012CC330>
N_stu.test_one()    # <__main__.LogicStudent object at 0x012CC330>


xia_gu = LogicStudent()
# 体现了 self 与 xia_gu 是同一个对象
print(xia_gu)       # <__main__.LogicStudent object at 0x018D2190>
xia_gu.test_one()   # <__main__.LogicStudent object at 0x018D2190>
class LogicStudent:

    def stu_infor(self):
        # print(N_stu.name, N_stu.age)
        # print(xia_gu.namem xioa_gu.age)
        print(self.name, self. age)


# 思考:在类当中是否可以访问到对象自己属性。是可以的
N_stu = LogicStudent()
N_stu.name = 'N'
N_stu.age = 18
N_stu.stu_infor()

xia_gu = LogicStudent()
xia_gu.name = "xia_gu"
xia_gu.age = 19
xia_gu.stu_infor()

init() 方法
__init__() 方法称为 初始化方法,也可称为构造方法。在创建对象时,会自动
执行该方法,为对象的属性设置初始值。
猜一猜,以下代码会先输出--1--,还是先输出--2-- ?

image.png
class Student():
    def __init__(self):
        print('--1--')          # 1


s = Student()       # 初始化方法,他在创建对象后自动执行的方法
print('--2--')                  # 2
class LogicStudent:
    def __init__(self, sut_name, sut_age):      # __init__方法 形参
        # 初始化对象的属性
        # self.name = 'N'
        # self.age = 18

        self.name = sut_name
        self.age = sut_age

    def sut_infor(self):
        print(self.name, self.age)


N_sut = LogicStudent('N', 18)                   # __init__方法 实参传递
N_sut.sut_infor()

M_miao = LogicStudent('miao', 28)
M_miao.sut_infor()

class LogicStudent:

    def __init__(self, stu_name, stu_age):  # __init__方法 形参传递
        self.name = stu_name
        self.age = stu_age
        # 1.__init__方法是否可以由返回值:可以,但是必须为None
        # retrun "111"      # __init__() should return None, not 'str'
    def stu_infor(self):
        # print(self.name, self.age)
        self.gender = 'female'
        self.addr = 'ChangSha'


N_stu = LogicStudent('N', 18)   # __init__方法 实参传递
# 2.在__init__方法中声明的属性,可否在类的外部通过对象访问?可以
# print(N_stu.name, N_stu.age)

# 3.在自定义的方法当中定义对象的属性,注意需要需要先调用指定的方法,才会将gender属性以及addr属性封装到该对象中才可以访问
N_stu.stu_infor()
print(N_stu.gender)
print(N_stu.addr)

str() 方法

如果在开发中,希望打印输出对象变量时,能够打印自定义的内容。就可以
使用 __str__() 方法,将自定义内容通过return关键字返回。

注意:返回值必须是字符串

class LogicStudent:

   def __init__(self):
       pass


s = LogicStudent()
print(s)            # 实例所在的内存地址  <__main__.LogicStudent object at 0x012CC390>
class LogicStudent:
    def __init__(self):
        self.name = 'N'
        self.age = 18


    def __str__(self):
        # return self.name    # "N"
        # return self.age     # 报错,注意:__str__方法必须返回的是字符串
        # return self.name, self.age  # 因为return返回多个时会打包成元组随意此处报错
        return f'{self.name},{self.age}'

s = LogicStudent()
print(s)                    # N,18
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容