pt06module&try&raise

Module

模块 Module 包含一系列数据、函数、类的文件,通常以.py结尾。

作用:让一些相关的数据,函数,类有逻辑的组织在一起,使逻辑结构更加清晰。有利于多人合作开发。

导入 import

import
(1) 语法
	import 模块名
	import 模块名 as 别名
(2) 作用:将模块整体导入到当前模块中
(3) 使用:模块名.成员

from import
(1) 语法:
from 模块名 import 成员名
from 模块名 import 成员名 as 别名
from 模块名 import *
(2) 作用:将模块内的成员导入到当前模块作用域中
(3) 使用:直接使用成员名
#module01.py

def func01():
    print("func01执行了")

def func02():
    print("func02执行了")
# "我过去"
# 语法:import 模块名
# 使用:模块名.成员
# 本质:创建文件,关联目标模块地址
import module01     #pycharm上在模块共同的目录上右键,Mark directory as ,Sources root

module01.func01()
module01.func02()

# "你过来"
# 语法:from 模块名 import 成员
#      直接使用成员
# 本质:将目标模块中的成员导入到当前模块作用域中
# 注意:小心命名冲突,程序自上而下
# from module01 import func01
# from module01 import func01,func02
from module01 import *

func01()  #func01执行了

def func01():
    print("dmoe05-func01")

func01()  #dmoe05-func01

练习

#module_exercise.py
data = 100

def func01():
    print("func01执行喽")

class MyClass:
    def func02(self):
        print("func02执行喽")

    @classmethod
    def func03(cls):
        print("func03执行喽")


print(__name__)
# 导入方式1:导入文件
# 适用性:面向过程的技术(全局变量/函数)
import module_exercise

print(module_exercise.data)
module_exercise.func01()
# 通过对象访问实例方法
m = module_exercise.MyClass()
m.func02()
module_exercise.MyClass.func03()

# 导入方式2:导入文件中的成员
# 适用性:面向对象的技术(类)
from module_exercise import *

print(data)
func01()
m = MyClass()
m.func02()
MyClass.func03()

练习:信息管理系统拆分

将信息管理系统拆分为4个模块student_info_manager_system.py

1)创建目录student_info_manager_system
 (2)创建模块bll,存储XXController
 业务逻辑层 business logic layer
 (3)创建模块usl,存储XXView
 用户显示层 user show layer
 (4)创建模块model,存储XXModel
 (5)创建模块main,存储调用XXView的代码
#bll.py
from model import StudentModel


class StudentController:
    """
        学生控制器:处理核心功能,存储...
    """

    __start_id = 100  # 大家的:系统不同界面使用的学生编号是一份(连续增加)

    @classmethod
    def __set_student_id(cls, stu):
        cls.__start_id += 1
        stu.sid = cls.__start_id

    def __init__(self):
        self.__list_student = []  # 自己的:系统不同界面使用自己数据(可以显示不同数据)

    @property  # 只读属性:View类只能读取,不能修改
    def list_student(self):
        return self.__list_student

    def add_student(self, new_stu):
        # 设置学生编号
        StudentController.__set_student_id(new_stu)
        # 追加到列表中
        self.__list_student.append(new_stu)

    def remove_student(self, sid):
        """
            在列表中删除学生信息
        :param sid: 学生编号
        :return: 是否成功
        """
        stu = StudentModel(sid=sid)
        if stu in self.__list_student:
            # 重写Model类的eq方法
            self.__list_student.remove(stu)
            return True
        return False

    def update_student(self, stu):
        """

        :param stu:
        :return:
        """
        for i in range(len(self.__list_student)):
            if self.__list_student[i].sid == stu.sid:
                # self.list_student[i].name = stu.name
                # self.list_student[i].age = stu.age
                # self.list_student[i].score = stu.score
                self.__list_student[i].__dict__ = stu.__dict__
                return True
        return False

    def ascending_order(self):
        self.__list_student.sort()

# 项目部署后,应该从main.py模块执行
# 变量__name__是bll
if __name__ == "__main__":
    # 测试代码,main.py模块执行时,不会执行
    controller = StudentController()
    controller.add_student(StudentModel())
    controller.add_student(StudentModel())
    controller.add_student(StudentModel())

#usl.py
from bll import StudentController
from model import StudentModel

class StudentView:
    """
        学生视图:输入/输出学生信息
    """

    def __init__(self):
        self.__controller = StudentController()

    def __display_menu(self):
        print("按1键录入学生信息")
        print("按2键显示学生信息")
        print("按3键删除学生信息")
        print("按4键修改学生信息")
        print("按5键根据成绩显示学生信息")

    def __select_menu(self):
        item = input("请输入选项:")
        if item == "1":
            self.__input_student()
        elif item == "2":
            # 先写出调用函数代码,再快捷键生成定义函数代码
            # alt + 回车
            self.__display_students()
        elif item == "3":
            self.__delete_student()
        elif item == "4":
            self.__set_student()
        elif item == "5":
            self.__order_by_score()

    def __input_student(self):
        stu = StudentModel()
        stu.name = input("请输入学生姓名:")
        stu.age = int(input("请输入学生年龄:"))
        stu.score = int(input("请输入学生成绩:"))
        self.__controller.add_student(stu)

    def main(self):
        while True:
            self.__display_menu()
            self.__select_menu()

    def __display_students(self):
        for item in self.__controller.list_student:
            # print(f"{item.name}的编号是{item.sid},年龄是{item.age},成绩是{item.score}")
            print(item)


    def __delete_student(self):
        sid = int(input("请输入需要删除的学生编号:"))
        if self.__controller.remove_student(sid):
            print("删除成功")
        else:
            print("删除失败")

    def __set_student(self):
        stu = StudentModel()
        stu.sid = input("请输入学生编号:")
        stu.name = input("请输入学生姓名:")
        stu.age = int(input("请输入学生年龄:"))
        stu.score = int(input("请输入学生成绩:"))
        if self.__controller.update_student(stu):
            print("修改成功")
        else:
            print("修改失败")

    def __order_by_score(self):
        self.__controller.ascending_order()
        self.__display_students()

#model.py
class StudentModel:
    def __init__(self, name="", age=0, score=0.0, sid=0):
        self.name = name
        self.age = age
        self.score = score
        self.sid = sid

    # 两个学生对象是否相同的依据:编号
    def __eq__(self, other):
        return self.sid == other.sid

    # 两个学生对象大小的依据:成绩
    def __gt__(self, other):
        return self.score > other.score

    # 显示学生的风格
    def __str__(self):
        return f"{self.name}的编号是{self.sid},年龄是{self.age},成绩是{self.score}"
#main.py
from usl import StudentView

# 如果是主模块才执行
# 快捷键:main+回车
if __name__ == '__main__':
    # (被导入时不执行)
    view = StudentView() 
    #光标停留StudentView(类名要正确),alt+enter -- import this name,选择usl的
    view.main()

加载过程:导入时执行

在模块导入时,模块的所有语句会执行。如果一个模块已经导入,则再次导入时不会重新执行模块内的语句。

模块变量doc、name

__doc__变量: 注释的文档字符串。
__name__变量:模块自身名字,可以判断是否为主模块。
当此模块作为主模块(第一个运行的模块)运行时,name绑定'__main__',不是主模块,而是被其它模块导入时,存储模块名。
#module_exercise.py
data = 100

def func01():
    print("func01执行喽")

class MyClass:
    def func02(self):
        print("func02执行喽")

    @classmethod
    def func03(cls):
        print("func03执行喽")


print(__doc__)   #注释的文档字符串

# 存储模块名称
print(__name__) # __main__
#在别的文件里导入上面的module_exercise模块时

import module_exercise   
#module_exercise被其它模块导入时,不是主模块,导入时运行,print(__name__)打印的是存储的是模块名module_exercise

使用:被调用时,不执行操作

#module_exercise.py
data = 100
...

if __name__ == '__main__':
    print(__name__)
import module_exercise   
#运行时,import执行模块,__name__为module_exercise,不满足if 将不会打印print(__name__)
"""
    小明使用手机打电话
        面向对象三大特征:
        封装:创建Person/MobilePhone/Landline类
        继承:创建Communication统一MobilePhone/Landline的行为
            隔离Person与MobilePhone/Landline的变化
        多态:MobilePhone/Landline重写Communication类dialing方法,实现具体功能
            编码时Person调用Communication
            运行时Person调用MobilePhone/Landline
"""


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

    def call(self, communication):
        print(self.name, "打电话")
        # 调用交通工具
        # 执行手机座机
        communication.dialing()


class Communication:
    def dialing(self):
        pass


class MobilePhone(Communication):
    def dialing(self):
        print("手机呼叫")


class Landline():
    def dialing(self):
        print("座机呼叫")


xm = Person("小明")
xm.call(MobilePhone())
xm.call(Landline())

"""
    玩家攻击敌人,敌人受伤,还可能死亡(加分)
          (头顶爆字,扣除血量)

    敌人攻击玩家,玩家受伤,还可能死亡(游戏结束)
          (闪现红屏,扣除血量)
"""


class Character:
    def __init__(self, hp, atk):
        self.hp = hp
        self.atk = atk

    # 子类完全相同
    def attack(self, target):
        print("发起攻击")
        target.damage(self.atk)

    # 子类部分相同
    def damage(self, value):
        self.hp -= value
        if self.hp <= 0:
            self.death()

    # 子类完全不同
    def death(self):
        pass

class Player(Character):
    def damage(self, value):
        print("闪现红屏")
        super().damage(value)

    def death(self):
        print("游戏结束")

class Enemy(Character):
    def damage(self, value):
        print("头顶爆字")
        super().damage(value)

    def death(self):
        print("加分")

p = Player(100, 25)
e = Enemy(50, 10)
p.attack(e)
e.attack(p)
p.attack(e)

模块分类

(1) 内置模块(builtins),在解析器的内部可以直接使用。
(2) 标准库模块,安装Python时已安装且可直接使用。
(3) 第三方模块(通常为开源),需要自己安装。
(4) 用户自己编写的模块(可以作为其他人的第三方模块)

了解time模块使用

"""
    标准库 - time

"""
import time

# 1. 人类时间:  0  ~  至今
# 秦始皇统一中国:-221
# 时间元组(年,月,日,时,分,秒,星期,年的第几天,夏令时偏移量)
time_tuple = time.localtime()
print(time_tuple)
#time.struct_time(tm_year=2023, tm_mon=4, tm_mday=1, tm_hour=17, tm_min=19, tm_sec=13, tm_wday=5, tm_yday=91, tm_isdst=0)

# 获取星期
print(time_tuple[6]) #5
print(time_tuple[-3]) #5
print(time_tuple.tm_wday) #5
# 获取年月日
print(time_tuple[:3])    #(2023, 4, 1)
# 获取时分秒
print(time_tuple[3:6])   #(17, 25, 52)

# 2. 机器时间
# 时间戳:从1970年元旦到现在经过的秒数
print(time.time())  # 1680341152.8060458

# 3. 时间戳 <--> 时间元组
# 时间元组 = time.localtime(时间戳)
print(time.localtime(1680341152.8060458))
#time.struct_time(tm_year=2023, tm_mon=4, tm_mday=1, tm_hour=17, tm_min=25, tm_sec=52, tm_wday=5, tm_yday=91, tm_isdst=0)

# 时间戳 = time.mktime(  时间元组 )
print(time.mktime(time_tuple))  #1680341351.0
print(time.mktime((1970, 8, 19, 10, 42, 0, 0, 0, 0)))  #19881720.0

# 4. 时间元组 <--> 字符串
# 字符串 = time.strftime(格式,时间元组)

print(time.strftime("%y/%m/%d %H:%M:%S", time_tuple))  #23/04/01 17:38:50

print(time.strftime("%y年%m月%d日 %H:%M:%S", time_tuple)) #23年04月01日 17:38:50
# 2021年08月19日 10:48:06
print(time.strftime("%Y年%m月%d日 %H:%M:%S", time_tuple)) #2023年04月01日 17:38:50
# 时间元组 = time.strptime(字符串,格式)
print(time.strptime("2023年04月01日 17:38:50", "%Y年%m月%d日 %H:%M:%S")) #time.struct_time(tm_year=2023, tm_mon=4, tm_mday=1, tm_hour=17, tm_min=38, tm_sec=50, tm_wday=5, tm_yday=91, tm_isdst=-1)

练习

"""
练习1:定义函数,根据年月日,计算星期。
输入:2020 9 15
输出:星期二
"""
import time


def get_week(year, month, day):
    """
        根据年月日获取星期
    :param year: int类型,年份
    :param month: int类型,月份
    :param day: int类型,天
    :return: str类型,星期
    """
    # 年月日 --> 字符串
    str_time = "%s-%s-%s" % (year, month, day)
    # 字符串  --> 时间元组
    tuple_time = time.strptime(str_time, "%Y-%m-%d")
    # 时间元组 --> 星期
    tuple_week = ("星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日")
    week_index = tuple_time[6]
    return tuple_week[week_index]

print(get_week(2021, 8, 19))

"""
练习2:定义函数,根据生日(年月日),计算活了多天.
输入:2010 1 1
输出:从2010年1月1日到现在总共活了多少天
"""


def get_birthday(year, month, day):
    """

    :param year:
    :param month:
    :param day:
    :return:
    """
    # 时间戳 = time.mktime(时间元组)
    time_birthday = time.mktime((year, month, day, 0, 0, 0, 0, 0, 0))
    # 当前时间戳 - 生日时间戳
    second = time.time() - time_birthday
    return second / 60 / 60 / 24


print("%.0f" % get_birthday(2010, 1, 1))

package

包package,将模块以文件夹的形式进行分组管理。

"""
    Python项目完整结构
    根目录
    包 #目录下带有 __init__.py  文件,封装包里的成员,在导入的时候体现
        模块
            类
                函数
                    语句
    main.py
"""

$ ls -R package01/
package01/:
__init__.py    package02/

package01/package02:
__init__.py    module01.py

# 绝对路径:从项目根目录开始
#方法一
import package01.package02.module01 as m    #只能找到模块
m.func01()
#方法二
from package01.package02.module01 import func01  #找到模块里的成员
func01()
#光标停留到模块名上,ctrl +q  查看模块位置
#__init__.py    文件,设置,封装包里的成员,在导入的时候体现功能
from package01.package02.module01 import func01

#demon.py
from package01.package02 import func01
func01()

练习

my_project02/
	main.py
	common/
		__init__.py
		list_helper.py
	skill_system/
		__init__.py
		skill_manager.py
通过导入包的方式,在main.py中调用skill_manager.py中实例方法。
通过导入包的方式,在skill_manager.py中调用list_helper.py中类方法。
#common/
#		__init__.py
from common.list_helper import C

#		list_helper.py
class C:
    @classmethod
    def func03(cls):
        print("C-func03")
#skill_system/
#		__init__.py
from skill_system.skill_manager import A

#		skill_manager.py
from common import C

C.func03()

class A:
    def func01(self):
        print("A - func01")
#main.py
# import skill_system    #只能找到模块
#
# a = skill_system.A()
# a.func01()

from skill_system import A   #找到模块里的成员

a = A()
a.func01()

总结

"""
    小结 - 程序结构
    1. 项目根目录
        包
            模块
                类
                    方法
        main.py

    2. 相关概念
        根目录: 主模块所在文件夹
        主模块: 第一次执行的模块,不会生成pyc文件.

    3. 导入模块
        import 模块
        模块.成员

        import 包.模块 as 别名
        别名.成员

        from 模块 import 成员
        直接访问成员

        from 模块 import *    #(导入所有的成员)
        直接访问成员

    4. 导入包
        备注:必须在包的__init__.py模块中提供成员

        import 包
        模块.成员

        import 包.包 as 别名
        别名.成员

        from 包 import 成员
        直接访问成员

        from 包 import *
        直接访问成员

    5. 导入模块是否成功的唯一标准
        导入路径 + 系统路径 = 真实路径
"""
import sys

print(sys.path)

try 处理异常

作用:将程序由异常状态转为正常流程

as 子句是用于绑定错误对象的变量,可以省略
except子句可以有一个或多个,用来捕获某种类型的错误。
else子句最多只能有一个。
finally子句最多只能有一个,如果没有except子句,必须存在。
如果异常没有被捕获到,会向上层(调用处)继续传递,直到程序终止运行。

语法

try:
	可能触发异常的语句
except 错误类型1 [as 变量1]:
	处理语句1
except 错误类型2 [as 变量2]:
	处理语句2
except Exception [as 变量3]:
	不是以上错误类型的处理语句
else:
	未发生异常的语句
finally:
	无论是否发生异常的语句
"""
    异常处理
        适用性:不处理语法错误,而是处理逻辑错误
        目的:将异常状态(不断向上返回),
            改为正常状态(继续向下执行)
        核心价值:
            保障程序按照既定流程执行,不紊乱
"""

# 方式1:包治百病(民间喜爱,使用最多)     #try下的执行出错后执行except后的操作
def div_apple(apple_count):
    try:
        # ValueError  str  fload int
        person_count = int(input("请输入人数:"))
        # ZeroDivisionError
        result = apple_count / person_count
        print("每人分得%f个苹果" % result)
    # except Exception:
    except:
        print("程序出错啦")

div_apple(10)

print("后续逻辑")
# 方式2:对症下药(官方建议),但是复杂

def div_apple(apple_count):
    try:
        # ValueError
        person_count = int(input("请输入人数:"))
        # ZeroDivisionError
        result = apple_count / person_count
        print("每人分得%f个苹果" % result)
    except ValueError:
        print("错误,输入的不是整数")
    except ZeroDivisionError:
        print("错误,输入的是零")

div_apple(10)

print("后续逻辑")
# 方式3: 无论是否异常,一定执行的逻辑

def div_apple(apple_count):
    try:
        person_count = int(input("请输入人数:"))
        result = apple_count / person_count
        print("每人分得%f个苹果" % result)
        # 打开文件的操作
        # 处理文件 
    except ZeroDivisionError:
        print("错误,输入的是零")
    finally: 
        # 关闭文件时,使用较多
        print("分苹果结束")

div_apple(10)

print("后续逻辑")
# 方式4:没有错误执行的逻辑

def div_apple(apple_count):
    try:
        person_count = int(input("请输入人数:"))
        result = apple_count / person_count
        print("每人分得%f个苹果" % result)
    except ValueError:
        print("错误,输入的不是整数")
    except ZeroDivisionError:
        print("错误,输入的是零")
    else:
        print("分苹成功啦")

div_apple(10)

print("后续逻辑")

练习

"""
练习:创建函数,在终端中录入int类型成绩。如果格式不正确,重新输入。
"""


def get_score():
    while True:
        try:
            score = int(input("请输入成绩:"))
            return score # 输入无误执行本行,退出函数
        except:
            print("输入有误,请输入整数")


score = get_score()
print("成绩是:%d" % score)
class StudentView:
    """
        学生视图:输入/输出学生信息
    """
....

    def __get_number(self,message):   #设计成函数,调用
        while True:
            try:
                number = int(input(message))
                return number
            except:
                print("输入有误,请输入整数")

    def __input_student(self):
        stu = StudentModel()
        stu.name = input("请输入学生姓名:")
        # stu.age = int(input("请输入学生年龄:"))  #原来的
        stu.age = self.__get_number("请输入学生年龄:")
        stu.score = self.__get_number("请输入学生成绩:")
        self.__controller.add_student(stu)

raise抛出

作用:抛出一个错误,让程序进入异常状态。
目的:在程序调用层数较深时,向主调函数传递错误信息要层层return比较麻烦,所以人为抛出异常,可以直接传递错误信息。

"""
    人为创造异常
    异常产生的完整流程
        1    --> 2  --> ... -->  3
     接收消息                    发送消息
  except Exception as e:     raise Exception()
"""


class Wife:
    def __init__(self, name="", age=0):  # 2
        self.name = name
        self.age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, value):  # 3
        if 20 <= value <= 30:
            self.__age = value
        else:
            # raise发送错误消息
            raise Exception("年龄超过范围", 1001)


while True:
    try:
        age = int(input("请输入年龄:"))
        shuang_er = Wife("双儿", age)  # 1
        print(shuang_er.__dict__)
        break
    # 接收错误消息
    except Exception as e:
        print(e.args)   #"年龄超过范围", 1001

迭代、迭代器、可迭代对象

每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。

"""
迭代 iteration: 每一次得到的结果会作为下一次的初始值
可迭代对象 iterable: 有__iter__函数,能够创造迭代器的对象
迭代器 iterator: 有__next__函数,实现迭代过程的对象
"""
#message = "我是齐天大圣孙悟空"
#for item in message:
#    print(item)    #我\n是\n齐...

# for循环原理
#message = "我是齐天大圣孙悟空"
#iterator = message.__iter__()
#item = iterator.__next__()
#print(item)  #我
#item = iterator.__next__()
#print(item)  #是  ....

# 1. 获取迭代器
iterator = message.__iter__()
while True:
    try:
        # 2. 计算下一个元素
        item = iterator.__next__()
        print(item)
    # 3. 如果停止迭代,则结束循环
    except StopIteration:
        break

# 面试题:
# 对象能够参与for循环的条件是什么?
# 答:对象必须具备__iter__函数,对象必须是可迭代对象
"""
创建列表,使用迭代思想,打印每个元素.
"""
list01 = [34, 54, 54, 56, 7]
iterator = list01.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

"""
创建字典,使用迭代思想,打印每个键值对.
"""
# 面试题:不使用for循环,获取字典所有键值对.
dict01 = {"a": 34, "b": 54, "c": 54}
iterator = dict01.__iter__()
while True:
    try:
        key = iterator.__next__()
        print(key, dict01[key])
    except StopIteration:
        break
"""
    迭代器  练习(for循环原理)
    需求:迭代自定义对象
"""


class StudentIterator:  # 3 定义迭代器,创建next函数
    def __init__(self, data):
        self.__data = data
        self.__index = -1   

    def __next__(self):
        try:
            self.__index += 1
            return self.__data[self.__index]  # 4 从第一个列表数据返回
        except:
            raise StopIteration()  # 5  异常抛出处理


class StudentController:  # 可迭代对象
    def __init__(self):
        self.__list_student = []

    def add_student(self, stu):
        self.__list_student.append(stu)

    def __iter__(self):
        return StudentIterator(self.__list_student)  #  1 把列表给到迭代器处理


controller = StudentController()
controller.add_student("A")
controller.add_student("B")
controller.add_student("C")

#for  原理实现
# for item in controller:
#     print(item)

iterator = controller.__iter__()   # 1  需创建 iter函数,返回迭代器
while True:
    try:
        item = iterator.__next__()  # 2  需创建迭代器
        print(item)  # A
    except StopIteration:  # 6 异常处理
        break

练习

"""
遍历商品控制器
class CommodityController:
	pass
	
controller = CommodityController()
controller.add_commodity("屠龙刀")
controller.add_commodity("倚天剑")
controller.add_commodity("芭比娃娃")

for item in controller:
	print(item)
"""

class CommodityIterator:  # 迭代器
    def __init__(self,data):
        self.__data = data
        self.__index = -1

    def __next__(self):
        try:
            self.__index += 1
            return self.__data[self.__index]
        except IndexError:
            raise StopIteration()

class CommodityController:  # 可迭代对象
    def __init__(self):
        self.__list_commodity = []

    def add_commodity(self, cmd):
        self.__list_commodity.append(cmd)

    def __iter__(self):
        return CommodityIterator(self.__list_commodity)

controller = CommodityController()
controller.add_commodity("屠龙刀")
controller.add_commodity("倚天剑")
controller.add_commodity("芭比娃娃")

# for item in controller:
#     print(item)
iterator = controller.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

#小鸭子原则 #没父类,依然可以使用,灵活,别的语言不可以
# ------------------架构师--------------------
class Person:
    def __init__(self, name=""):
        self.name = name

    def go_to(self, position, vehicle):
        print("去" + position)
        vehicle.transport() # 调用鸭子的呱呱叫方法 

# ------------------程序员--------------------
class Car:  # 狗
    def transport(self):  # 呱呱
        print("汽车在行驶")

class Airplane:  # 猫
    def transport(self):  # 呱呱
        print("飞机在飞行")


zl = Person("老张")
car = Car()
air = Airplane()
zl.go_to("东北", car)
zl.go_to("东北", air)

"""
#创建自定义range类,实现下列效果.  
class MyRange:
	pass
for number in MyRange(5):
	print(number)# 0 1 2 3 4
"""


class MyRangeIterator:
    def __init__(self, end):
        self.__number = -1
        self.__end = end

    def __next__(self):
        if self.__number < self.__end - 1:
            self.__number += 1
            return self.__number
        raise StopIteration()

class MyRange:
    def __init__(self, stop):
        self.__stop = stop

    def __iter__(self):
        return MyRangeIterator(self.__stop)

# for number in MyRange(5):
#     print(number)# 0 1 2 3 4

# 循环一次  计算一次  返回一次
# 每次都存储当前结果,释放之前结果  m_range = MyRange(9999999999999999)
m_range = MyRange(9)
iterator = m_range.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

生成器generator

(1) 定义:能够动态 (循环一次计算一次返回一次) 提供数据的可迭代对象。
(2) 作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。以上作用也称之为延迟操作或惰性操作,通俗的讲就是在需要的时候才计算结果,而不是一次构建出所有结果。

生成器函数yield

(1) 定义:含有yield语句的函数,返回值为生成器对象。

# 创建:
def 函数名():yield 数据
…
# 调用:
	for 变量名 in 函数名():
	语句
说明:
	-- 调用生成器函数将返回一个生成器对象,不执行函数体。
	-- yield翻译为”产生”或”生成”
执行过程:
a. 调用生成器函数会自动创建迭代器对象。
b. 调用迭代器对象的next()方法时才执行生成器函数。
c. 每次执行到yield语句时返回数据,暂时离开。
d. 待下次调用next()方法时继续从离开处继续执行。

原理:生成迭代器对象的大致规则如下
	a. 将yield关键字以前的代码放在next方法中。
	b. 将yield关键字后面的数据作为next方法的返回值。
"""
    迭代器 --> yield
"""


class StudentController:  # 可迭代对象
    def __init__(self):
        self.__list_student = []

    def add_student(self, stu):
        self.__list_student.append(stu)

    def __iter__(self):
        # 生成迭代器代码的大致规则:
        # 1. 将yield之前的代码定义到__next__函数体中
        # 2. 将yield之后的数据作为__next__函数返回值
        index = 0
        yield self.__list_student[index]

        index += 1
        yield self.__list_student[index]

        index += 1
        yield self.__list_student[index]


controller = StudentController()
controller.add_student("A")
controller.add_student("B")
controller.add_student("C")

# for item in controller:
#     print(item)

iterator = controller.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

"""
    yield --> 生成器函数
"""

"""
class MyRange:
    def __init__(self, stop):
        self.__stop = stop

    def __iter__(self):
        number = 0
        while number <  self.__stop:
            yield number
            number += 1

# for number in MyRange(5):
#     print(number)# 0 1 2 3 4

# 循环一次  计算一次  返回一次
# 每次都存储当前结果,释放之前结果
m_range = MyRange(8)
iterator = m_range.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break
"""

"""
# 生成器的伪代码
class generator:# 生成器对象 =   可迭代对象 +  迭代器对象
    def __iter__(self):# 可迭代对象
        return self
    
    def __next__(self):# 迭代器对象
        产生数据 
"""


def my_range(stop):
    number = 0
    while number <  stop:
        yield number
        number += 1


# print(my_range(5))  #生成器对象  
for item in my_range(5):  #制作自己的range函数
    print(item)

# result = my_range(9999999999999999999999999999999)
# iterator = result.__iter__()
# while True:
#     try:
#         item = iterator.__next__()
#         print(item)
#     except StopIteration:
#         break
"""
    生成器函数应用
"""
# 需求:定义函数,在列表中查找大于10的所有数字
list01 = [3, 34, 55, 6, 6, 78, 89]


# 传统思想: 创建容器存储所有结果
def find_number_gt_10():
    list_data = []
    for item in list01:
        if item > 10:
            list_data.append(item)
    return list_data

result = find_number_gt_10()
for number in result:
    print(number)


# 生成器思想:循环一次 计算一次 返回一次
def find_number_gt_10():
    for item in list01:
        if item > 10:
            yield item


# 惰性 延迟
result = find_number_gt_10()
#print(result)  #生成器对象 
for number in result:
    print(number)  #34\n55\n78\n89
# 练习1:在列表中找出所有偶数
list01 = [43, 43, 54, 56, 76, 87, 98]


def find_all_even():
    for item in list01:
        if item % 2 == 0:
            yield item


result = find_all_even()
for number in result:
    print(number)

# 练习2:在列表中找出所有数字
list02 = [43, "悟空", True, 56, "八戒", 87.5, 98]


def find_all_number():
    for item in list02:
        # if type(item) == int or type(item) == float:
        if type(item) in (int, float):
            yield item


for number in find_all_number():
    print(number)

class Employee:
    def __init__(self, eid, did, name, money):
        self.eid = eid  # 员工编号
        self.did = did  # 部门编号
        self.name = name
        self.money = money


list_employees = [
    Employee(1001, 9002, "师父", 60000),
    Employee(1002, 9001, "孙悟空", 50000),
    Employee(1003, 9002, "猪八戒", 20000),
    Employee(1004, 9001, "沙僧", 30000),
    Employee(1005, 9001, "小白龙", 15000),
]


# 定义函数,在员工列表中查找编号是1003的员工
def find_employee_by_eid():
    for item in list_employees:
        if item.eid == 1003:
            return item   #只有一个对象,用return


emp = find_employee_by_eid()
print(emp.__dict__)


# 定义函数,在员工列表中查找部门是9001的所有员工
def find_employees_by_did():
    for item in list_employees:
        if item.did == 9001:
            yield item   #多个对象用yield

generator = find_employees_by_did()
for item in generator:
    print(item.__dict__)


# 定义函数,在员工列表中查找薪资最高的员工
def get_max_by_money():
    max_value = list_employees[0]
    for i in range(1, len(list_employees)):
        if max_value.money < list_employees[i].money:
            max_value = list_employees[i]
    return max_value

emp = get_max_by_money()
print(emp.__dict__)

# 定义函数,在员工列表中查找所有薪资大于20000的员工姓名
def find_names_by_money():
    for item in list_employees:
        if item.money > 20000:
            yield item.name


for item in find_names_by_money():
    print(item)

你可能感兴趣的:(python,python,pycharm,django)