python-15-迭代器和生成器

这篇博客涵盖了Python编程中的几个核心概念。首先,介绍了如何创建和使用`Pointer`、`Circle`类,包括计算面积、周长以及判断点与圆的位置关系。接着,展示了`PetShop`和`Pet`类的实现,支持不同类型的宠物如狗和猫,具备吠叫、吃食等行为,并能展示商店内的宠物。然后,讨论了`__repr__`方法在打印列表时的作用,以及如何自定义异常和使用`finally`关键字确保代码块的执行。此外,讲解了`with`关键字的上下文管理器功能,确保文件操作的正确关闭。最后,通过示例展示了如何创建和使用自定义迭代器,以及如何利用生成器生成斐波那契数列,强调了迭代器以时间换空间的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

01-练习1

import math


class Pointer(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


class Circle(object):
    def __init__(self, cp, radius):  # cp = p,radius = 3
        self.cp = cp
        self.radius = radius

    def get_area(self):
        return self.radius ** 2 * math.pi

    def get_length(self):
        return self.radius * 2 * math.pi

    def relationship(self, point):
        """
        求一个点和圆的关系。有三种关系:在圆内,在圆外,在圆上
        :param point: 需要判断的点
        """
        # 计算圆心到point的距离
        distance = (point.x - self.cp.x) ** 2 + (point.y - self.cp.y) ** 2
        if distance > self.radius ** 2:
            print('在圆外')
        elif distance < self.radius ** 2:
            print('在圆内')
        else:  # 等于的情况
            print('在圆上')


p = Pointer(3, 4)  # 创建了一个Pointer对象
c = Circle(p, 5)  # 创建好的Pointer对象传递给了Circle对象c
# print(hex(id(p)), hex(id(c)))

print(c.get_area())
print(c.get_length())

p1 = Pointer(10, 10)
c.relationship(p1)

p2 = Pointer(2, 2)
c.relationship(p2)

p3 = Pointer(0, 0)
c.relationship(p3)

02-练习2

import math


class Pointer(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


class Circle(object):
    def __init__(self, x, y, radius):  # cp = (3,4),radius = 5
        self.x = x
        self.y = y
        self.radius = radius

    def get_area(self):
        return self.radius ** 2 * math.pi

    def get_length(self):
        return self.radius * 2 * math.pi

    def relationship(self, point):  # point = p1
        distance = (point.x - self.x) ** 2 + (point.y - self.y) ** 2
        if distance > self.radius ** 2:
            print('在圆外')
        elif distance < self.radius ** 2:
            print('在圆内')
        else:  # 等于的情况
            print('在圆上')


p = Pointer(3, 4)
c = Circle(3, 4, 5)
p1 = Pointer(10, 10)
c.relationship(p1)

# print(hex(id(p)), hex(id(c)), hex(id(p1)))

03-练习3

class PetShop(object):
    def __init__(self, shop_name, pet_list=None):
        self.shop_name = shop_name
        if pet_list is None:
            pet_list = []
        self.pet_list = pet_list

    def show_pets(self):
        if len(self.pet_list) == 0:
            print('本店还没有宠物')
            return

        print('{}有{}个宠物,它们是:{}'.format(self.shop_name, len(self.pet_list), self.pet_list))

        # for pet in self.pet_list:
        #     print(pet)


class Pet(object):
    def __init__(self, name, gender, age, breed):
        self.name = name
        self.gender = gender
        self.age = age
        self.breed = breed

    def bark(self):
        print(self.name + '正在叫')

    def eat(self):
        print(self.name + '正在吃东西')

    def __repr__(self):
        return '姓名:{},性别{},年龄:{},品种:{}'.format(self.name, self.gender, self.age, self.breed)


class PetDog(Pet):
    def bark(self):
        print(self.name + '正在汪汪汪')

    def build_home(self):
        print(self.name + '正在拆家')

    def eat(self):
        print(self.name + '正在啃骨头')


class PetCat(Pet):
    def __init__(self, name, gender, age, breed, eyes_color):
        super(PetCat, self).__init__(name, gender, age, breed)
        self.eyes_color = eyes_color

    def bark(self):
        print(self.name + '正在喵喵喵')

    def sajiao(self):
        print(self.name + '正在撒娇')

    def eat(self):
        print(self.name + '正在吃鱼')

    def __repr__(self):
        x = super(PetCat, self).__repr__()
        x += ",眼睛颜色:{}".format(self.eyes_color)
        return x


class PetBird(Pet):
    pass


dog1 = PetDog('大黄', 'female', 3, '哈士奇')
dog2 = PetDog('二黄', 'male', 2, '萨摩耶')
cat1 = PetCat('tom', 'male', 2, '英短', 'blue')
cat2 = PetCat('包子', 'female', 3, '加菲猫', 'black')

ps = PetShop('萌宠', [dog1, dog2, cat1, cat2])
ps.show_pets()

04-打印列表

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
        return '姓名:{},年龄:{}'.format(self.name, self.age)


p1 = Person('张三', 18)
p2 = Person('李四', 20)

# print(p1)  # 调用 __str__ 或者 __repr__ 方法

persons = [p1, p2]

# 直接打印列表,会调用列表里元素的 __repr__ 方法
print(persons)  # 直接打印一个列表,会把列表里的每一个对象的内存地址打印出来

 

# print(p1)  # 调用 __str__ 或者 __repr__ 方法
# 直接打印列表,会调用列表里元素的 __repr__ 方法
print(persons)  # 直接打印一个列表,会把列表里的每一个对象的内存地址打印出来(这里可以理解为如果没__repr__函数就只会打印内存地址)

05-练习04

class Student(object):
    def __init__(self, number, name, age, gender, score):
        self.number = number
        self.name = name
        self.age = age
        self.gender = gender
        self.score = score

    def __str__(self):
        return '编号:{},姓名:{},年龄:{},性别:{},分数{}'.format(self.number, self.name, self.age, self.gender,
                                                     self.score)


class Grade(object):
    def __init__(self, name, students):
        self.name = name
        self.students = students

    def show_all(self):
        for student in self.students:
            print(student)

    def get_student_by_number(self, n):
        for s in self.students:
            if s.number == n:
                return s
        else:
            return '用户未找到'

    def failed_students(self):
        result = filter(lambda student: student.score < 60, self.students)
        for x in result:
            print(x)

    def order_students(self):
        # self.students.sort(key=lambda s: s.score, reverse=True)  # 直接修改self.students
        return sorted(self.students, key=lambda s: s.score, reverse=True)


# 如果数字以 0 开头,在Python2里表示八进制
s1 = Student(1, 'zhangsan', 18, 'male', 80)
s2 = Student(5, '李四', 19, 'male', 50)
s3 = Student(10, 'tony', 20, 'male', 70)
s4 = Student(7, 'jack', 18, 'female', 90)
s5 = Student(4, 'henry', 19, 'female', 56)

g = Grade('中二班', [s1, s2, s3, s4, s5])
# g.show_all()
# g.failed_students()
# x = g.order_students()
# for student in x:
#     print(student)


print(g.get_student_by_number(1))

06-finally关键字的使用

file = open('../02-视频/03-练习3.mp4', 'rb')

try:
    while True:
        content = file.read(1024)
        if not content:
            break
        print(content)
finally:  # 最终都会被执行的代码
    print('文件被关闭了')
    file.close()
finally:  # 最终都会被执行的代码

07-finally的注意事项

def test(a, b):
    x = a + b
    return x  # 一旦return就表示函数结束
    return 'hello'  # 这段代码不会被执行,一般情况下,一个函数最多只能执行一个return语句


def demo(a, b):
    try:
        x = a / b
    except ZeroDivisionError:
        return '除数不能为0'
    else:
        return x
    finally:
        print('我是finally')
        # return 'good'  # 如果函数里有finally,finally里的返回值会覆盖之前的返回值


print(demo(1, 2))
# print(demo(1, 0))
finally:
    print('我是finally')
    # return 'good'  # 如果函数里有finally,finally里的返回值会覆盖之前的返回值

08-with关键字

# try:
#     file = open('01-练习.py', 'r')
# except FileNotFoundError:
#     print('文件不存在')
# else:
#     try:
#         file.read()
#     finally:
#         file.close()

# x = open('01-练习.py', encoding='utf8')
# print(type(x))  # <class '_io.TextIOWrapper'>

try:
    with open('01-练习.py', 'r', encoding='utf8') as file:
        file.read()  # 不需要再手动的关闭文件
        # file.close()  # with 关键字会帮助我们关闭文件
except FileNotFoundError:
    print('文件未找到')

# with我们称之为上下文管理器,很多需要手动关闭的连接
# 比如说 文件连接,socket连接,数据库的连接 都能使用 with关键自动关闭连接
# with 关键字后面对象,需要实现 __enter__ 和 __exit__ 魔法方法

with作用:简化代码:

with open('01-练习.py', 'r', encoding='utf8') as file:
    file.read()  # 不需要再手动的关闭文件
    # file.close()  # with 关键字会帮助我们关闭文件

不用with:

 file = open('01-练习.py', 'r')
# except FileNotFoundError:
#     print('文件不存在')
# else:
#     try:
#         file.read()
#     finally:
#         file.close()
# with我们称之为上下文管理器,很多需要手动关闭的连接
# 比如说 文件连接,socket连接,数据库的连接 都能使用 with关键自动关闭连接
# with 关键字后面对象,需要实现 __enter__ 和 __exit__ 魔法方法

09-上下文管理器

  # with 语句后面的结果对象,需要重写 __enter__和__exit__方法
# 当进入到with代码块时,会自动调用 __enter__ 方法里的代码
# 当with代码块执行完成以后,会自动调用 __exit__ 方法


class Demo(object):
    def __enter__(self):
        print('__enter__方法被执行了')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__方法被调用了')


def create_obj():
    x = Demo()
    return x


# y = Demo()
# d = y.__enter__()
# print(y is d)

with create_obj() as d:  # as 变量名
    # 变量 d 不是 create_obj的返回结果
    # 它是创建的对象 y 调用__enter__之后的返回结果
    print(d)

10-自定义异常

# 系统内置的异常:
# ZeroDivisionError:除以0的异常  1 / 0
# FileNotFoundError:文件不存在异常  open('xxx.txt')
# FileExistsError: 多次创建同名的文件夹 os.mkdir('test')
# ValueError:  int('hello')
# KeyError:  person = {'name':'zhangsan'}    person['age']
# SyntaxError:    print('hello','good')
# IndexError    names = ['zhangsan','lisi']  names[5]

# 要求:让用户输入用户名和密码,如果用户名和密码的长度在 6~12 位正确,否则不正确
from exceptions import LengthError

password = input('请输入您的密码:')
m = 6
n = 12
if m <= len(password) <= n:
    print('密码正确')
else:
    # print('密码格式不正确')
    # 使用 raise 关键字可以抛出一个异常
    raise LengthError(m, n)

# 把密码保存到数据库里
print('将密码保存到数据库')

11-装饰器回顾

def can_play(fn):
    print('外部函数被调用了')

    def inner(name, game, **kwargs):  # kwargs = {'clock':22}  kwagrs['clock']
        clock = kwargs.get('clock', 21)
        if clock >= 21:
            print('太晚了不能玩儿游戏了')
        else:
            fn(name, game)

    return inner


@can_play
def play_game(name, game):
    print(name + '正在玩儿' + game)


play_game('张三', '王者荣耀', clock=20)

两层def

一个@ 就可以调用

12-高级装饰器

def can_play(clock):
    print('最外层函数被调用了,clock = {}'.format(clock))

    def handle_action(fn):
        print('handle_action被调用了')

        def do_action(name, game):
            if clock < 21:
                fn(name, game)
            else:
                print('太晚了,不能玩儿游戏了')

        return do_action

    return handle_action


@can_play(12)
def play_game(name, game):
    print(name + '正在玩儿' + game)


play_game('张三', '王者荣耀')

多层def

一个@全部调用(记得返回下面函数的参数)

13-装饰器的练习(了解)

# user_permission = 11  # 1011
user_permission = 12
'''
permission	英[pəˈmɪʃn]
美[pərˈmɪʃn]
n.	准许; 许可; 批准; 许可证; 书面许可;
'''

# 权限因子
# 用户权限  &  权限因子 != 0
DEL_PERMISSION = 8  # 1011 & 1000  ==>  1000
READ_PERMISSION = 4  # 1011 & 0100 ==> 0000
WRITE_PERMISSION = 2  # 1011 & 0010 ==> 0010
EXE_PERMISSION = 1  # 1011 & 0001 ==> 0001


def check_permission(x, y):
    def handle_action(fn):
        def do_action():
            if x & y != 0:  # 有权限,可以执行
                fn()
            else:
                print('对不起,您没有响应的权限')

        return do_action

    return handle_action


@check_permission(user_permission, READ_PERMISSION)
def read():
    print('我正在读取内容')


@check_permission(user_permission, WRITE_PERMISSION)
def write():
    print('我正在写入内容')


@check_permission(user_permission, EXE_PERMISSION)
def execute():
    print('我正在执行内容')


@check_permission(user_permission, DEL_PERMISSION)
def delete():
    print('我正在删除内容')


read()
write()
execute()
delete()

14-可迭代对象

# 有很多可迭代对象:  list/tuple/dict/set/str/range/filter/map
# for...in 可迭代对象
from collections.abc import Iterable


class Demo(object):
    def __init__(self, x):
        self.x = x
        self.count = 0

    def __iter__(self):  # 只要重写了 __iter__ 方法就是一个可迭代对象
        return self

    def __next__(self):
        # 每一次for...in都会调用一次__next__方法,获取返回值
        self.count += 1
        if self.count <= self.x:
            return self.count - 1
        else:
            raise StopIteration  # 让迭代器停止


d = Demo(10)
# isinstance:用来判断一个实例对象是否是有指定的类创建出来的
print(isinstance(d, Iterable))  # True

# for...in循环的本质就调用可迭代对象的 __iter__ 方法,获取到这个方法的返回值
# 这个返回值需要是一个对象,然后再调用这个对象 __next__ 方法
for i in Demo(10):
    print(i)

# names = list('hello')
# print(isinstance(names, Iterable))  # True

迭代是访问集合元素的一种方式。迭代器是⼀个可以记住遍历的位置的对象。迭代器对象从集合的第一 个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

Python3 迭代器与生成器


迭代器

迭代是Python最强大的功能之一,是访问集合元素的一种方式。

迭代器是一个可以记住遍历的位置的对象。

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器有两个基本的方法:iter() 和 next()

字符串,列表或元组对象都可用于创建迭代器:

>>> list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
迭代器对象可以使用常规for语句进行遍历:


实例(Python 3.0+)
#!/usr/bin/python3
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")
执行以上程序,输出结果如下:

1 2 3 4
也可以使用 next() 函数:

实例(Python 3.0+)
#!/usr/bin/python3
 
import sys         # 引入 sys 模块
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
 
while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()
执行以上程序,输出结果如下:

1
2
3
4

创建一个迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。

如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。

更多内容查阅:Python3 面向对象

__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。

__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。

创建一个返回数字的迭代器,初始值为 1,逐步递增 1:

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass)
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
执行输出结果为:

1
2
3
4
5

StopIteration

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

在 20 次迭代后停止执行:

实例(Python 3.0+)
class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)
执行输出结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。

以下实例使用 yield 实现斐波那契数列:

实例(Python 3.0+)
#!/usr/bin/python3
 
import sys
 
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()
执行以上程序,输出结果如下:

0 1 1 2 3 5 8 13 21 34 55

15-迭代器的使用

# 有很多可迭代对象:  list/tuple/dict/set/str/range/filter/map
# for...in 可迭代对象
from collections.abc import Iterable


class Demo(object):
    def __init__(self, x):
        self.x = x
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.count += 1
        if self.count <= self.x:
            return self.count - 1
        else:
            raise StopIteration


d = Demo(10)

# i = d.__iter__()
# i.__next__()

i = iter(d)  # 内置函数 iter 可以获取到一个可迭代对象的迭代器
print(next(i))
print(next(i))
print(next(i))
print(next(i))

16-使用迭代器生成斐波那契数列

import time


class Fibonacci(object):
    def __init__(self, n):
        self.n = n
        self.num1 = self.num2 = 1
        self.count = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.count += 1
        if self.count <= self.n:
            x = self.num1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            return x
        else:
            raise StopIteration


# 1,1,2,3,5,8,13,21,34,55,89,144
f = Fibonacci(3000)  # 占时间,不占用空间。以时间换空间
for i in f:
    pass

print('--------------')
print(i)
# 既然有列表了,为什么还要有生成器呢?

# 占空间,不占时间。  以空间换时间
nums = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]

17-exceptions

class LengthError(Exception):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return '长度必须要在{}至{}之间'.format(self.x, self.y)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老板来片烤面包

君子博学于文,赠之以礼,谢君~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值