zoukankan      html  css  js  c++  java
  • Python学习笔记第四周

    目录

      一、基础概念

        1、装饰器

          1、装饰器本质就是函数

          2、实现装饰器知识储备

            1、函数即变量

            2、高阶函数

            3、嵌套函数

          例子

            1、将一个函数名作为实参传递给另外一个函数

            2、返回值为函数名

            3、函数嵌套函数

            4、完整装饰器例子

            5、装饰器高级版本

        2、列表生成器

        3、生成器

        4、斐波那契数列

        5、迭代器

        6、内置函数

        7、json、pickle序列化

        8、软件目录结构规范

    一、基础概念

    1、装饰器:

      1、装饰器本质上就是函数,用来装饰其他函数

      原则:装饰器写好后,原则上不能修改其他函数源代码

        1、不能修改被装饰函数源代码

        2、不能修改被装饰函数调用方式

        总结成一点就是装饰器对被装饰函数完全透明,用这个函数的人完全不知道装饰器的存在

      2、实现装饰器的知识储备

        1、函数即变量

         在python中,变量定义值,在内存中开辟一块空间存放该变量值,当变量名不再引用该变量值后,python解释器会自动回收该值所在内存,函数也是如此,通过函数名调用函数体,当函数名不再引用该函数体,函数体从内存中被解释器回收。

              2、高阶函数

             a)把一个函数名作为实参传递给另外一个函数,在不修改被装饰函数源代码情况下为其添加功能

             b)返回值为该函数名,不修改函数的调用方式

        3、嵌套函数

          在一个函数内通过def声明一个函数

      装饰器=高阶函数+嵌套函数

     例子

      1、将一个函数名作为实参传递给另外一个函数

    def test1(func):  #传入函数名作为实参
        func()
    
    def bar():
        print('in the bar!')
        
    test1(bar)
    #输出:
    in the bar!
    import time
    
    def bar():
        print('in the bar!')
    
    def test1(func):
        start_time = time.time()
        func()# 运行bar函数
        stop_time = time.time()
        print('the func running time is %s'  %(stop_time-start_time))
    
    
    test1(bar)
    #输出:
    in the bar!
    the func running time is 8.58306884765625e-05

      2、返回值为函数名

    import time
    
    def bar():
        print('in the bar!')
    
    def test1(func):
        print(func)
        return func
    
    
    bar = test1(bar)   #将bar函数名作为参数传递给函数test1内,同时返回值为bar函数名而不是bar函数执行结果,并将其重新赋值给bar
    bar() #执行bar()会先执行test1,打印bar对应的内存地址,然后执行bar函数对应的函数体内容
    #输出:
    <function bar at 0x289a464>
    in the bar!

      3、函数嵌套函数

    def foo():
        print('in the  foo')
        def bar():
            print('in the bar')
        return bar() #执行foo时会返回bar函数执行结果
    
    foo()
    #输出:
    in the  foo
    in the bar

      4、完整装饰器例子

    import time
    
    def deco(func):
        def wrapper(*args,**kwargs):  #无论原始函数自身带任何参数均可以在这包含
            start_time = time.time()
            func(*args,**kwargs)   #当test1传入时,执行test1的返回结果,如果源函数携带参数,这里可以在执行原函数时带源函数所带参数
            stop_time = time.time()
            print('the func time is %s'  %(stop_time-start_time))
        return wrapper  #直接返回函数名
    
    @deco   #@deco 等价于       test1 = deco(test1)
    def test1(name):
      time.sleep(3)
      print('in the test1')
      print('the name is %s' %name)
    
    
    test1('gavin')
    #输出:
    in the test1
    the name is gavin
    the func time is 3.0022261142730713
    import time
    
    def deco(func):
        def wrapper(*args,**kwargs):  #无论原始函数自身带任何参数均可以在这包含
            start_time = time.time()
            func(*args,**kwargs)   #当test1传入时,执行test1的返回结果,如果源函数携带参数,这里可以在执行原函数时带源函数所带参数
            stop_time = time.time()
            print('the func time is %s'  %(stop_time-start_time))
        return wrapper  #直接返回函数名
    
    @deco   #@deco 等价于       test1 = deco(test1)
    def test1(name):
      time.sleep(3)
      #print('in the test1')
      #print('the name is %s' %name)
      return name  #返回name值
    
    
    print(test1('gavin'))
    #输出:
    the func time is 3.0015320777893066
    None   #用该方法没法返回源函数需要返回的参数
    import time
    
    def deco(func):
        def wrapper(*args,**kwargs):  #无论原始函数自身带任何参数均可以在这包含
            start_time = time.time()
            res = func(*args,**kwargs)   #当test1传入时,执行test1的返回结果,如果源函数携带参数,这里可以在执行原函数时带源函数所带参数 
            stop_time = time.time()
            print('the func time is %s'  %(stop_time-start_time))
            return res   #当需要被修饰函数有返回值时,可以在装饰器中将其返回
        return wrapper  #直接返回函数名
    
    @deco   #@deco 等价于       test1 = deco(test1)
    def test1(name):
      time.sleep(3)
      #print('in the test1')
      #print('the name is %s' %name)
      return name
    
    
    print(test1('gavin'))
    #输出
    the func time is 3.00175404548645
    gavin

       5、装饰器高级版本:通过装饰器来划分不同的登录认证界面

    #版本一,通过不带参数的auth装饰器来完成home与bbs认证
    user,passwd = 'gavin','123'
    def auth(func):
        def wrapper(*args,**kwargs):
            username = input('usernmae: ').strip()
            password = input('password: ').strip()
            if user == username and passwd == password:
                print('33[32;1mauthticatin passed33[32;0m'.center(50,'@'))
                func(*args,**kwargs)
            else:
                exit('wrong input!')
        return wrapper
    
    
    
    
    
    @auth
    def home():
        print('in the home page!')
    
    @auth
    def bbs():
        print('in the bbs page!')
    
    home()
    bbs()
    #输出:
    usernmae: gavin
    password: 123
    @@@@@@@@@authticatin passed@@@@@@@@@
    in the home page!
    usernmae: gavin
    password: a
    wrong input!
    user,passwd = 'gavin','123'
    def auth(func):
        def wrapper(*args,**kwargs):
            username = input('usernmae: ').strip()
            password = input('password: ').strip()
            if user == username and passwd == password:
                print('33[32;1mauthticatin passed33[32;0m'.center(50,'@'))
                res = func(*args,**kwargs)  #将home函数对应的运行结果返回
                return res
            else:
                exit('33[31;1mwrong input!33[32;0m')
        return wrapper
    
    
    
    
    
    @auth
    def home():
        return 'home page'  #需要装饰器可以返回该返回值
    
    @auth
    def bbs():
        print('in the bbs page!')
    
    print(home())
    bbs()
    #输出:
    usernmae: gavin
    password: 123
    @@@@@@@@@authticatin passed@@@@@@@@@
    home page
    usernmae: gavin
    password: 123
    @@@@@@@@@authticatin passed@@@@@@@@@
    in the bbs page!
    user,passwd = 'gavin','123'
    def auth(auth_type):  #装饰器携带的参数会在第一层传入装饰器
        def outer(func): #装饰器要装饰的源函数会在第二层传入到装饰器
            def wrapper(*args,**kwargs):
                if auth_type == 'local':
                    username = input('usernmae: ').strip()
                    password = input('password: ').strip()
                    if user == username and passwd == password:
                        print('33[32;1mauthticatin passed33[32;0m'.center(50,'@'))
                        res = func(*args,**kwargs)  #将home函数对应的运行结果返回
                        return res
                    else:
                        exit('33[31;1mwrong input!33[32;0m')
                elif auth_type == 'ldap':
                    print('暂时不支持')
                    func(*args,**kwargs)
            return wrapper
        return outer
    
    
    
    
    
    @auth(auth_type = 'local')
    def home():
        return 'home page'  #需要装饰器可以返回该返回值
    
    @auth(auth_type = 'ldap')
    def bbs():
        print('in the bbs page!')
    
    print(home())
    bbs()
    #输出
    usernmae: gavin
    password: 123
    @@@@@@@@@authticatin passed@@@@@@@@@
    home page
    暂时不支持
    in the bbs page!

    2、列表生成器

    >>> a = [ i * 2 for i in range(10)]
    >>> a
    [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

    3、生成器:generator

    为了避免列表中数据过多占用太多内存空间,导致系统不可用,使用生成器来替代列表产生数据序列

    >>> b = (i * 2 for i in range(10))
    >>> b
    <generator object <genexpr> at 0x10223d7d8> 

    此时b为生成器,只有在调用的时候才会产生数据,所以使用通常的b[5]调用列表的方法是没法得到数据的

    >>> b[2]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'generator' object is not subscriptable

    生成器只有在调用时才会产生相应的数据,同时只记录当前的位置,只有通过__next__()方式或者next()内置函数才能调用

    >>> b.__next__()
    0
    >>> b.__next__()
    2
    >>> b.__next__()
    4
    >>> c = next(b)
    >>> print(c)
    6

    >>> b = (i * 2 for i in range(10)) 

    >>> for n in b:print(n) #也可以使用for循环一次性全部取出,这样可以不用使用next方法同时避免最后遇到StopIteration错误
    ...
    0
    2
    4
    6
    8
    10
    12
    14
    16
    18

    4、斐波那契数列

    fibonacci除了第一个和第二个数外,其他任意数都是前面两个数相加得到的

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b  #yield类似断点,执行到这里会跳出生成器,然后下一次进入生成器会从这个位置进入继续执行
            a, b = b, a + b  #yield会保存函数的中断状态
            n = n + 1
        return 'Done'
    
    res = fib(6)
    for n in res:   #同样斐波那契函数也可以使用for循环方式取到所有想要的数值,同时也避免使用next方法,但是有一点for循环没法做到,就是返回return的值
        print(n)
    #输出
    1
    1
    2
    3
    5
    8

    如果想要取到return返回的值,需要使用下面的方法

    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b  #yield类似断点,执行到这里会跳出生成器,然后下一次进入生成器会从这个位置进入继续执行
            a, b = b, a + b  #yield会保存函数的中断状态
            n = n + 1
        return 'Done'
    
    res = fib(6)
    
    while True:
        try:
            x = next(res)  #next()为内置函数,类似于__next__()
            print('res:', x)
        except StopIteration as e:  #如果想要获得return返回的值,必须抓到StopIteration错误
            print('Generator return valuel:', e.value)
            break #当结束后会进入exception,同时需要跳出该循环
    #输出
    res: 1
    res: 1
    res: 2
    res: 3
    res: 5
    res: 8
    Generator return valuel: Done

    通过协程方法达到多线程效果:

    #版本一:单独传入next与send,查看yield与send方法使用
    import time
    
    def consumer(name):
        print('%s准备吃包子啦' %name)
        while True:
            baozi = yield #yield保存当前状态,返回时直接返回到这个状态,但是单纯调用next不会给yield传值
            print('%s包子来啦,被%s吃了!' %(baozi,name))
    
    
    eat = consumer('gavin')
    eater = next(eat)  #只唤醒yield,不会给它传值
    baozi1 = '韭菜馅'
    eat.send(baozi1) #send可以调用yield,同时给yield传值,也就是唤醒yield同时给它传值
    #输出
    gavin准备吃包子啦
    韭菜馅包子来啦,被gavin吃了!
    #版本二:通过协程方式达到并行效果
    import time
    
    def consumer(name):
        print('%s准备吃包子啦' %name)
        while True:
            baozi = yield #yield保存当前状态,返回时直接返回到这个状态,但是单纯调用next不会给yield传值
            print('%s包子来啦,被%s吃了!' %(baozi,name))
    
    
    def producter():
        c1 = consumer('gavin')#这个动作只是把它变成生成器
        c2 = consumer('alex')
        c1.__next__()#需要执行next才会执行生成器
        c2.__next__()
        print('老子开始做包子啦!')
        for i in range(1,5):
            time.sleep(1)
            print('做了一个包子,分两半,一个白菜馅,一个韭菜馅')
            c1.send(i)
            c2.send(i)
    
    producter()
    #输出
    gavin准备吃包子啦
    alex准备吃包子啦
    老子开始做包子啦!
    做了一个包子,分两半,一个白菜馅,一个韭菜馅
    1包子来啦,被gavin吃了!
    1包子来啦,被alex吃了!
    做了一个包子,分两半,一个白菜馅,一个韭菜馅
    2包子来啦,被gavin吃了!
    2包子来啦,被alex吃了!
    做了一个包子,分两半,一个白菜馅,一个韭菜馅
    3包子来啦,被gavin吃了!
    3包子来啦,被alex吃了!
    做了一个包子,分两半,一个白菜馅,一个韭菜馅
    4包子来啦,被gavin吃了!
    4包子来啦,被alex吃了!

    5、迭代器

    可直接作用于for循环的数据结构包括:

      1:集合类型数据:list、tuple、dict、set、str

      2、generator,包括生成器和带yield的generator function函数

    这些可以直接作用于for循环对象统称为可迭代对象Iterable

    可以使用isinstance()判断一个对象是否是Iterable

    >>> from collections import Iterable
    
    >>> isinstance([], Iterable)
    True
    >>> isinstance({}, Iterable)  
    True
    >>> isinstance((), Iterable)   
    True
    >>> isinstance((x for x in range(20)), Iterable) 
    True

    生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopItrable错误表示没法继续返回下一个值

    可以被next()函数调用并不断返回下一个值的对象称为迭代器Iterator

    >>> isinstance((x for x in range(20)), Iterator)
    True
    >>> isinstance({}, Iterator)                      
    False
    >>> isinstance([], Iterator)  
    False
    >>> isinstance((), Iterator)  
    False

    生成器都是Iterator对象,但是list dict set虽然是Iterable但是不是Iterator,如果想把它们变为Iterator,可以使用iter()函数

    >>> isinstance(iter(()), Iterator)
    True
    >>> isinstance(iter([]), Iterator)    
    True
    >>> isinstance(iter({}), Iterator)  
    True

    Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

    Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

    6、内置函数

    >>> abs(-1)  #取绝对值
    1
    >>> print(all([-1])) #如果里面包括0为false其余都为true,这个相当于and,只要有false就为false
    True
    >>> print(all([0,1]))
    False
    >>> print(any([0,1]))   #只要有真就为true,不管有没有false
    True
    >>> print(any([0,-1]))
    True
    >>> print(ascii('ä¸中å午'))  #将值转换为asii码
    'xe4xb8u4e2dxe5u5348'
    >>> print(bin(1))  #将十进制转为二进制
    0b1
    >>> bool([])
    False
    >>> bool([1])  #布尔函数,判断真假
    True
    >>> bool([-1])
    True
    >>> a = bytearray('abcde', encoding='utf-8')   #可以通过asii码的形式修改字符串
    >>> print(a[1])
    98
    >>> a[1] = 50  #将b替换为2
    >>> print(a)
    bytearray(b'a2cde')
    >>> print(callable([]))  #是否可以包含括号,列表不能包含括号
    False
    >>> def func():print('1')
    ... 
    >>> print(callable(func)) #函数可以包含括号
    True
    >>> print(chr(98)) #通过数字得到对应的asii码
    b
    >>> print(ord('b'))#通过asii码得到对应的数字
    98
    >>> code = "for i in range(5):print(i)"
    >>> exec(code)  #可以将字符串对应的函数执行
    0
    1
    2
    3
    4
    >>> 
    >>> 
    >>> a = dict()  #定义字典
    >>> a
    {}
    >>> divmod(5,3)  #取两个数字的商和余数
    (1, 2)
    >>> a = '''{'a':1,'b':'aaaaa'}'''
    >>> c = eval(a)  #取引号
    >>> c
    {'a': 1, 'b': 'aaaaa'}
    >>> calc = lambda n:print(n)  #匿名函数,如果不反复调用执行一次就结束可以使用匿名函数,执行完毕后立即回收内存
    >>> 
    >>> calc(5)
    5
    >>> calc = lambda n:print(n+1)
    >>> calc(5)
    6
    >>> res = filter(lambda n:n>5,range(10))  #过滤器:只取大于5的数值
    >>> for i in res:print(i)
    ... 
    6
    7
    8
    9
    >>> res1 = map(lambda n:n*n,range(5))  #和匿名函数配合
    >>> for i in res:print(i)
    >>> for i in res1:print(i)
    ... 
    0
    1
    4
    9
    16
    >>> import functools  #reduce函数从内置函数中去除
    >>> res2 = functools.reduce(lambda x,y:x+y,range(10)) #操作x+赋值给x
    >>> print(res2)
    45
    >>> float(10)  #将整数变为浮点数
    10.0
    >>> madlib = " I {verb} the {object} off the {place} ".format(verb="took", object="cheese", place="table")  #format是准备替换%s的内置函数,匹配更加精确,通过{}与format方法进行引用,此例format通过变量名进行引用
    >>> madlib
    ' I took the cheese off the table '
    >>> '{},{}'.format('a','b')  #通过顺序方式依次引用a  b
    'a,b'
    >>> a = set([1,1,1,1,33,4,1,45])  #将列表变为集合
    >>> a
    {1, 4, 45, 33}
    >>> b = frozenset([1,1,1,1,33,4,1,45])  #被冻结的集合,没法添加
    >>> b
    frozenset({1, 4, 45, 33})
    >>> print(hash('I have a apple')) #做hash操作
    7983704463637394503
    >>> len('I have a apple')
    14
    >>> print(hex(255)) #将十进制转换为16进制
    0xff
    >>> def test():local_var = 333,print(locals()) 
    ... 
    >>> test()
    {}
    >>> print(globals())
    {'test': <function test at 0x101a479d8>, 'res': <filter object at 0x101945b38>, 'functools': <module 'functools' from '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/functools.py'>, '__name__': '__main__', 'a': {1, 4, 45, 33}, '__builtins__': <module 'builtins' (built-in)>, 'b': frozenset({1, 4, 45, 33}), 'res1': <map object at 0x101a534e0>, 'res2': 45, 'c': {'a': 1, 'b': 'aaaaa'}, '__doc__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, 'calc': <function <lambda> at 0x101a478c8>, '__spec__': None, 'i': 16, 'Iterable': <class 'collections.abc.Iterable'>, 'Iterator': <class 'collections.abc.Iterator'>, 'func': <function func at 0x101a477b8>, 'madlib': ' I took the cheese off the table ', 'code': 'for i in range(5):print(i)', '__package__': None}
    >>> print(globals().get('local_var'))
    None
    >>> print(max([1,2,3,4]))  #打印最大
    4
    >>> print(min([1,2,3,4]))   #打印最小
    1
    >>> print(oct(255))  #打印8进制
    0o377
    >>> a = 'Hello world'
    
    #str与repr的区别在于str与repr虽然都是显示字符串、但是str显示的更人性化、所以一般和print一起调用,而repr一般是给解释器使用所以和eval()一起使用的多一些
    >>> b = str(a)
    >>> c = repr(a)  #对该字符串再增加引号
    >>> d = eval(c)  #将c增加的引号脱去
    >>> print(a==b)
    True
    >>> print(a==c)
    False
    >>> print(a==d)
    True
    >>> print(str(a))
    Hello world
    >>> print(repr(a))
    'Hello world'
    >>> print(eval(repr(a)))
    Hello world
    >>> print(list(reversed([3,4,55,23,45]))) #对列表里的数据倒序排列
    [45, 23, 55, 4, 3]
    >>> round(1.3345,3)#去小数点3位
    1.335
    >>> slice(2,6)
    slice(2, 6, None)
    >>> d = range(20)
    >>> d
    range(0, 20)
    >>> d[slice(2,5)]  #分割
    range(2, 5)
    >>> sum([1,44,32,11,45])#将列表中的数据相加
    133
    >>> type([1,44,32,11,45]) #打印数据类型
    <class 'list'>
    >>> a = {6: 2,8:0, 1:4,-5:6,99: 11,4:22} 
    >>> print(a)
    {1: 4, 99: 11, 4: 22, 6: 2, 8: 0, -5: 6}
    >>> print(sorted(a.items())) #对字典按照key值来排序
    [(-5, 6), (1, 4), (4, 22), (6, 2), (8, 0), (99, 11)]
    >>> print(sorted(a.items(),key=lambda x:x[1])) #对字典按照value值来排序
    [(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)]
    >>> print(sorted(a.items(),key=lambda x:x[1],reverse = False ))#对字典按照value值来排序,默认reverse = False采用正序排序
    [(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)]
    >>> print(sorted(a.items(),key=lambda x:x[1],reverse = True ))#对字典按照value值来排序,reverse = True采用反序排序

    [(4, 22), (99, 11), (-5, 6), (1, 4), (6, 2), (8, 0)]
    >>> print(sorted(a.items(),reverse = True )) #对字典的key值进行反向排序
    [(
    99, 11), (8, 0), (6, 2), (4, 22), (1, 4), (-5, 6)]
    >>> a = [1,2,3,4]
    >>> b = ['a','b','c','d']
    >>> for i in zip(a,b):print(i) #合并打印
    ...
    (
    1, 'a') (2, 'b') (3, 'c') (4, 'd')
    >>> c = ['a','b']
    >>> for i in zip(a,c):print(i) #如果一方的值少,会按照少的那方的数据个数来打印
    ...
    (
    1, 'a') (2, 'b')
    >>> __import__('os') #和import一样,但是是采用字符串方式来进行引用
    <module 'os' from '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/os.py'
    > >>> __import__('os',globals(),locals(),['path','pip'])
    <module 'os' from '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/os.py'>

    7、json、pickle与序列化

    用于序列化的两个模块

    • json 用于字符串与python数据类型间进行转换
    • pickle用于python特有的类型与python数据类型间进行转换

    Json模块提供了四个功能:dumps、dump、loads、load

    pickle模块提供了四个功能:dumps、dump、loads、load

    json默认情况下只字符串、字典、列表进行序列化,因为json是通用的,所有语言都支持json,在不进行特殊自定义情况下,不能序列化函数

    import json
    info = {
        'name': 'alex',
        'age': 23,
        'job': 'IT'
    }
    
    print(repr(info))
    #输出
    {'job': 'IT', 'name': 'alex', 'age': 23}
    info_json = json.dumps(info,sort_keys=True)  #sort_keys用来对序列进行排序
    print(info_json)
    #输出
    {"age": 23, "job": "IT", "name": "alex"}
    info_json1 = json.dumps(info,sort_keys=True, indent=4) #indent可以对dumps的序列进行优化,表示数值离括号的距离
    print(info_json1)
    #输出
    {
        "age": 23,
        "job": "IT",
        "name": "alex"
    }
    info_json2 = json.dumps(info,sort_keys=True, separators=(',',':')) #在网络传输过程中为了节省传输带宽,可以对无用的字符进行压缩,这里是对,和:进行压缩以节省更多传输空间
    print(info_json2)
    #输出
    {"age":23,"job":"IT","name":"alex"}
    import json
    info = {
        'name': 'alex',
        'age': 23,
        'job': 'IT'
    }
    
    with open('seriliaztion.txt','w') as f:
        f.write(repr(info))  #按照普通方式写入文件,普通方式写入要求字符串格式进行写入
    
    
    with open('seriliaztion.txt','r') as f:
        for line in f:
            print(type(line))
            print(line)  #对该形式存入的输出只能按照字符串方式进行打印
    
    #输出
    <class 'str'>
    {'age': 23, 'name': 'alex', 'job': 'IT'}
    
    with open('seriliaztion-json.txt','w') as f:
        f.write(json.dumps(info,sort_keys=True)) #在写入时对其进行json编码
    
    
    with open('seriliaztion-json.txt','r') as f:
        for line in f:
            print(json.loads(line)['name'])  #对此进行解码,在解码后可以按照字典方式针对key打印value
            print(json.loads(line)['age'])
            print(json.loads(line)['job'])
    #输出
    alex
    23
    IT
    with open('seriliaztion-json.txt','r') as f:
        data = json.load(f) #等同于data = json.loads(f.read())
    print(data['job'])
    #输出
    IT
    #pickle与json的区别在于pickle不需要特殊定义就默认支持将函数序列化,同时pickle生产的文件是二进制文件,需要加b
    import pickle
    def sayhi(name):
        print('hi {}'.format(name))
    
    info = {
        'name': 'gavin',
        'age': 30,
        'func': sayhi
    }
    
    with open('seriliaztion-pickle.txt','wb') as f:  #需要加wb
        pickle.dump(info,f)  #等同于f.write(pickle.dumps(info))

     8、软件目录结构规范

     (摘抄于http://www.cnblogs.com/alex3714/articles/5765046.html)

    为什么要设计好目录结构?

    "设计项目目录结构",就和"代码编码风格"一样,属于个人风格问题。对于这种风格上的规范,一直都存在两种态度:

    1. 这种个人风格问题"无关紧要"。理由是能让程序work就好,风格问题根本不是问题。
    2. 规范化能更好的控制程序结构,让程序具有更高的可读性。

    "项目目录结构"其实也是属于"可读性和可维护性"的范畴,设计一个层次清晰的目录结构,就是为了达到以下两点:

    1. 可读性高: 不熟悉这个项目的代码的人,一眼就能看懂目录结构,知道程序启动脚本是哪个,测试目录在哪儿,配置文件在哪儿等等。从而非常快速的了解这个项目。
    2. 可维护性高: 定义好组织规则后,维护者就能很明确地知道,新增的哪个文件和代码应该放在什么目录之下。这个好处是,随着时间的推移,代码/配置的规模增加,项目结构不会混乱,仍然能够组织良好。

    所以,保持一个层次清晰的目录结构是有必要的。更何况组织一个良好的工程目录,其实是一件很简单的事儿。

    目录组织方式

    假设你的项目名为foo, 最方便快捷目录结构这样就足够了:

    Foo/

    |-- bin/
    |   |-- foo
    |
    |-- foo/ | |-- tests/ | | |-- __init__.py | | |-- test_main.py | | | |-- __init__.py | |-- main.py | |-- docs/ | |-- conf.py | |-- abc.rst | |-- setup.py |-- requirements.txt |-- README

    简要解释一下:

    1. bin/: 存放项目的一些可执行文件,当然你可以起名script/之类的也行。
    2. foo/: 存放项目的所有源代码。(1) 源代码中的所有模块、包都应该放在此目录。不要置于顶层目录。(2) 其子目录tests/存放单元测试代码; (3) 程序的入口最好命名为main.py
    3. docs/: 存放一些文档。
    4. setup.py: 安装、部署、打包的脚本。
    5. requirements.txt: 存放软件依赖的外部Python包列表。
    6. README: 项目说明文件。

    除此之外,有一些方案给出了更加多的内容。比如LICENSE.txt,ChangeLog.txt文件等

    下面,再简单讲一下这些目录的理解和个人要求

    关于README的内容

    每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。

    它需要说明以下几个事项:

    1. 软件定位,软件的基本功能。
    2. 运行代码的方法: 安装环境、启动命令等。
    3. 简要的使用说明。
    4. 代码目录结构说明,更详细点可以说明软件的基本原理。
    5. 常见问题说明。

    有以上几点是比较好的一个README。在软件开发初期,由于开发过程中以上内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的。

    关于requirements.txt和setup.py

    setup.py

    一般来说,用setup.py来管理代码的打包、安装、部署问题。业界标准的写法是用Python流行的打包工具setuptools来管理这些事情。这种方式普遍应用于开源项目中。不过这里的核心思想不是用标准化的工具来解决这些问题,而是说,一个项目一定要有一个安装部署工具,能快速便捷的在一台新机器上将环境装好、代码部署好和将程序运行起来。

    刚开始接触Python写项目的时候,安装环境、部署代码、运行程序这个过程全是手动完成,遇到过以下问题:

    1. 安装环境时经常忘了最近又添加了一个新的Python包,结果一到线上运行,程序就出错了。
    2. Python包的版本依赖问题,有时候我们程序中使用的是一个版本的Python包,但是官方的已经是最新的包了,通过手动安装就可能装错了。
    3. 如果依赖的包很多的话,一个一个安装这些依赖是很费时的事情。
    4. 新同学开始写项目的时候,将程序跑起来非常麻烦,因为可能经常忘了要怎么安装各种依赖。

    setup.py可以将这些事情自动化起来,提高效率、减少出错的概率。"复杂的东西自动化,能自动化的东西一定要自动化。"是一个非常好的习惯。

    setuptools的文档比较庞大,刚接触的话,可能不太好找到切入点。学习技术的方式就是看他人是怎么用的,可以参考一下Python的一个Web框架,flask是如何写的: setup.py

    当然,简单点自己写个安装脚本(deploy.sh)替代setup.py也未尝不可。

    requirements.txt

    这个文件存在的目的是:

    1. 方便开发者维护软件的包依赖。将开发过程中新增的包添加进这个列表中,避免在setup.py安装依赖时漏掉软件包。
    2. 方便读者明确项目使用了哪些Python包。

    这个文件的格式是每一行包含一个包依赖的说明,通常是flask>=0.10这种格式,要求是这个格式能被pip识别,这样就可以简单的通过 pip install -r requirements.txt来把所有Python包依赖都装好了。

    关于配置文件的使用方法

    注意,在上面的目录结构中,没有将conf.py放在源码目录下,而是放在docs/目录下。

    很多项目对配置文件的使用做法是:

    1. 配置文件写在一个或多个python文件中,比如此处的conf.py。
    2. 项目中哪个模块用到这个配置文件就直接通过import conf这种形式来在代码中使用配置。

    这种做法我不太赞同:

    1. 这让单元测试变得困难(因为模块内部依赖了外部配置)
    2. 另一方面配置文件作为用户控制程序的接口,应当可以由用户自由指定该文件的路径。
    3. 程序组件可复用性太差,因为这种贯穿所有模块的代码硬编码方式,使得大部分模块都依赖conf.py这个文件。

    所以,我认为配置的使用,更好的方式是,

    1. 模块的配置都是可以灵活配置的,不受外部配置文件的影响。
    2. 程序的配置也是可以灵活控制的。

    能够佐证这个思想的是,用过nginx和mysql的同学都知道,nginx、mysql这些程序都可以自由的指定用户配置。

    所以,不应当在代码中直接import conf来使用配置文件。上面目录结构中的conf.py,是给出的一个配置样例,不是在写死在程序中直接引用的配置文件。可以通过给main.py启动参数指定配置路径的方式来让程序读取配置内容。当然,这里的conf.py你可以换个类似的名字,比如settings.py。或者你也可以使用其他格式的内容来编写配置文件,比如settings.yaml之类的。

        

      

  • 相关阅读:
    CSS盒子模型
    getContextPath、getServletPath、getRequestURI、request.getRealPath的区别
    MYSQL中的CASE WHEN END AS
    单点登录的精华总结
    git&github
    June 21st 2017 Week 25th Wednesday
    June 20th 2017 Week 25th Tuesday
    June 19th 2017 Week 25th Monday
    June 18th 2017 Week 25th Sunday
    June 17th 2017 Week 24th Saturday
  • 原文地址:https://www.cnblogs.com/xiaopi-python/p/6370150.html
Copyright © 2011-2022 走看看