python學(xué)習(xí)筆記之04.
迭代器和生成器
迭代器
迭代是Python最強(qiáng)大的功能之一秆撮,是訪問集合元素的一種方式。
迭代器是一個可以記住遍歷的位置的對象船侧。
迭代器對象從集合的第一個元素開始訪問欠气,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會后退镜撩。
迭代器有兩個基本的方法:iter() 和 next()预柒。
字符串,列表或元組對象都可用于創(chuàng)建迭代器:
實例(Python 3.0+)
>>>list=[1,2,3,4]
>>> it = iter(list) # 創(chuàng)建迭代器對象
>>> print (next(it)) # 輸出迭代器的下一個元素
1
>>> print (next(it))
2
>>>
迭代器對象可以使用常規(guī)for語句進(jìn)行遍歷:
實例(Python 3.0+)
#!/usr/bin/python3
list=[1,2,3,4]
it = iter(list) # 創(chuàng)建迭代器對象
for x in it:
print (x, end=" ")
執(zhí)行以上程序袁梗,輸出結(jié)果如下:
1 2 3 4
也可以使用 next() 函數(shù):
實例(Python 3.0+)
#!/usr/bin/python3
import sys # 引入 sys 模塊
list=[1,2,3,4]
it = iter(list) # 創(chuàng)建迭代器對象
while True:
try:
print (next(it))
except StopIteration:
sys.exit()
執(zhí)行以上程序宜鸯,輸出結(jié)果如下:
1
2
3
4
生成器
在 Python 中,使用了 yield 的函數(shù)被稱為生成器(generator)遮怜。
跟普通函數(shù)不同的是淋袖,生成器是一個返回迭代器的函數(shù),只能用于迭代操作奈泪,更簡單點理解生成器就是一個迭代器适贸。
在調(diào)用生成器運行的過程中,每次遇到 yield 時函數(shù)會暫停并保存當(dāng)前所有的運行信息涝桅,返回 yield 的值, 并在下一次執(zhí)行 next() 方法時從當(dāng)前位置繼續(xù)運行拜姿。
調(diào)用一個生成器函數(shù),返回的是一個迭代器對象冯遂。
以下實例使用 yield 實現(xiàn)斐波那契數(shù)列:
實例(Python 3.0+)
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函數(shù) - 斐波那契
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()
執(zhí)行以上程序,輸出結(jié)果如下:
0 1 1 2 3 5 8 13 21 34 55
裝飾器
引用知乎大神非常形象的比喻:
https://www.zhihu.com/question/26930016
內(nèi)褲可以用來遮羞,但是到了冬天它沒法為我們防風(fēng)御寒壁却,聰明的人們發(fā)明了長褲批狱,有了長褲后寶寶再也不冷了,裝飾器就像我們這里說的長褲展东,在不影響內(nèi)褲作用的前提下赔硫,給我們的身子提供了保暖的功效。
裝飾器本質(zhì)上是一個Python函數(shù)盐肃,它可以讓其他函數(shù)在不需要做任何代碼變動的前提下增加額外功能爪膊,裝飾器的返回值也是一個函數(shù)對象。它經(jīng)常用于有切面需求的場景砸王,比如:插入日志推盛、性能測試、事務(wù)處理谦铃、緩存耘成、權(quán)限校驗等場景。裝飾器是解決這類問題的絕佳設(shè)計驹闰,有了裝飾器瘪菌,我們就可以抽離出大量與函數(shù)功能本身無關(guān)的雷同代碼并繼續(xù)重用。概括的講疮方,裝飾器的作用就是為已經(jīng)存在的對象添加額外的功能控嗜。
下面是一個重寫了特殊方法 getattribute 的類裝飾器, 可以打印日志:
def log_getattribute(cls):
# Get the original implementation
orig_getattribute = cls.__getattribute__
# Make a new definition
def new_getattribute(self, name):
print('getting:', name)
return orig_getattribute(self, name)
# Attach to the class and return
cls.__getattribute__ = new_getattribute
return cls
# Example use
@log_getattribute
class A:
def __init__(self,x):
self.x = x
def spam(self):
pass
下面是使用效果:
>>> a = A(42)
>>> a.x
getting: x
42
>>> a.spam()
getting: spam
>>>
作業(yè)
員工信息管理程序
staffs.txt
3,Rain Wang,21,13451054608,IT,2017‐04‐01
4,Mack Qiao,44,15653354208,Sales,2016‐02‐01
5,Rachel Chen,23,13351024606,IT,2013‐03‐16
6,Eric Liu,19,18531054602,Marketing,2012‐12‐01
7,Chao Zhang,21,13235324334,Administration,2011‐08‐08
8,Kevin Chen,22,13151054603,Sales,2013‐04‐01
9,Shit Wen,20,13351024602,IT,2017‐07‐03
10,Shanshan Du,26,13698424612,Operation,2017‐07‐02
11,Libai,26,134435366,IT,2015‐10‐2
12,Libai,26,134435366,IT,2015‐10‐23
StaffManage.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Created by master on 2018/5/21 16:45.
import codecs
import os
from tabulate import tabulate
class StaffManage(object):
file_path = "staffs.txt"
# 增刪改查入口
def manage(self, sql):
lower_sql = sql.lower()
if lower_sql.startswith("add"):
self.add(sql)
elif lower_sql.startswith("del"):
self.remove(sql)
elif lower_sql.startswith("update"):
self.update(sql)
elif lower_sql.startswith("find"):
self.find(sql)
elif lower_sql.startswith("exit"):
exit("退出程序")
else:
log("命令不存在或者輸入錯誤骡显,請仔細(xì)檢查后重新輸入疆栏!", "error")
# 查詢
def find(self, sql):
'''
find name,age from staff_table where age > 22
find * from staff_table where dept = "IT"
find * from staff_table where enroll_date like "2013"
'''
lower_sql = sql.lower()
lower_sql = lower_sql.replace("find", "").replace("*", "").replace("from", "") \
.replace("staff_table", "").replace('"', "").replace("'", "").strip()
list_param = lower_sql.split("where")
new_staffs = []
if list_param[0]:
log("沒有這個命令,請確認(rèn)惫谤!", "error")
else:
list_staff = self.load_file()
if "=" in list_param[1]:
key = list_param[1].split("=")[0].strip()
value = list_param[1].split("=")[1].strip()
for staff in list_staff:
if staff[key].lower() == value:
new_staffs.append(staff)
elif "like" in list_param[1]:
key = list_param[1].split("like")[0].strip()
value = list_param[1].split("like")[1].strip()
for staff in list_staff:
if value in staff[key].lower():
new_staffs.append(staff)
else:
if ">" in list_param[1]:
key = list_param[1].split(">")[0].strip()
value = list_param[1].split(">")[1].strip()
for staff in list_staff:
if int(staff[key]) > int(value):
new_staffs.append(staff)
elif "<" in list_param[1]:
key = list_param[1].split("<")[0].strip()
value = list_param[1].split("<")[1].strip()
for staff in list_staff:
if int(staff[key]) < int(value):
new_staffs.append(staff)
print_table(new_staffs)
# 添加紀(jì)錄
def add(self, sql):
# "add staff_table Alex Li,25,134435344,IT,2015‐10‐29"
sql = "0," + sql.replace("add", "").replace("ADD", "").replace("staff_table", "").strip()
d_staff = self.__split_line(sql)
if not self.phone_exist(self.load_file(), d_staff["phone"]):
d_staff["staff_id"] = str(int(self.__get_last_staff_id()) + 1)
self.__insert([d_staff])
log("影響了1行")
else:
log("存在重復(fù)的手機(jī)號碼壁顶,請確認(rèn)!", "error")
# 判斷手機(jī)號是否存在
def phone_exist(self, staffs, phone):
phones = []
for staff in staffs:
phones.append(staff["phone"])
return phone in phones
# 插入記錄
def __insert(self, staffs, mode="a+"):
with codecs.open(self.file_path, mode, "utf-8") as f:
for i in range(len(staffs)):
staff = staffs[i]
record = ""
len_values = len(staff.values())
for j in range(len_values):
v = list(staff.values())[j]
if j < len_values - 1:
record += v + ","
else:
record += v
if i > 0:
f.write("\n" + record)
else:
f.write(record)
# 更新記錄
def update(self, sql):
effect_lines = 0
lower_sql = sql.lower()
lower_sql = lower_sql.replace("update", "").replace("staff_table", "") \
.replace('"', "").replace('set', "").replace("'", "").strip()
list_param = lower_sql.split("where")
u_key = list_param[0].split("=")[0].strip()
u_value = list_param[0].split("=")[1].strip()
o_key = list_param[1].split("=")[0].strip()
o_value = list_param[1].split("=")[1].strip()
list_staff = self.load_file()
for staff in list_staff:
if staff[o_key].lower() == o_value:
staff[u_key] = u_value
effect_lines += 1
log("影響了%s行" % effect_lines)
self.__insert(list_staff, "w")
# 刪除記錄
def remove(self, sql):
# del from staff where id=3
effect_lines = 0
sql = sql.lower().replace("del", "").replace("from", "").replace("staff_table", "") \
.replace("where", "").strip()
list_param = sql.split("=")
id = list_param[1].strip()
list_staff = self.load_file()
for staff in list_staff:
if staff["staff_id"] == id:
list_staff.remove(staff)
effect_lines += 1
else:
return
log("影響了%s行" % effect_lines)
self.__insert(list_staff, "w")
# 切分sql,提取有效字段
def __split_line(self, line):
list_param = line.split(",")
d_staff = {}
for i in range(len(list_param)):
if i == 0:
d_staff["staff_id"] = list_param[i].strip()
elif i == 1:
d_staff["name"] = list_param[i].strip()
elif i == 2:
d_staff["age"] = list_param[i].strip()
elif i == 3:
d_staff["phone"] = list_param[i].strip()
elif i == 4:
d_staff["dept"] = list_param[i].strip()
elif i == 5:
d_staff["enroll_date"] = list_param[i].strip()
return d_staff
# 加載數(shù)據(jù)表
def load_file(self):
if os.path.exists(self.file_path):
list_staffs = []
with codecs.open(self.file_path, "r", "UTF-8") as staff_list:
for line in staff_list:
staff = self.__split_line(line)
list_staffs.append(staff)
return list_staffs
# 讀取數(shù)據(jù)表的最后一行
def __read_last_line(self):
with codecs.open(self.file_path, 'r', "UTF-8") as f: # 打開文件
lines = f.readlines()
return lines[-1] # 取最后一行
# 獲取最后一個id溜歪,實現(xiàn)id自增
def __get_last_staff_id(self):
line = self.__read_last_line()
d_staff = self.__split_line(line)
return d_staff["staff_id"]
# 日志工具
def log(msg, log_type="info"):
if log_type == 'info':
print("\033[32;1m%s\033[0m" % msg)
elif log_type == 'error':
print("\033[31;1m%s\033[0m" % msg)
# 打印表格
def print_table(staffs):
print(tabulate(staffs, tablefmt="grid"))
if __name__ == '__main__':
staffManage = StaffManage()
while True:
sql_eval = input(">>>")
staffManage.manage(sql_eval)