• 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
  • 相关阅读:
    写一些,给2013
    C# DateTime变量不能赋null值
    31222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
    王爽《汇编语言》第三版 第十五章 外中断
    王爽《汇编语言》第三版 第十四章 端口
    王爽《汇编语言》第三版 第十二章 内中断
    王爽《汇编语言》第三版 第十一章 标志寄存器
    王爽《汇编语言》第三版 第十章 call和ret指令
    王爽《汇编语言》第三版 第九章 转移指令的原理
    王爽《汇编语言》第三版 第八章 数据处理的两个基本问题
  • 原文地址:https://www.cnblogs.com/lisa-blog/p/10194300.html
Copyright © 2020-2023  润新知