python学习笔记04

python学习笔记之04.

迭代器和生成器

迭代器

迭代是Python最强大的功能之一,是访问集合元素的一种方式。
迭代器是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。

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

实例(Python 3.0+)

>>>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
生成器

在 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

装饰器

引用知乎大神非常形象的比喻:
https://www.zhihu.com/question/26930016

内裤可以用来遮羞,但是到了冬天它没法为我们防风御寒,聪明的人们发明了长裤,有了长裤后宝宝再也不冷了,装饰器就像我们这里说的长裤,在不影响内裤作用的前提下,给我们的身子提供了保暖的功效。

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

下面是一个重写了特殊方法 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
>>>

作业

员工信息管理程序
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("命令不存在或者输入错误,请仔细检查后重新输入!", "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("没有这个命令,请确认!", "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)

    # 添加纪录
    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("存在重复的手机号码,请确认!", "error")

    # 判断手机号是否存在
    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

    # 加载数据表
    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

    # 读取数据表的最后一行
    def __read_last_line(self):
        with codecs.open(self.file_path, 'r', "UTF-8") as f:  # 打开文件
            lines = f.readlines()
            return lines[-1]  # 取最后一行

    # 获取最后一个id,实现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)

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

推荐阅读更多精彩内容

  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 18,934评论 17 410
  • 今天7点钟就上班了,奋战了一天,最后还加了一个小时的班。 下午陈睿去白云区了,搬了一点东西走,回到家后,感觉家里 ...
    清和简阅读 181评论 0 0
  • 《一路同行》 原曲:罗大佑 《明天会更好》 填词:邝鉴萍 演唱:【光明顶】邝鉴萍、关炳刚、周铂淏、张宇 不愿看你远...
    邝鉴萍阅读 215评论 0 6
  • 夜幕拉开放飞几粒星辰 湖水蛹动筑起几道波纹 月与月的对称忽略了轴心 我一个人,披着雾踏着林 蛐蛐大概因为贪嗅了花粉...
    靠劲儿阅读 235评论 0 0
  • 高考成绩已经出炉,不管你们成绩如何,都要清楚,成功不必自满,失败不必伤心。因为,人生就是不断清零的过程。 但有些事...
    f5c8375254c2阅读 422评论 0 9