• 章节二十:项目实操:毕业项目


    章节二十:项目实操:毕业项目

    今天是你的毕业礼,按照国际惯例,理应会有毕业寄语。不过告别的话总得最后说,我们还是先来完成我们的最后一个项目吧。

    相信经历过前面几个项目实操的磨练,相信现在的你看到比较长的代码是淡定得很吧。

    毕业项目背景是这样的:这个项目是我公司的一个小姐姐,在原本零基础的情况下学完Python基础语法课后帮朋友做出来的。偷偷告诉你,其实就是你也很熟悉的酱酱。

    然后她跑来跟我“吹嘘”,因为这个小程序,朋友得到了老板额外给的一笔奖金,然后请了她大餐一顿。

    我一看,哟~这小姑娘就是拿了我在课堂上教的东西去“班门弄斧”了嘛,但我却颇感欣慰,我写的课是实实在在能够帮助人啊(流下了老父亲的泪水)。

    所谓赠人代码,手有余香,相信酱酱会更加努力学Python的吧。

    老规矩,项目三部曲,先来看这个项目目标是什么。

    1. 明确项目目标

    因为这个程序应用的场景比较特殊,没有相关经验的同学可能不太理解,所以我会先花点功夫把我们要做的项目讲得清楚一些。(以下我会称酱酱的朋友为A君)

    A君目前在一家资产评估公司实习,他的工作日常就是跑遍市区里的住宅小区,调查小区的地址、建筑年份和每栋楼里每个单元里每一户的朝向和面积。

    比如一户的资料是:富安花园(小区)3栋 2单元 401户;朝向:南北朝向;面积:90平方。他需要把每一户的信息都记录下来。

    为了节省时间,通常他们会当场把一栋楼里所有单元的数据画在一张平面图里。等回去之后,再把平面图记录的数据,录入到excel表里。

    image.png-400.1kB

    举个例子,上面这张平面图表示的是这一栋有4个单元,每个单元有15层楼,其中1,2单元有两户,面积和朝向是140平方,南北朝向。

    3单元有四户,有2户面积60平方,南北朝向,2户面积80平方,东西朝向;4单元有四户,面积70平方,东西朝向。

    A君向酱酱抱怨原本看房已经很累人了,录入更烦。可能你觉得用excel的自动填充功能不是很方便吗,事情远没有这么简单。

    确实,有一些重复的单元格只要填一次,自动下拉就可以复制粘贴,对于A君(excel菜鸟)来说,每次只要手动输入户室号就可以。(当然掌握一些excel技巧可以节省一些功夫)

    image.png-250.3kB

    不过,不同单元的户数、朝向和面积不完全是一样的,所以不能以一个单元的数据复制给其他单元。

    比如说,好不容易输入了1单元的数据,复制给了2单元,但因为3单元有4户,面积和朝向都不一样,所以3单元又得重新处理,户室号、面积、朝向都不一样。

    image.png-236.9kB

    好不容易搞完3单元,到了4单元,面积和朝向又不一样了。求此时A君心里的阴影面积。

    再者,一栋楼通常就有两三百条数据,通常一个小区有多栋楼,每栋楼的构造也不太一样,如果要把一个片区的数据放在一个表里,可能就有好几千条数据。

    在这让人有密集恐惧的数据面前,数据一多,就很容易出错。一旦出错,一是难以发现,二是改起来挺费劲,牵连甚广。如果你经常和excel打交道的话,我想你多少能感同身受。

    这样经历了和excel斗智斗勇斗出个斗鸡眼的一段时间后,A君给酱酱发了一个求助的微信:不是说Python能解决重复性劳动咩?你给我支支招呗!

    于是酱酱捣鼓了一番,做出来了这么一个程序:

    image.png-1074.2kB

    只要在终端输入一些模版数据,程序就可以自动录入剩下的数据,甚至连excel都不用打开。

    在终端运行该程序后,打开excel对应的文件,就会发现数据是按一定的规律录入好的。

    image.png-393.3kB

    所以,我们今天的任务就是把这个程序做出来。在此,奖励酱酱一个酱香鸡腿。(如果大家私下做出来自己挺满意的程序,可以和助教分享噢,说不定会出现在以后的课堂里)

    当然你的工作可能不像A君这样要处理这样的事情,但我仍希望你能从中找到一些解决问题的共性,迁移到你或许能应用到的工作场景中。

    2. 分析过程,拆解项目

    为了便于教学,今天我们的目的是希望把一个小区某一栋楼内的所有户室的资料录入到excel表里,这栋楼的资料是这样子的:

    image.png-112.9kB

    上一关我们学到了流程图,我们可以尝试将实现过程拆解成流程图的步骤。

    酱酱当时画了个简陋版的流程图:

    image.png-77.8kB

    可见,这里的关键点是找到数据中的规律,确定可以复用的模版数据,我们在模块那关也学到csv模块是可以处理excel文件格式的,所以老师将这一项目拆解成3个版本,也可以当成是三大步骤。

    image.png-82.5kB

    具体每一版本要做的工作,我们一个个来看吧。

    3. 逐步执行,代码实现

    首先,我们需要了解我们需要什么数据,也就是表格里的表头,这些一般是业务规定的,没有什么商量的余地。

    3.1 版本1.0: 输入表头,确定模版数据

    当我们要在Python读写excel的时候,调用csv模块是个很好的选择。相信你对csv文件读写的知识还有印象吧,下面就请你根据提示补全代码,往csv写入表头。

    image.png-221.7kB

    import csv
    #调用csv模块
    with open('assets.csv', 'a', newline='') as csvfile:
    #调用open()函数打开csv文件,传入参数:文件名“assets.csv”、追加模式“a”、newline=''。
        writer = csv.writer(csvfile, dialect='excel')
        # 用csv.writer()函数创建一个writer对象。
        header=['小区名称', '地址', '建筑年份', '楼栋', '单元', '户室', '朝向', '面积']
        writer.writerow(header)
        #用writerow()函数将表头写进csv文件里
    

    此时,如果你复制代码到本地编辑器运行,就会在py文件所在的文件夹里,看到新建了一个名为assets的csv文件,打开的话就是这样的:

    image.png-90.4kB

    这里稍微提一下,如果你用的是Mac电脑,当你直接用excel打开csv文件可能会显示乱码,这是因为Mac电脑打开excel是默认用GBK编码处理中文的,而Python默认是UTF-8编码,所以导致加载出来是乱码。

    解决方案是Mac用户要在open()函数里加上参数'encoding='GBK'(如果选择用Numbers打开就不需要)

    with open('assets.csv', 'a', newline='',encoding='GBK') as csvfile:
    

    确定好表头之后,接下来,我们要确定以哪些数据为模版数据,也就是哪些数据只需输入一次便可重复利用,写入循环。

    我们一个个来看,一个小区一栋楼的小区名称、地址、建筑年份、肯定是相同的,所以可以输入一次,复用所有。

    title = input('请输入小区名称')
    address = input('请输入小区地址:')
    year = input('请输入小区建造年份:')
    block = input('请输入楼栋号:')
    

    而同一栋内部的单元分布也许是不同的,比如说有的单元只有两户室,有的单元有四户室,所以它的房间朝向、面积也会不同,所以一个单元的数据不能做模板数据。

    我们再缩小范围,我们会发现在同一单元下,每一楼的户型和朝向一般是一样的,也就是只需要知道一个单元下某一楼层的数据,该单元的其它楼层都可以复用,区别只是户室号。

    确定了以此为模版数据,下一阶段我们就来看看具体怎么转化成代码的形式。

    3.2 阶段2:获取、复用模版数据

    在阶段1,我们已经确定了模版数据是一个单元下某一层楼的数据,也就是说我们只要拿到起始楼层的每个户室的数据(朝向和面积),这个单元内其他楼层的户室都可以套用。

    而户室号一般是由楼层+后两位序号(以下我会简称为尾号)组成的,如201,202,203,204;301,302,303,304...尾号是统一的,变的只是前面的楼层数(每层加一),所以户室号拆成两部分处理会方便我们后续的操作。

    那么,接下来,我们就来获取模版数据吧~不过每次获取数据前我们就得想好我们要用什么样的形式存储数据。

    现在我们需要拿到的是起始楼层每一个户室的朝向和面积,我们可以判断出朝向和面积是并列关系,它是从属于户室的。

    image.png-56.7kB

    我们很自然能想到这里用字典嵌套列表的形式会更方便,其中字典的键是户室号,面积和朝向组成的列表为字典的值,类似这种形式。

    start_floor_rooms = {301:['南北',70],302:['南北',70],303:['东西',80],304:['东西',80]}
    #初始楼层的数据
    

    我们一步步来看,首先我们来把第一对键值对 301:['南北',70] 放进字典start_floor_rooms里,这是我们之前反复接触过的,你可以先看代码和注释。

    start_floor = input('请输入起始楼层:')
    end_floor = input('请输入终止楼层:')
    #确定每一单元有几层楼
    
    start_floor_rooms = {}
    #创建字典,存放起始楼层所有户室的信息
    floor_last_number = []
    #创建列表,存放户室的尾号如['01','02','03'],后续楼层可复用
    
    last_number = input('请输入起始楼层户室的尾号:(如01,02)')
    
    floor_last_number.append(last_number)
    #将元素添加到存放户室尾号的列表里,如floor_last_number = ['01']
    
    room_number = int(start_floor + last_number)
    #户室名为room_number,由楼层start_floor和尾号last_number组成,如'301'
    
    direction = int(input('请输入 %d 的朝向(南北朝向输入1,东西朝向输入2):' % room_number ))
    #输入中文比输入数字要麻烦许多,我们可以先用1和2代替
    
    area = int(input('请输入 %d 的面积,单位 ㎡ :' % room_number))
    
    start_floor_rooms[room_number] = [direction,area]
    # 户室号为键,朝向和面积组成的列表为值,添加到字典里,如start_floor_rooms = {301:[1,70]}
    
    print(start_floor_rooms)
    

    你可以运行一下,看看目前的代码的运行结果是什么。

    image.png-498.9kB

    可见,这段代码只能让我们获取起始楼层一个户室的信息,为了获取起始楼层其他户室的信息,我们需要加入循环。

    现在请你在下面代码的基础上改进:【在已经缩进的代码块前加入循环语句】,实现打印效果{301:[1,70],302:[1,70],303:[2,60]}

    image.png-550.2kB

    start_floor = input('请输入起始楼层:')
    end_floor = input('请输入终止楼层:')
    
    input('接下来请依次输入起始层每个房间的户室尾号、南北朝向及面积,按任意键继续')
    
    start_floor_rooms = {}
    floor_last_number = []
    # 收集起始层的房间信息
    
    # 定义循环控制量
    room_loop = True
    while room_loop:
        last_number = input('请输入起始楼层户室的尾号:(如01,02)')
        floor_last_number.append(last_number)
        #将尾号用append()添加列表里,如floor_last_number = ['01','02']
        room_number = int(start_floor + last_number)
        #户室号为room_number,由楼层start_floor和尾号last_number组成,如301
    
        direction = int(input('请输入 %d 的朝向(南北朝向输入1,东西朝向输入2):' % room_number ))
        area = int(input('请输入 %d 的面积,单位 ㎡ :' % room_number))
        start_floor_rooms[room_number] = [direction,area]
        # 户室号为键,朝向和面积组成的列表为值,添加到字典里,如start_floor_rooms = {301:[1,70]}
    
        continued= input('是否需要输入下一个尾号?按 n 停止输入,按其他任意键继续:')
        #加入打破循环的条件
        if continued == 'n':
            room_loop = False
        else:
            room_loop = True
    print(start_floor_rooms)
    

    因为每一单元的户室数不是固定的,所以用while循环会更妥当,所以我们可以先定义一个循环控制量,让循环条件为True,再“人为”地打破循环.

    好的,现在我们就已经获得了起始楼层所有户室的数据,下一步我们就要将这层的数据迁移到其他楼层里,即只需把户室号的楼层数加一。

    image.png-68.2kB

    那怎么迁移呢?我们的第一反应可能是给每一个楼层都创建一个新字典,这样虽然可行,但随着楼层的增加,字典就会有非常多个,不好管理,

    所以把一个单元内所有楼层的数据放在一块会更方便我们的处理,也就是说将每一个楼层的字典统一放在一个存放单元级的字典里,我们希望的格式应该是这样的:

    star_floor = 3
    end_floor = 5
    #为了举例,假设这个单元只有3-5楼
    
    start_floor_rooms = {301:[1,80],302:[1,80],303:[2,90],304:[2,90]}
    #初始楼层的模版数据
    
    unit_rooms={ 3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                }
    #存放了该单元所有楼层数据的字典,键是楼层数,值是每一楼层所有户室的信息,也是一个字典。
    

    虽然unit_rooms这个结构看起来很复杂,但我们分析一下就知道,这是字典嵌套字典的情况。(为了方便讲解,以下我会把最外层的字典称为大字典,里层的字典称为小字典)

    image.png-80kB

    大字典的键是楼层数,值是小字典,而每个小字典和初始楼层start_floor_rooms的数据只是户室号的区别。

    那么接下来我们只需往unit_rooms不断添加键值对就可以了。为了化繁为简,展示重点,接下来我会给出一些固定变量,是我们上一阶段的代码能获取的结果。

    还记得怎么往空字典添加键值对吧?现在请你补全下面代码,打印出unit_rooms,打印结果为{3:{301:[1,80],302:[1,80],303:[2,90]}}

    image.png-180.7kB

    start_floor = '3'
    start_floor_rooms = {301:[1,80],302:[1,80],303:[2,90]}
    #初始楼层的数据
    
    unit_rooms = {}
    unit_rooms[int(start_floor)] = start_floor_rooms
    #创建一个存放单元所有楼层数据的字典
    print(unit_rooms)
    

    现在字典里已经有了3楼所有户室的信息,接下来就是往字典里添加其他楼层的信息(键值对)。

    假设现在的单元只有3楼和4楼,每一楼层都有3个户室,我们来看看怎么把3楼的数据复制给4楼,并放在unit_rooms里。

    image.png-489.8kB

    start_floor = '3'
    end_floor = '4'
    floor_last_number = ['01','02','03']
    # 之前input()输入的数据为str类型
    
    start_floor_rooms = {301:[1,80], 302:[1,80], 303:[2,90]}
    #初始楼层的模版数据
    
    unit_rooms = {}
    #创建一个字典,存储所有楼层的数据
    unit_rooms[int(start_floor)] = start_floor_rooms
    #unit_rooms = {3: {301: [1, 80], 302: [1, 80], 303: [2, 90]}}
    
    floor_rooms = {}
    #给4楼创建一个字典
    for i in range(len(start_floor_rooms)):
        #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
        number = '4' + floor_last_number[i]
        #字符串拼接, number = ['401','402','403']
        info = start_floor_rooms[int(start_floor + floor_last_number[i])]
        # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
        # int(start_floor + floor_last_number[0])= 301 
        # info = [1,80]
    
        floor_rooms[int(number)] = info
        #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
        #循环三次,所以floor_rooms = {401:[1,80], 402:[1,80], 403:[2,90]}
    
    unit_rooms[4] = floor_rooms
    #以4为键,floor_rooms为值,给字典unit_rooms添加键值对
    print(unit_rooms)
    #unit_rooms = {3: {301: [1, 80], 302: [1, 80], 303: [2, 90]}, 4: {401: [1, 80], 402: [1, 80], 403: [2, 90]}}
    

    现在我们已经知道怎么往unit_rooms添加键值对了吧,不过一个单元一般不会只有两层楼,接下来我们就需要加入循环,将所有楼层的数据一次性放进字典unit_rooms里。

    在一开始,我们可以通过input()询问知道一栋楼里有多少层。

    start_floor = input('请输入起始楼层:')
    end_floor = input('请输入终止楼层:')
    

    现在我们假设一栋楼是3-7楼,即start_floor = 3end_floor = 7

    因为楼层是已知的,那么这里用for循环会更方便一些,循环的执行次数应该是除初始楼层之外剩余的楼层数。(因为初始楼层是模版数据,需要手动录入)

    也就是说如果是3-7楼,我们的循环是执行4、5、6、7四次,所以循环的条件就可以写成:

    for floor in range(start_floor + 1, end_floor + 1):  
    # 在此例中,为 for floor in range (4,8)
    

    那么,我们将循环加入上一步,结果就是:

    start_floor = '3'
    end_floor = '7'
    floor_last_number = ['01','02','03']
    start_floor_rooms = {301:[1,80],302:[1,80],303:[2,90]}
    #初始楼层的模版数据
    unit_rooms = {}
    #新建一个存放所有楼层的字典
    unit_rooms[int(start_floor)] = start_floor_rooms
    
    for floor in range(int(start_floor) + 1, int(end_floor) + 1):
            #遍历除初始楼层外的其他楼层
            floor_rooms = {}
            #每个楼层都建立一个字典
            for i in range(len(start_floor_rooms)):
            #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
                number = str(floor) + floor_last_number[i]
                info = start_floor_rooms[int(start_floor + floor_last_number[i])]
                # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
                floor_rooms[int(number)] = info
                #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
            unit_rooms[floor] = floor_rooms
    print(unit_rooms)
    

    直接运行一下,看看效果吧~

    image.png-484kB

    很好,现在我们就把一个单元里所有楼层的数据放进了字典unit_rooms里了,接下来就是写入我们在一开始创建好的csv文件里。

    3.3 阶段3.0:写入csv文件

    在阶段2.0,我们把一个单元内所有户室的数据都存在unit_rooms这个字典里,理论上我们已经可以以单元为单位写入到csv文件,现在最关键的是如何从字典取出我们想要的数据。

    我们来看一开始已经输入过的表头,它们是'小区名称', '地址', '建筑年份', '楼栋', '单元', '户室', '朝向', '面积'

    image.png-90.4kB

    其中'小区名称','地址','建筑年份', '楼栋', '单元'都需要手动输入,并赋值给相应的变量,不过只需输入一遍就能复用到其余所有单元格里。

    title = input('请输入小区名称')
    address = input('请输入小区地址:')
    year = input('请输入小区建造年份:')
    block = input('请输入楼栋号:')
    unit = input('请输入单元号:')
    

    剩下的'户室'、'朝向'和'面积‘都存储在字典unit_rooms里,假设现在字典是长这样的:

    unit_rooms={ 3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                }
    

    我们来思考一下要怎么一次性把户室号(301-304,401-404,501-504)和户室号对应的朝向和面积都一次性取出来呢?

    相信你会有点想法,又有点不太确定,那么就请你打代码试试看吧~

    image.png-179.8kB

    咋样,成功了吗?下面来讲讲我的思路。

    同样我们把最外层的字典unit_rooms成为大字典,里面嵌套的字典成为小字典(sub_dict)。

    image.png-80kB

    可见,大字典的值是小字典(sub_dict),其中户室是小字典的键,朝向是小字典的值(列表)的第0个元素,面积是小字典的值(列表)的第1个元素。

    也就是说我们需要的数据都在大字典的值里,所以第一步我们需要遍历大字典里的键(key),来取出值(value)。

    有些同学可能会这么写:

    image.png-202.3kB

    unit_rooms={ 3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                }
    for i in range(3,6):
        sub_dict = unit_rooms[i]
        print(sub_dict) 
    

    这当然没问题,不过老师在这里想给大家介绍一种新方法,可以直接遍历字典里所有的值,这样就不用去数字典里有多少个键值对了。它的语法是:

    for value in DictName.values():
    # value的名字可以自行另取
    # DictName是要遍历的字典的名称
    # .values():是固定的用法
    

    所以,如果我们要取出unit_rooms的值,就可以写成:

    image.png-200.3kB

    unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                }
    for sub_dict in unit_rooms.values():
        print(sub_dict)
    

    好,现在我们已经取出小字典(sub_dict)了,前面我们分析过户室号是sub_dict的键,朝向和面积是sub_dict的值,所以下一步就是要遍历sub_dict的键和值,这里老师也介绍一种新的语法。

    for k,v in DictName.items():
    #遍历字典的键值对,k对应键,v对应值
    #k,v 的名字可以自己取,DictName是字典名
    

    举个例子,你可以运行以下代码看看结果。

    image.png-156.3kB

    tv_dict = {'芒果台':'湖南卫视', '荔枝台':'江苏卫视', '番茄台':'东方卫视'}    
    for logo,name in tv_dict.items():
        print(logo + '是' + name)
    

    回到正题,现在请你在下列代码的基础下,补全代码,打印出字典下每一户室的门牌号、朝向和面积,格式为:【户室号:301 朝向:1 面积:80 】

    image.png-365.9kB

    unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                 }
    for sub_dict in unit_rooms.values():
        for room,info in sub_dict.items():
        #room对应的是键,即户室号;info对应的是sub_dict的值,是一个列表
            print('户室号:%d 朝向 %d 面积:%d' % (room,info[0],info[1]))
            #info[0]对应的是朝向,info[1]对应的是面积
    

    现在还有个细节是一开始我们将'南北'记成1,'东西'记成2,所以现在我们需要改回来,当然你可以写入csv文件再全部替换,不过我们还是有始有终,在Python完成操作吧。

    事实上我们用条件判断和赋值语句就可以了。

    unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                 }
    for sub_dict in unit_rooms.values():
        for room,info in sub_dict.items():
            if info[0] == 1:
                info[0] = '南北'
            elif info[0] == 2:
                info[0] = '东西'
    

    在这里,我也介绍另外一种方法,是对列表索引的活用,留意第7行和第9行的代码。

    unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                 }
    for sub_dict in unit_rooms.values():
        for room,info in sub_dict.items():
            dire = ['', '南北', '东西']
            #建立一个列表,第0个元素为空,第1个元素为'南北',第2个元素为'东西'
            print(dire[info[0]])
    

    最后一行:因为info[0]的值不是1就是2,所以dire[info[0]]不是dire[1]就是dire[2]

    如果是dire1,就是取列表dire的第一个元素'南北',dire2则取'东西'。所以代码就是:(直接运行即可)

    image.png-370kB

    unit_rooms = {3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]},
                 4:{401:[1,80],402:[1,80],403:[2,90],404:[2,90]},
                 5:{501:[1,80],502:[1,80],503:[2,90],504:[2,90]}
                 }
    for sub_dict in unit_rooms.values():
        for room,info in sub_dict.items():
            dire = ['', '南北', '东西']
            print('户室号:%d 朝向:%s 面积:%d' % (room,dire[info[0]],info[1]))
    

    那么,截至目前,我们似乎把一切准备工作都做完了,我们来把前面的代码都整合在一起:

    import csv
    #调用csv模块
    with open('assets.csv', 'a', newline='') as csvfile:
    #调用open()函数打开csv文件,传入参数:文件名“assets.csv”、追加模式“a”、newline=''。
        writer = csv.writer(csvfile, dialect='excel')
        # 用csv.writer()函数创建一个writer对象。
        header=['小区名称', '地址', '建筑年份', '楼栋', '单元', '户室', '朝向', '面积']
        writer.writerow(header)
    
    title=input('请输入小区名称:')
    address = input('请输入小区地址:')
    year = input('请输入小区建造年份:')
    block = input('请输入楼栋号:')
    unit=input('请输入单元号:')
    
    start_floor = input('请输入起始楼层:')
    end_floor = input('请输入终止楼层:')
    
    # 开始输入模板数据
    input('接下来请输入起始层每个房间的门牌号、南北朝向及面积,按任意键继续')
    
    start_floor_rooms = {}
    floor_last_number = []
    # 收集起始层的房间信息
    
    # 定义循环控制量
    room_loop = True
    while room_loop:
        last_number = input('请输入起始楼层户室的尾号:(如01,02)')
        floor_last_number.append(last_number)
        #将尾号用append()添加列表里,如floor_last_number = ['01','02']
        room_number = int(start_floor + last_number)
        #户室号为room_number,由楼层start_floor和尾号last_number组成,如301
    
        direction = int(input('请输入 %d 的朝向(南北朝向输入1,东西朝向输入2):' % room_number ))
        area = int(input('请输入 %d 的面积,单位 ㎡ :' % room_number))
        start_floor_rooms[room_number] = [direction,area]
        # 户室号为键,朝向和面积组成的列表为值,添加到字典里,如start_floor_rooms = {301:[1,70]}
    
        continued= input('是否需要输入下一个尾号?按 n 停止输入,按其他任意键继续:')
        #加入打破循环的条件
        if continued == 'n':
            room_loop = False
        else:
            room_loop = True       
    
    unit_rooms = {}
    #新建一个放单元所有户室数据的字典
    unit_rooms[start_floor] = start_floor_rooms
    #unit_rooms={3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]}}
    for floor in range(int(start_floor) + 1, int(end_floor) + 1):
            #遍历除初始楼层外的其他楼层
            floor_rooms = {}
            #每个楼层都建立一个字典
            for i in range(len(start_floor_rooms)):
            #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
                number = str(floor) + floor_last_number[i]
                info = start_floor_rooms[int(start_floor + floor_last_number[i])]
                # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
                floor_rooms[int(number)] = info
                #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
            unit_rooms[floor] = floor_rooms
        
    with open('assets.csv', 'a', newline='')as csvfile:
        writer = csv.writer(csvfile, dialect='excel')
        for sub_dict in unit_rooms.values():
            for room,info in sub_dict.items():
                dire = ['', '南北', '东西']
                writer.writerow([title,address,year,block,unit,room,dire[info[0]],info[1]])
    

    截至目前,我们只是完成了一个单元内所有户室的循环,考虑到一栋楼里可能会有多个单元,所以我们要在一开始再加入一层单元间的循环。我们的最后代码就变成这样:

    import csv
    #调用csv模块
    with open('assets.csv', 'a', newline='') as csvfile:
    #调用open()函数打开csv文件,传入参数:文件名“assets.csv”、追加模式“a”、newline=''。
        writer = csv.writer(csvfile, dialect='excel')
        # 用csv.writer()函数创建一个writer对象。
        header=['小区名称', '地址', '建筑年份', '楼栋', '单元', '户室', '朝向', '面积']
        writer.writerow(header)
    
    title=input('请输入小区名称:')
    address = input('请输入小区地址:')
    year = input('请输入小区建造年份:')
    block = input('请输入楼栋号:')
    
    
    unit_loop = True
    while unit_loop:
        unit=input('请输入单元号:')
        start_floor = input('请输入起始楼层:')
        end_floor = input('请输入终止楼层:')
    
        # 开始输入模板数据
        input('接下来请输入起始层每个房间的门牌号、南北朝向及面积,按任意键继续')
    
        start_floor_rooms = {}
        floor_last_number = []
        # 收集起始层的房间信息
    
        # 定义循环控制量
        room_loop = True
        while room_loop:
            last_number = input('请输入起始楼层户室的尾号:(如01,02)')
            floor_last_number.append(last_number)
            #将尾号用append()添加列表里,如floor_last_number = ['01','02']
            room_number = int(start_floor + last_number)
            #户室号为room_number,由楼层start_floor和尾号last_number组成,如301
    
            direction = int(input('请输入 %d 的朝向(南北朝向输入1,东西朝向输入2):' % room_number ))
            area = int(input('请输入 %d 的面积,单位 ㎡ :' % room_number))
            start_floor_rooms[room_number] = [direction,area]
            # 户室号为键,朝向和面积组成的列表为值,添加到字典里,如start_floor_rooms = {301:[1,70]}
    
            continued= input('是否需要输入下一个尾号?按 n 停止输入,按其他任意键继续:')
            #加入打破循环的条件
            if continued == 'n':
                room_loop = False
            else:
                room_loop = True       
    
        unit_rooms = {}
        #新建一个放单元所有户室数据的字典
        unit_rooms[start_floor] = start_floor_rooms
        #unit_rooms={3:{301:[1,80],302:[1,80],303:[2,90],304:[2,90]}}
        for floor in range(int(start_floor) + 1, int(end_floor) + 1):
        #遍历除初始楼层外的其他楼层
            floor_rooms = {}
            #每个楼层都建立一个字典
            for i in range(len(start_floor_rooms)):
            #遍历每层有多少个房间,这里是3,即执行for i in range 3 的循环
                number = str(floor) + floor_last_number[i]
                info = start_floor_rooms[int(start_floor + floor_last_number[i])]
                # 依次取出字典start_floor_rooms键对应的值,即面积和朝向组成的列表
                floor_rooms[int(number)] = info
                #给字典floor_rooms添加键值对,floor_rooms = {401:[1,80]}
            unit_rooms[floor] = floor_rooms
        
        with open('assets.csv', 'a', newline='')as csvfile:
        #Mac用户要加多一个参数 encoding = 'GBK'
            writer = csv.writer(csvfile, dialect='excel')
            for sub_dict in unit_rooms.values():
                for room,info in sub_dict.items():
                    dire = ['', '南北', '东西']
                    writer.writerow([title,address,year,block,unit,room,dire[info[0]],info[1]])   
    
        unit_continue = input('是否需要输入下一个单元?按 n 停止单元输入,按其他任意键继续:')
        if unit_continue == 'n':
            unit_loop = False
        else:
            unit_loop = True
    
    print('恭喜你,资产录入工作完成!')        
    

    老规矩,又到了检验劳动成果的时候了!不过因为这里涉及到文件读写,所以你可以把csv的文件地址改成绝对路径,或者把代码复制到本地编辑器里,这样在py文件相同的文件夹里就能找到我们所新建的assets.csv文件了。

    另外要注意的是,这个程序没有加上异常错误的处理,所以在运行时该输入数字时要输入数字,否则会报错。

    image.png-544.1kB

  • 相关阅读:
    php 工厂模式实例
    nginx多虚拟主机配置
    PHP提高编程效率的方法
    PHP 多态
    锁机制之PHP文件锁
    深入认识javascript中的eval函数(转载)
    PHP&MYSQL 常用的一些性能检测
    寒假作业1:问答题
    软件测试基础知识总结
    七种测试驱动模式
  • 原文地址:https://www.cnblogs.com/ywb123/p/16390785.html
Copyright © 2020-2023  润新知