day21:包和异常处理

1,复习

# 序列化模块
# json
    # dumps
    # loads
    # dump 和文件有关
    # load load不能load多次
# pickle
    # 方法和json的一样
    # dump和load的时候 文件是rb或者wb打开的
    # 支持Python所有的数据类型
    # 序列化和反序列化需要相同的环境
# shelve
    # 操作方法和字典类似
    # open方法
    # open方法获取了一个文件句柄
View Code

2,json的格式化输出,这个感兴趣的话了解一下就好,直接copy老师的博客

Serialize obj to a JSON formatted str.(字符串表示的json对象) 
Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key 
ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。) 
If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). 
If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). 
indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json 
separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。 
default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. 
sort_keys:将数据根据keys的值进行排序。 
To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.
import json
data = {'username':['李华','二愣子'],'sex':'male','age':16}
json_dic2 = json.dumps(data,sort_keys=True,indent=2,separators=(',',':'),ensure_ascii=False)
print(json_dic2)
# 平时查看可以这样看,会显得很清晰,但是写到文件里面是,最好还是紧凑着写,节省空间
输出结果:
{
  "age":16,
  "sex":"male",
  "username":[
    "李华",
    "二愣子"
  ]
}

3,包,把解决一类问题的模块放在同一个文件夹里就是包,我们之前接触的那些模块re,sys,其实都是包,只不过我们是直接import进来,没有关注过内部的结构。

4,如何创建一个包?pycharm里面project--》new--》Python package,上面还有一个是directory,创建的时候二者的图标稍有不同,两个的区别是包里面每个文件夹都有一个__init__双下init方法。

5,Python2里面只有带上__init__.py这个文件才叫做包,但是Python3里面没有也可以,

# 代码创建包
import os
os.makedirs('glance/api')
os.makedirs('glance/cmd')
os.makedirs('glance/db')
l = [] # 这个列表是为了后面批量关闭
# 两个包下有同名模块也不会冲突,因为来自两个不同的命名空间
l.append(open('glance/__init__.py','w'))
l.append(open('glance/api/__init__.py','w'))
l.append(open('glance/api/policy.py','w'))
l.append(open('glance/api/versions.py','w'))
l.append(open('glance/cmd/__init__.py','w'))
l.append(open('glance/cmd/manage.py','w'))
l.append(open('glance/db/__init__.py','w'))
l.append(open('glance/db/models.py','w'))
map(lambda f:f.close(),l)

6,关于包的导入分为import和from...import...但是二者无论何时何位置,都必须遵循一个原则就是:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,但是必须遵循这个原则。

7,模块名区分大小写,foo.py和FOO.py是两个模块

8,可以用点来调用的有包,模块,函数和类

# 可以有很多的点,但是点的左边必须是一个包
# as 另外一个用起来很方便的地方
import glance.api.policy as policy
policy.get()

9,包也可以用from...import...来进行导入,这样import的话,import后面是不允许有点的

from glance.api import policy
policy.get()
from glance import api.policy  # 这是错误的,pycharm也会给报错的,后面不允许出现点

10,

# 直接这样写,是找不到的
# import glance # 如果要这样写,还需要一些操作,除了找不到的问题,还需要解决一些其他问题,下文会细讲
from part.glance.api import policy   # 这就可以了或者把glance文件夹的路径添加到path里面也可以的
from glance.api import policy  把glance路径加到path里面就可以这样写了

import sys
policy.get()

# ["/Users/guolixiao/PycharmProjects/lisa's_practise/boys/part", "/Users/guolixiao/PycharmProjects/lisa's_practise/boys",
sys.path.append("/Users/guolixiao/PycharmProjects/lisa's_practise/boys/part/glance")
# 这样添加完成之后,虽然上面还是飘红,但是其实已经生效了
print(sys.path)

11,python2里面如果没有双下__init__方法,那么根本没有办法来做这些导入操作的,Python3没有限制

import glance
# 这样写只有glance 大文件下的__init__会执行,子文件夹下的不会执行
# 模块和包还是有一点不一样的,模块一导入相当于执行了这个py文件
# 那问题来了,你这样导入包得话,他会去执行啥呢?啥也没执行,只有空的__init__函数
# 导入包的话,默认会执行包里面的__init__文件,这个是一定的,所以我们可以在__init__文件里面加代码
# glance.api.policy.get()  # AttributeError: module 'glance' has no attribute 'api'

12,其实也不是所有的内置模块,都可以直接用import 包名 这样的方式来导入,当然大部分是可以的,有一个例外就是urllib

import urllib
urllib.urlopen()  # 这样是找不到的

# 这可以用from的方式来导入,这其实也就是说,他其实也是一个包,但是他没有对这个包进行任何的处理
# 只有进行过特殊处理的,来可以像导入一个模块那样直接import 包名
from urllib import urlopen

13,照搬老师的博客

 什么是模块?
# 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
# 但其实import加载的模块分为四个通用类别: 
# 
#   1 使用python编写的代码(.py文件)
# 
#   2 已被编译为共享库或DLL的C或C++扩展
# 
#   3 包好一组模块的包
# 
#   4 使用C编写并链接到python解释器的内置模块
# 
 为何要使用模块?
#    如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。
# 
#     随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,

14,绝对路径情况,从外到内,这些都是操作怎么直接import 包名的,我们也希望直接导入包名会把里面所有的变量和函数加载到内存里,这样我调用的时候就能调用到了,相当于是一个连续出发的动作。

import glance  调用的文件
# 绝对路径的时候,要给全路径,不然找不到,外面执行就能找到
print(sys.path) # 写内层和外层都要以这里面有的路径为基准,他有的路径就是glance的上层和上上层,才可以找到
print("glance***************")
from part.glance import api  
from part.glance import cmd
from part.glance import db
print("glance-api******")
# import policy  # 这个只可以在当前文件执行的时候会找到,到外面就找不到了,其实是没有什么意义的,因为我们不会再包的内部做什么操作,都是在外面操作
# import versions

from part.glance.api import policy  # 我们需要import然后把变量和函数加载到内存,然后才可以使用
from part.glance.api import versions

15包的进阶,绝对路径有个问题,就是我的包一旦移动了路径,前面写的就都得修改,这不是我们想要的,所以我们引入了相对路径,绝对路径修改后的绝对路径

# 我在part目录下新建一个dir文件夹,然后把整个glance文件,拖进去,当然pycharm会自动给我们修改绝对路径
# 但是我们不想用绝对路径了,相对路径怎么解决呢
# import glance # 因为glance变成了当前执行文件的下一层,所以这样肯定是找不到了
from dir import glance
# 绝对路径的时候,要给全路径,不然找不到,外面执行就能找到
glance.db.models.register_models('sql')
glance.api.policy.get()
from dir.glance import db  # glance 目录的init文件
from dir.glance import api
from part.dir.glance import cmd
from dir.glance.api import versions
from dir.glance.api import policy

16,相对路径写法,这种情况下改变包的路径也不用去管,这是相对路径的优点,只要相对位置不变就可以,可以随意移动包,只要能找到包的位置,就能找到包里面的模块,缺点是不能再包里面使用,但是绝对路径里面外面都可以使用的,绝对路径只要写全,path里面能找到的就可以内部外部都执行

import glance

glance.db.models.register_models('sql')
glance.api.policy.get()
from . import db
from . import api
from . import cmd
from . import versions
from . import policy

17,相对路径得话,外面调用不会报错,里面调用就会报错,因为你用点的方式去找的话,只有在外面的角度才能找到的,这是机制决定的,点和点点都不行,只要有相对路径,内部就不可以

# 总结
# 使用绝对路径,
# 不管在包内还是外部,导入了就能用
# 不能挪动,但是直观

# 使用相对路径
# 可以随意移动包,只要能找到包的位置,就可以使用包里面的模块
# 不能在包里直接使用模块了,包里的模块如果想使用其他模块的内容只能使用相对路径,使用了相对路径就不能再包内直接执行了

18,一般我们也不需要修改包内部的内容,包都是直接拿来用就行。一般你能做一个很厉害的包的时候,就用相对路径,其他时候,就用绝对路径就可以了

目前大部分还没有达到能制作包的程度,另外包和包之间不可以相互依赖,极少的情况下可以,这种情况下,两个包需要一起安装的。最好是独立包,自己做的包,可以引用Python本身的内置模块,一般不需要引用扩展模块或者自己写的其他模块

19,包里面的__all__,all方法是和星号来配合使用的,第三种可以直接调用包的方法,这个不用glance来调用的话,目前我没有尝试成功, 从glance开始调用是成功的。先记住相对和绝对路径的吧

import glance

glance.db.models.register_models('sql')
glance.api.policy.get()

# policy.get() 这样一直不成功
from .api import *
from .cmd import *
from .db import *
__all__ = ['policy','versions']

20,软件开发代码规范,以后所有的非web项目作业,都要用下面的格式来写,六个目录,bin,conf,core,db,lib,log,web项目他还有一个其他的规范

 21,bin 目录下就写一个开始文件start.py,程序入口,你写的程序,其实99.9%不是你维护的,这个程序可能就交给运维,如果做运维的话,接触的就不止是Python代码,还有可以有Java,PHP,C++,C语言,go语言,PHP,都需要接触,可能都不精,那我就我规定好,所有的语言写的,我都有一个叫bin的目录,这里面存的都是我的程序入口,这里面就一个文件,Python里面叫start.py,PHP里面叫做start.php,只要执行start.py整个程序就执行起来了,我也不知道中间是怎么走的,这就是我们需要要的效果,只要执行他,整个程序就跑起来。所以这个文件里面的逻辑,不宜复杂,应该是非常简短的。有可能只有一句if __name__ =='__main__': core.main,当然不包括import啥的。假如你写了20几个py文件,不指定入口文件的话,别人看起来是非常痛苦的。

import sys
import os
sys.path.append(os.path.dirname(os.getcwd()))
# 拿到当前路径的上一层目录,并把它放入到path里面,这是一个定式,只要每次执行前都把它这句话拿过来执行一下就好
from core  import core  # 这句话只有在pycharm里面执行没有问题,因为他会自动把路径加入到sys.path
# print(sys.path)  会自动添加当前路径和pycharm的项目路径,这个项目路径是只有在pycharm里面才会添加的


if __name__ =='__main__':
    core.main()

22,core目录下的core.py,这个文件里面存的是你写的代码,整个目录结构中,只有这一个是和代码相关的文件,假如我在这个文件写一个main方法,这个方法才是我们程序真正的入口,这里面可能有调用了其他的方法,

from core import login
# 由于项目路径直接加到了path里面,所以直接从core文件夹来导入就可以了,login还是在和core同级的文件login.py里面

def main():
    print('main')
    login.login()

23,conf文件夹,配置文件文件夹,配置文件是给运维人员看的,运维人员虽然不懂代码,但是他却可以给你去调一些参数,比方说,IP地址,端口号,用户名,密码,文件路径,等等,后期可能会有数据库的名称,mysql还是Oracle呢等等。还能去配置一些程序的功能,但是我可以通过去修改配置项去增加或者修改一个功能。

24,db文件夹,主要放一些数据;lib里面主要放一些自己写的模块和包,通用的一些模块,每次写都可以用的,单是没有自动安装在Python解释器里面,他是你自己写的一些通用模块。比方说,你把你的计算器写成一个通用模块;log文件夹是你执行程序的过程中,你希望记录的一些过程。把中间的一些结果记录下来,后面我们还会去学习一个专门记录LOG文件的一个模块,现在先了解就好。

25, 异常处理,重要,但是不难,异常主要有两大类,程序的逻辑错误,语法错误,我们在程序中就要尽量去规避掉,程序中的语法错误,逻辑错误很多,也是我们真正要处理的一部分,如下

# 1/0   # ZeroDivisionError: division by zero
# name  # NameError: name 'name' is not defined
# 2+'3' # TypeError: unsupported operand type(s) for +: 'int' and 'str'
# [][3]  # IndexError: list index out of range
# {}['k'] # KeyError: 'k'

ret = int(input('number >>>'))  # 加入输入'a'
print(ret * '*')
# ValueError: invalid literal for int() with base 10: 'a'

26,遇到错误,程序就停下来不执行了,这不是我们我需要的,我们希望程序可以忽略掉错误,继续往下执行,或者是说,发生错误后,我们可以针对错误去做一些处理,能不是直接抛出错误,结束运行。那么久可以用try...catch...来处理。把你想要处理的,捕捉错误的代码放入到try里面,如果有错误就会被except捕捉到。try里面的代码是一定会执行的,除非遇到错误,except里面的代码,没有错误不会去执行。捕捉except后面指定的错误类型。一般情况下我们会把你认为可能会有问题的,或者你预估到客户可能会输入错误的的,但是你却没有办法处理的,放入到try...catch...里面。

try:
    ret = int(input('number >>>'))  # 加入输入'a'
    print(ret * '*')
except ValueError:
    print("您输入的内容有误,请输入一个数字")

运行结果:
number >>>aaa
您输入的内容有误,请输入一个数字

27,except 支持多分支

try:
    [][3]
    ret = int(input('number >>>'))  # 加入输入'a'
    print(ret * '*')
except ValueError:
    print("您输入的内容有误,请输入一个数字")
except IndexError:
    print("index error,list index out of range")

28,有没有一个万能的可以捕获所有错误的类型呢?有,就是exception

try:
    [][3]
    ret = int(input('number >>>'))  # 加入输入'a'
    print(ret * '*')
except ValueError:
    print("您输入的内容有误,请输入一个数字")
except IndexError:
    print("index error,list index out of range")
except Exception:
    print("你错了,老铁")

29,总结

# 总结:
# 程序一旦发生错误,就从错误大的位置停下来了,不再继续执行后面的内容
# 使用try和except就能处理异常
    # try使我们需要处理的代码
    # except后面跟一个错误类型,当代码发生错误且错误类型符合的时候,就会执行except中的代码
    # except支持多分支
    #有没有一个能处理所有错误的类型:exception
        # 有了万能的处理机制仍然需要把能预测到的问题单独处理
        # 单独处理的所有内容都应该卸载万能异常之前
   # else:没有异常的时候执行else中的代码
   finally:不管代码是否异常,都会执行

30,try...except...else...

try:
    ret = int(input('number >>>'))  # 加入输入'a'
    print(ret * '*')
    print("没有被错误中断得话,这里面的代码就会全部执行")
except ValueError:
    print("您输入的内容有误,请输入一个数字")except Exception:
    print("except里面,捕捉到指定错误是会执行")
else:
    print("没有捕捉到错误的时候,执行这一步")  # 类似循环的else分支,没有被break打断就会去执行
    

31,except后面直接加冒号,指的是捕捉所有错误类型

32,finally分支,因为我们希望在最后有一段代码,不管是否有异常都希望去执行,比如下面的例子

def func():
    try:
        f = open('file','w')  # 这儿只是举个例子是操作文件,也有可能是操作数据库,和网络,而且并不是所有都有with语法
        '''
        中间自己写的一些代码,可能会有错,也可能没错,但是不管有错没错,我打开的文件,都需要关闭的
        '''
        # f.close() 加在这儿的话,程序遇到错误,就没有办法关闭了,所以不可以
        print("try")
        return # 加上这句即使return,finnally也会执行

    except:
        # f.close() # 这儿也不合适,只有发生错误才会关,没错呢?
        print("except")
    # else:
    #     f.close() # 也不合适,发生错误关不了
    finally:
        f.close() # 只有加在这儿是可以的

    f.close() # 加在外面为什么不行呢?如果前面有return得话,这句话就不执行了,但是finally里面即使前面return了,还是会执行。
print(func())

33,finally和return相遇的时候还是会执行,一般用作函数里做异常处理时,不管是否异常,去做一些收尾工作。一般else里面都是结论,就是没有错误的话我就是做什么,或者去触发一个什么任务。

34,什么时候用异常处理?try...except...应该尽量少用,因为他本身就是附加给程序的一种异常处理的逻辑,与你的主要工作是没有关系的,加多了,会导致代码可读性变差,只有在有些程序无法预知时,才应该加上try...except...,其他的逻辑错误,应该尽量修正。在代码没有成型之前,不要加这些,尽量先修正自己能够杜绝的,无法杜绝的再用try...except...去处理。

35,except打印具体错误,

try:
    '''
    你的代码
    '''
    1/0
except Exception as e:  # 这个名字随便起,要有意义
    print('你错了',e)  # 你错了 division by zero

36,三级菜单

 

menu = {
    '北京':{
        '海淀':{
            '五道口':{
                'soho':{},
                '网易':{},
                'google':{}

            },
            '中关村':{
                '爱奇艺':{},
                '汽车之家':{},
                'youku':{},
            },
            '上地':{
                '百度':{},
            }
        },
        '昌平':{
            '沙河':{
                '老男孩':{},
                '北航':{}
            },
            '天通源':{},
            '回龙观':{}
        },
        '朝阳':{},
        '东城':{}
    },
    '上海':{
        '闵行':{},
        '闸北':{},
        '浦东':{}
    },
    '山东':{},
}

# 此处的b 是比较难理解的地方,利用循环,实现返回上一层
# 此处的q 需要给每一层都要返回一个q 知道最上一层
# 最后层为空是,继续打印这一层的key,除非输入q或者是b
# 递归实现
def threeLM(dic):
    while True:
        for k in dic:print(k)
        key = input('input>>').strip()   # 北京
        if key == 'b' or key == 'q' :return key
        elif key in dic.keys() and dic[key]:
            ret = threeLM(dic[key])
            if ret == 'q':return 'q'  # 加上这就会就会一直return到最后,不加这句话其实只是return了一层而已
            print(ret)
        # elif (not dic.get(key)) or (not dic[key]):
        #     continue  
# 最后两行不写也是continue的效果

# 列表实现,我觉得列表更好理解,堆栈的
l =[menu]
while l:
    for key in l[-1]:print(key)
    k = input('input>>').strip()
    if k in l[-1].keys() and l[-1][k]:
        l.append(l[-1][k])   # 每次把用户输入key对应的小字典,放入列表的最后一个
    if k == 'b':
        l.pop()
    if k == 'q':
        break
    else:continue

threeLM(menu)

37,大作业 select name age where age > 12

column_dic = {'id':0,'name':1,'age':2,'phone':3,'job':4}


# 去文件里面拿符合age > 22这个条件的行
def filter_hander(operate,con):
    selected_lst = []
    col,val = con.split(operate)
    col = col.strip()
    val = val.strip()
    # 文件中取到的值,和22来比较,所以要用整形
    # 如果是like的话 ==,这个比较字符串就可以了,不用强转,我不在意你是否是int
    judge = 'int(line_lst[column_dic[col]]) %s int(val)' %operate if operate=='<' or operate=='>' else \
        'line_lst[column_dic[col]] %s val'%operate
    f = open('users',encoding='utf-8')
    for line in f:
        line_lst = line.strip().split(',')
        if eval(judge):
            selected_lst.append(line_lst)
    f.close()
    return selected_lst


# 去文件里面拿符合age > 22这个条件的行 
def get_selected_line(con):
    if '>' in con:
        selected_lst = filter_hander('>',con)
    elif '<' in con:
        selected_lst = filter_hander('<', con)
    elif '=' in con:
        selected_lst = filter_hander('==',con.replace('=','=='))  # =换成==
    elif 'like' in con:
        selected_lst = filter_hander('in',con)  # like转换成in
    return selected_lst

# 这个函数的提高再用应用了列表生成时
# 这个函数拿到了你想显示的参数,name 和 age 返回值是一个列表
# 这个处理的是你像要哪些参数
def get_show_list(col_condition):
    col_info_lst = col_condition.strip().split('select')
    col_info_lst = [col_info_item for col_info_item in col_info_lst if col_info_lst.strip()]
    if col_info_lst:
        col_info = col_info_lst[0].strip()
        if '*' == col_info:
            return column_dic.keys()
        elif col_info:
            ret = col_info.strip(',')
            return [item.strip() for item in ret]
        else:print(col_info)  # 空的时候


# 返回符合条件行的指定参数
def show(selected_lst,show_lst):
    for selected_item in selected_lst:
        for col in show_lst:
            print(selected_item[column_dic[col]],end = '')
        print('')  # 打印一个空

# condition = input('>>>')
condition = 'select name age where age > 22'
ret = condition.split('where')
con = ret[1].strip()
print(con)  # age > 22

show_lst = get_show_list(ret[0])

selected_lst = get_selected_line(con)

show(selected_lst,show_lst)
View Code

 

posted on 2018-12-29 10:26  Lisa_Guo  阅读(290)  评论(0编辑  收藏  举报