Zhong__Python迭代器/生成器

时间:2020.12.11

环境:Python3

目的:迭代器/生成器学习

说明:

作者:Zhong QQ交流群:121160124 欢迎加入!

 

迭代器

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

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

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

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

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

import sys

# 定义一个列表
ls = ["a","b"]

# 创建迭代器对象
iter_obj = iter(ls)

# 查看类型
print(type(iter_obj))  # <class 'list_iterator'>

# # 输出迭代器的下一个元素
# print(next(iter_obj))  # a
#
# # 输出迭代器的下一个元素
# print(next(iter_obj))  # b
#
# # 输出迭代器的下一个元素
# print(next(iter_obj))  # StopIteration

while True:
    try:
        print(next(iter_obj))
    except StopIteration:
        sys.exit()

 

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

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

__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))  # 1
print(next(myiter))  # 2
print(next(myiter))  # 3  
print(next(myiter))  # 4
print(next(myiter))  # 5

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

 

生成器

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

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

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

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

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

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=" ")  # 0 1 1 2 3 5 8 13 21 34 55 
    except StopIteration:
        sys.exit()

 

关注微信公众号

 

 

 

 

#include <Windows.h> #include <string> #include <vector> #include <unordered_map> #include <queue> #include <climits> #include <sstream> #include "Resource.h" // 登录对话框的消息处理函数 INT_PTR CALLBACK LoginDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_COMMAND: if (wp == IDOK || wp == IDCANCEL) { EndDialog(hDlg, wp); return TRUE; } break; case WM_CLOSE: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } // 主界面对话框的消息处理函数(修改) INT_PTR CALLBACK MainDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_COMMAND: if (wp == IDOK || wp == IDCANCEL) { EndDialog(hDlg, wp); return TRUE; } break; case WM_CLOSE: EndDialog(hDlg, IDCANCEL); return TRUE; } return FALSE; } // 定义校园地点(顶点) enum CampusPlace { PLACE_BEI_DAMEN, // 北大门 PLACE_XI_DAMEN, // 西大门 PLACE_NAN_DAMEN, // 南大门 PLACE_SONGSHAN_HU, // 松山湖 PLACE_XIN_TIYU_CHANG, // 新体育场 PLACE_OLD_TIYU_CHANG, // 老体育场 PLACE_LEQUN_LOU, // 乐群楼 PLACE_QIUZHEN_LOU, // 求真楼 PLACE_JINGYE_LOU, // 敬业楼 PLACE_HOU_CUN_G1, // 乐业楼 PLACE_HAI_TANG_YUAN, // 海棠苑 PLACE_WU_TONG_YUAN, // 梧桐苑 PLACE_XUE_SHU_JIAO_LIU_ZHONG_XIN ,// 学术交流中心 PLACE_SHUANG_CHUANG_LOU, //双创大楼 PLACE_GONG_YE_ZHONG_XIN, //工业中心 PLACE_XING_ZHEN_LOU, //行政楼 PLACE_JUN_ZHU_YUAN, //筠竹苑 PLACE_XIANG_ZHANG_YUN, //香樟苑 PLACE_SAN_SI_SHI_TANG, //第二食堂 PLACE_YI_ER_SHI_TANG, //第一食堂 }; // 地点名称映射 const std::unordered_map<CampusPlace, std::wstring> PlaceNames = { {PLACE_BEI_DAMEN, L"北大门"}, {PLACE_XI_DAMEN, L"西大门"}, {PLACE_NAN_DAMEN, L"南大门"}, {PLACE_SONGSHAN_HU, L"松山湖"}, {PLACE_XIN_TIYU_CHANG, L"新体育场"}, {PLACE_OLD_TIYU_CHANG, L"老体育场"}, {PLACE_LEQUN_LOU, L"乐群楼"}, {PLACE_QIUZHEN_LOU, L"求真楼"}, {PLACE_JINGYE_LOU, L"敬业楼"}, {PLACE_HOU_CUN_G1, L"乐业楼"}, {PLACE_HAI_TANG_YUAN, L"海棠苑"}, {PLACE_WU_TONG_YUAN, L"梧桐苑"}, {PLACE_XUE_SHU_JIAO_LIU_ZHONG_XIN, L"学术交流中心"}, {PLACE_SHUANG_CHUANG_LOU, L"双创大楼"}, {PLACE_GONG_YE_ZHONG_XIN,L"工业中心"}, {PLACE_XING_ZHEN_LOU,L"行政楼"}, {PLACE_JUN_ZHU_YUAN,L"筠竹苑"}, {PLACE_XIANG_ZHANG_YUN,L"香樟苑"}, {PLACE_SAN_SI_SHI_TANG,L"第二食堂"}, {PLACE_YI_ER_SHI_TANG,L"第一食堂"} }; // 优化后的校园地图邻接表 std::unordered_map<CampusPlace, std::vector<std::pair<CampusPlace, int>>> CampusGraph = { // 北大门 {PLACE_BEI_DAMEN, { {PLACE_HOU_CUN_G1, 8}, // 北大门 → 乐业楼 (8分钟) {PLACE_XIN_TIYU_CHANG, 8}, // 北大门 → 新体育场 (8分钟) {PLACE_QIUZHEN_LOU, 15}, // 北大门 → 求真楼 (15分钟,直达) { PLACE_SHUANG_CHUANG_LOU, 3}, {PLACE_GONG_YE_ZHONG_XIN,2}, {PLACE_SAN_SI_SHI_TANG,10}, }}, // 西大门 {PLACE_XI_DAMEN, { {PLACE_WU_TONG_YUAN, 3}, // 西大门 → 梧桐苑 (3分钟) {PLACE_HAI_TANG_YUAN, 5}, // 西大门 → 海棠苑 (5分钟) {PLACE_LEQUN_LOU, 10} // 西大门 → 乐群楼 (10分钟) }}, // 南大门 {PLACE_NAN_DAMEN, { {PLACE_XUE_SHU_JIAO_LIU_ZHONG_XIN, 3}, // 南大门 → 学术交流中心 (3分钟) {PLACE_JINGYE_LOU, 12}, // 南大门 → 敬业楼 (12分钟) {PLACE_SONGSHAN_HU, 15} // 南大门 → 松山湖 (15分钟) }}, // 松山湖 {PLACE_SONGSHAN_HU, { {PLACE_XIN_TIYU_CHANG, 3}, // 松山湖 → 新体育场 (3分钟) {PLACE_OLD_TIYU_CHANG, 4}, // 松山湖 → 老体育场 (4分钟) {PLACE_HAI_TANG_YUAN, 6}, // 松山湖 → 海棠苑 (6分钟) {PLACE_NAN_DAMEN, 15} // 松山湖 → 南大门 (15分钟) }}, // 新体育场 {PLACE_XIN_TIYU_CHANG, { {PLACE_BEI_DAMEN, 8}, // 新体育场 → 北大门 (8分钟) {PLACE_SONGSHAN_HU, 3}, // 新体育场 → 松山湖 (3分钟) {PLACE_OLD_TIYU_CHANG, 5} // 新体育场 → 老体育场 (5分钟) }}, // 老体育场 {PLACE_OLD_TIYU_CHANG, { {PLACE_SONGSHAN_HU, 4}, // 老体育场 → 松山湖 (4分钟) {PLACE_XIN_TIYU_CHANG, 5}, // 老体育场 → 新体育场 (5分钟) {PLACE_LEQUN_LOU, 2} // 老体育场 → 乐群楼 (2分钟) }}, // 乐群楼 {PLACE_LEQUN_LOU, { {PLACE_OLD_TIYU_CHANG, 2}, // 乐群楼 → 老体育场 (2分钟) {PLACE_QIUZHEN_LOU, 3}, // 乐群楼 → 求真楼 (3分钟) {PLACE_JINGYE_LOU, 4}, // 乐群楼 → 敬业楼 (4分钟) {PLACE_XI_DAMEN, 10} // 乐群楼 → 西大门 (10分钟) }}, // 求真楼 {PLACE_QIUZHEN_LOU, { {PLACE_LEQUN_LOU, 3}, // 求真楼 → 乐群楼 (3分钟) {PLACE_BEI_DAMEN, 15}, // 求真楼 → 北大门 (15分钟) {PLACE_JINGYE_LOU, 2} // 求真楼 → 敬业楼 (2分钟) }}, // 敬业楼 {PLACE_JINGYE_LOU, { {PLACE_LEQUN_LOU, 4}, // 敬业楼 → 乐群楼 (4分钟) {PLACE_QIUZHEN_LOU, 2}, // 敬业楼 → 求真楼 (2分钟) {PLACE_NAN_DAMEN, 12} // 敬业楼 → 南大门 (12分钟) }}, // 乐业楼 {PLACE_HOU_CUN_G1, { {PLACE_BEI_DAMEN, 5}, // 航训楼G1 → 北大门 (5分钟) {PLACE_XIN_TIYU_CHANG, 10}, // 航训楼G1 → 新体育场 (10分钟) {PLACE_LEQUN_LOU, 4} }}, // 海棠苑 {PLACE_HAI_TANG_YUAN, { {PLACE_SONGSHAN_HU, 6}, // 海棠苑 → 松山湖 (6分钟) {PLACE_WU_TONG_YUAN, 2}, // 海棠苑 → 梧桐苑 (2分钟) {PLACE_XI_DAMEN, 5} // 海棠苑 → 西大门 (5分钟) }}, // 梧桐苑 {PLACE_WU_TONG_YUAN, { {PLACE_HAI_TANG_YUAN, 2}, // 梧桐苑 → 海棠苑 (2分钟) {PLACE_XI_DAMEN, 3} // 梧桐苑 → 西大门 (3分钟) }}, // 学术交流中心 {PLACE_XUE_SHU_JIAO_LIU_ZHONG_XIN, { {PLACE_NAN_DAMEN, 3}, // 学术交流中心 → 南大门 (3分钟) {PLACE_JINGYE_LOU, 10} // 学术交流中心 → 敬业楼 (10分钟) }} }; // Dijkstra算法:计算起点到终点的最短路径 std::pair<std::vector<CampusPlace>, int> DijkstraShortestPath(CampusPlace start, CampusPlace end) { // 距离数组:记录每个地点的最短距离 std::unordered_map<CampusPlace, int> dist; // 前驱节点数组:记录路径 std::unordered_map<CampusPlace, CampusPlace> prev; // 优先队列(小顶堆):存储 (当前距离, 地点) std::priority_queue<std::pair<int, CampusPlace>, std::vector<std::pair<int, CampusPlace>>, std::greater<std::pair<int, CampusPlace>>> pq; // 1. 初始化所有距离为无穷大 for (const auto& entry : CampusGraph) { dist[entry.first] = INT_MAX; prev[entry.first] = (CampusPlace)-1; } // 起点到自身的距离为0 dist[start] = 0; pq.push({0, start}); while (!pq.empty()) { // 2. 取出当前距离最小的节点 auto current = pq.top().second; pq.pop(); // 如果已经到达终点,可以提前退出以提高效率 if (current == end) { break; } // 3. 遍历当前节点的所有邻居 for (const auto& neighbor_pair : CampusGraph[current]) { CampusPlace next_place = neighbor_pair.first; int weight = neighbor_pair.second; // 4. 松弛操作:更新距离 if (dist[current] != INT_MAX && dist[next_place] > dist[current] + weight) { dist[next_place] = dist[current] + weight; prev[next_place] = current; // 更新前驱节点 pq.push({dist[next_place], next_place}); } } } // 5. 从终点回溯到起点,重建路径 std::vector<CampusPlace> path; if (dist[end] != INT_MAX) { // 只有当终点可达时才重建路径 for (CampusPlace p = end; p != (CampusPlace)-1; p = prev[p]) { path.push_back(p); } std::reverse(path.begin(), path.end()); // 反转路径,使其从起点到终点 } // 返回路径和总距离,如果不可达,总距离为-1 return {path, dist[end] == INT_MAX ? -1 : dist[end]}; } // 导航对话框的消息处理函数 INT_PTR CALLBACK NaviDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_INITDIALOG: { // 初始化起点/终点下拉框 HWND hComboStart = GetDlgItem(hDlg, IDC_COMBO_START); HWND hComboEnd = GetDlgItem(hDlg, IDC_COMBO_END); // 向下拉框添加地点选项 for (const auto& entry : PlaceNames) { SendMessage(hComboStart, CB_ADDSTRING, 0, (LPARAM)entry.second.c_str()); SendMessage(hComboEnd, CB_ADDSTRING, 0, (LPARAM)entry.second.c_str()); } // 默认选择第一个选项 SendMessage(hComboStart, CB_SETCURSEL, 0, 0); SendMessage(hComboEnd, CB_SETCURSEL, 1, 0); return TRUE; } case WM_COMMAND: { if (LOWORD(wp) == IDC_BTN_QUERY) { // 点击“查询路径”按钮 HWND hComboStart = GetDlgItem(hDlg, IDC_COMBO_START); HWND hComboEnd = GetDlgItem(hDlg, IDC_COMBO_END); HWND hEditPath = GetDlgItem(hDlg, IDC_EDIT_PATH); // 获取选择的起点/终点索引 int startIdx = SendMessage(hComboStart, CB_GETCURSEL, 0, 0); int endIdx = SendMessage(hComboEnd, CB_GETCURSEL, 0, 0); if (startIdx == CB_ERR || endIdx == CB_ERR) { MessageBox(hDlg, L"请选择起点和终点!", L"提示", MB_ICONINFORMATION); return TRUE; } // 转换为CampusPlace枚举 CampusPlace start = (CampusPlace)startIdx; CampusPlace end = (CampusPlace)endIdx; // 计算最短路径 auto [path, totalTime] = DijkstraShortestPath(start, end); if (path.empty() || totalTime == INT_MAX) { SetWindowText(hEditPath, L"无法到达该地点!"); return TRUE; } // 格式化路径文本 std::wstringstream ss; ss << L"最短路径(步行约" << totalTime << L"分钟):\n"; for (size_t i = 0; i < path.size(); ++i) { ss << PlaceNames.at(path[i]); if (i != path.size() - 1) ss << L" → "; } SetWindowText(hEditPath, ss.str().c_str()); return TRUE; } // 处理关闭/取消按钮 else if (LOWORD(wp) == IDOK || LOWORD(wp) == IDCANCEL) { EndDialog(hDlg, LOWORD(wp)); return TRUE; } break; } case WM_CLOSE: { EndDialog(hDlg, IDCANCEL); return TRUE; } } return FALSE; } int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) { // 1. 显示登录对话框 INT_PTR nLoginResult = DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), nullptr, LoginDlgProc); // 2. 如果登录成功(点击“确定”),显示主界面 if (nLoginResult == IDOK) { INT_PTR nMainResult = DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG2), nullptr, MainDlgProc); // 3. 如果主界面点击“确定”,显示导航界面 if (nMainResult == IDOK) { DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG3), nullptr, NaviDlgProc); } } // 所有界面关闭后,程序退出 return 0; }在这段程序上添加哈夫曼编码和解码 和走迷宫(图的遍历算法)
最新发布
11-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我变了_我没变

随意 。。。

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

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

打赏作者

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

抵扣说明:

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

余额充值