美文网首页Python18Python
缪雪峰python笔记

缪雪峰python笔记

作者: neo已经被使用 | 来源:发表于2017-08-26 21:09 被阅读201次
    • 基础

      1.r''表示''内部的字符串默认不转义
      2.'''...'''表示多行内容
      3. 布尔值:True、False(注意大小写)
      4.与运算and、或运算:or、非运算:not
      5. None代表空值
      6.声明一个变量(前面不用声明类型--动态语言):  
               a = 1;//a是整数
               b = 'hello'//b是str(字符串)
      7.除法:
            /:  9/3 = 3.0(计算结果是浮点数)
       地板除//:  10/3 = 3(计算结果是整数)
      8.ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符
      9.对bytes类型的数据用带b前缀的单引号或双引号表示:x = b'ABC'
      10.要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes
          '中文'.encode('utf-8') 得到bytes类型为b'\xe4\xb8\xad\xe6\x96\x87'
        从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()
        b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')得到str类型为'中文'
      11.计算长度len():计算的是str的字符数,如果换成bytes应该这么写len(b'ABC')输出3
           len('中文'.encode('utf-8'))输出6,可见一个英文字符占一个字节,一个中文字符占3个字节
      12.如果源代码中有中文,则需要在开头加上
            # -*- coding: utf-8 -*- 
        告诉Python解释器按utf-8编码读取,注意:声明了这个并不代表文件本身是utf-8编码的
      13.格式化字符串%:
          'Hello, %s' % 'world' -----'Hello, world'
          'Hi, %s, you have $%d.' % ('Michael', 1000000)-----'Hi, Michael, you have $1000000.'
          格式化整数和浮点数还可以指定是否补0和整数与小数的位数:
          '%2d-%02d' % (3, 1)----' 3-01'
          '%.2f' % 3.1415926-----'3.14'
          %015d  ----至少15位(不足高位补0)
          如果你不太确定应该用什么,%s永远起作用,它会把任何数据类型转换为字符串:
          'Age: %s. Gender: %s' % (25, True)----'Age: 25. Gender: True'
          字符串里面的%是一个普通字符怎么办?这个时候就需要转义,用%%来表示一个%
      14.有序列表list(可变)和tuple(不可变)
              list:
                    s = ['first','second','three']//索引从0开始s[0]
                    //还可以-1做索引代表最后一个s[-1]是three、s[-2]、s[-3]
                    s.append('x')
                    s.insert(1,'x')
                    s.pop()//删除末尾元素
                    s.pop(1)//删除index为1的元素
                    s[1]='haha'//替换
                    list里面的元素的数据类型也可以不同,比如:
                    L = ['Apple', 123, True]
                    [] 是空列表
             tuple:
                   ()是空tuple
                   (1)定义的不是tuple而是小括号1这个数
                  所以,只有1个元素的tuple定义时必须加一个逗号,,来消除歧义:(1,)
                  “可变的”tuple:
                  t = ('a', 'b', ['A', 'B'])
                  t[2][0] = 'X'
                  t[2][1] = 'Y'
      15.条件判断:
                      if x://只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False
                          print('True')//注意要缩进
      16.int()函数把str转换成整数
      17.循环有两种:a.for...in循环 b.while循环
            names = ['Michael', 'Bob', 'Tracy']
            for name in names:
                print(name)
            sum = 0
            n = 99
            while n > 0:
                sum = sum + n
                n = n - 2
            print(sum)
      18. 字典dict,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度
            d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
            d['Michael']//得到 95
            避免key不存在的错误,有两种办法,
              一是通过in判断key是否存在:'Thomas' in d
              二是通过dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value:
                d.get('Thomas')  
                d.get('Thomas', -1)
            pop(key)//删除
            dict的key必须是不可变对象
      19. set(无序和无重复元素的集合):set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key
          s = set([1, 2, 3])//传入的参数[1, 2, 3]是一个list
          add(key)
          remove(key)
      20.字符串可以通过+相连(和java一样)
      21.bin()十进制转二进制,hex()十进制转十六进制,oct()十进制转八进制,0b二进制  0x十六进制  0八进制
      22.join()方法:
        fields = []
        fields.append('a')
        fields.append('b')
        fields.append('c')
        fields.append('d')
        print(" ".join(fields))#输出a b c d
        print(",".join(fields))#输出a,b,c,d
      
    • 函数

      1.函数名是指向一个函数对象的引用,可以把函数名赋给一个变量,相当于“别名”  eg:
        a = abs #abs是内置函数取绝对值
        a(-1)
      2.定义函数:
            def my_abs(x): #有冒号
                if x >= 0: #注意缩进
                    return x #注意缩进
                else:
                    return -x
      3.默认参数:
          def power(x, n=2):
          power(5)和power(5,2)的结果是一样的
         默认参数的坑:L默认是一个空列表,每次调用这个方法L的内容会改变,导致L的内容是改变后的内容
          def add_end(L=[]):
              L.append('END')
              return L  
          调用第一次返回['END']
          调用第二次返回['END','END']
          ...
          解决方法:
          def add_end(L=None):
              if L is None:
                  L = []
              L.append('END')
              return L
          因为None是不可变对象,所以每次调用只会加一个
          调用第一次返回['END']
          调用第二次返回['END']
      4.可变参数(*):在函数调用时自动组装为一个tuple
          def calc(*numbers):
          calc(1,2,3) #调用
          如果已经有了一个list或tuple,只需要在前面加*就会当成可变参数
          nums = [1, 2, 3]
          calc(*nums)
      5.关键字参数(**):可变参数在函数调用时自动组装为一个dict,是参数的拷贝,改变不会影响参数本身
        def person(name, age, **kw):
            print('name:', name, 'age:', age, 'other:', kw)
        eg:person('Adam', 45, gender='M', job='Engineer')
              输出name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
        如果已经有了一个dict,只需要在前面加**就会当成关键字参数
        extra = {'city': 'Beijing', 'job': 'Engineer'}
        person('Jack', 24, **extra)
      6.命名关键字参数
        对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数
        如果要限制关键字参数的名字,就可以用命名关键字参数
        例如,只接收city和job作为关键字参数,定义如下:
        def person(name, age, *, city, job): #*后面的参数被视为命名关键字参数
            print(name, age, city, job) 
        此时调用函数时必须传递四个参数,并且最后两个字典的key必须分别是 city和job,否则会报错
        如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
        def person(name, age, *args, city, job):
            print(name, age, args, city, job)
        命名关键字可以有缺省值:
        def person(name, age, *, city='Beijing', job): #调用时可以不用传city的字典
      7.参数组合
        def f1(a, b, c=0, *args, **kw):
              print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
        注意 tuple 和 list可以调用  eg:
           args = (1, 2, 3, 4)
           kw = {'d': 99, 'x': '#'}
           f1(*args, **kw)
          输出a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
      8.尾递归
          在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况
          普通递归:
            def fact(n):
                if n==1:
                    return 1
                return n * fact(n - 1)#表达式
            尾递归:
            def fact(n):
                return fact_iter(n, 1)
            
            def fact_iter(num, product):
                if num == 1:
                    return product
                return fact_iter(num - 1, num * product) #没有表达式,仅返回递归函数本身
      
    • 高级特性

      1. 切片(Slice):取一个list或tuple的部分元素
          L[0:3]代表取L的[0,3),如果第一个索引为0,还可以省略:L[:3]
          L[1:len(L)]代表L的[1,L的长度),可以省略为L[1:]
          L[-1]取倒数第一个元素,L[-2:]代表取后面两个
          L[:10:2] 前10个元素 每隔两个取一个
          L[::5] 所有元素,每隔五个取一个
          对tuple切片得到的结果还是tuple
          字符串'xxx'也可以看成是一种list,可以进行切片(类似java中的substring),eg:
          'ABCDEFG'[:3] ->'ABC'
      2.迭代(for ... in):只要是可迭代对象就可以使用这种方式
          dict默认是对key迭代,若要对value 则 for value in dict.values():  若同时对key value迭代则for k, v in d.items()
          字符串也是可迭代对象 eg:for ch in 'ABC':
          如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:
            from collections import Iterable
            isinstance('abc', Iterable) # str是否可迭代 输出true
          对list实现类似Java那样的下标循环:
            for i, value in enumerate(['A', 'B', 'C']):
                print(i, value) #输出0 A   (","逗号会输出空格)
                                    1 B
                                    2 C
         同时遍历两个变量
         for x, y in [[1, 1], [2, 4], [3, 9]]:
              print(x, y)
      3.列表生成式(#注意操作在for前面)
          list(range(1, 11)) 生成 [1,10]
          [x * x for x in range(1, 11)] 生成[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
          还可以过滤:
          [x * x for x in range(1, 11) if x % 2 == 0] 生成[4, 16, 36, 64, 100]
          两层循环,可以生成全排列:
          [m + n for m in 'ABC' for n in 'XYZ']生成 ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
          for循环其实可以同时使用两个甚至多个变量:
          d = {'x': 'A', 'y': 'B', 'z': 'C' }
          for k, v in d.items():
              print(k, '=', v)
          输出:y = B
               x = A
               z = C
          把一个list中所有的字符串变成小写:
          L = ['Hello', 'World', 'IBM', 'Apple']
          [s.lower() for s in L] #注意操作在for前面
        4.生成器(generator):不必创建完整的list,从而节省大量的空间
          把一个列表生成式的[]改成(),就创建了一个generator
          如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
          每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行,eg定义一个generator,依次返回数字1,3,5:
          def odd():
          yield 1
          yield(3)
          yield(5)
          for i in odd():
          print(i)
          输出1 3 5
        也可以这样  o = odd()
                  next(o)
                  next(o)
                  next(o)
         同样输出1 3 5(到了最后一个元素,再调用next(o)会报错)
      5.迭代器(Iterator)
          凡是可作用于for循环的对象都是Iterable类型;
          凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
          集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
          Python的for循环本质上就是通过不断调用next()函数实现的
      
    • 函数式编程

      1.map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回
      2. reduce()和map接收参数一样,把结果继续和序列的下一个元素做累积计算eg:reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
      3.字符串转int(利用 map 和reduce)
          from functools import reduce
          def str2int(s):
              def fn(x, y):
                  return x * 10 + y
              def char2num(s):
                  return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
              return reduce(fn, map(char2num, s))
      4.filter()筛选和map接收参数一样,返回也是Iterator惰性序列
      5.sorted()函数可以对list进行排序,还可以接收一个参数key函数来实现自定义排序eg:按绝对值排序:
        sorted([36, 5, -12, 9, -21], key=abs) # 输出 [5, 9, -12, -21, 36]
        要进行反向排序,不必改动key函数,可以传入第三个参数reverse=True
      6.返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量
        def count():
            fs = []
            for i in range(1, 4):
                def f():
                     return i*i
                fs.append(f)
            return fs
        
        f1, f2, f3 = count() #此时f1() f2() f3()的结果都是9,因为引用了同一个变量i ,解决办法:
        def count():
            def f(j):
                def g():
                    return j*j
                return g
            fs = []
            for i in range(1, 4):
                fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
            return fs       
      7.匿名函数
        def f(x):
            return x * x
        等价于 lambda x: x * x
      8.装饰器:在不改变某个函数具体实现的情况下,增加函数的功能
        def now():
            print('2015-3-25')
        需要增加打印函数名的功能:
        def log(func):
            @functools.wraps(func)#用于把原始函数的__name__等属性复制到wrapper()函数中,否则调用now.__name__会得到 wrapper
            def wrapper(*args, **kw):
                print('call %s():' % func.__name__)#__name__是函数对象内置
                return func(*args, **kw)
            return wrapper
        使用@
        @log
        def now():
            print('2015-3-25')
       @log 等价于 now = log(now)
        输出:call now():
             2015-3-25
      如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数eg:
        def log(text):
            def decorator(func):
                def wrapper(*args, **kw):
                    print('%s %s():' % (text, func.__name__))
                    return func(*args, **kw)
                return wrapper
            return decorator
        用法:
        @log('execute')
        def now():
            print('2015-3-25')
      9.偏函数(functools.partial):把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单
         int()函数默认按十进制转换
        int('12345', 8)转化8进制到十进制
        import functools
        int2 = functools.partial(int, base=2)#偏函数,转换二进制到10进制
        int2('1000000')  相当于kw = { 'base': 2 }
                              int('10010', **kw)
        max2 = functools.partial(max, 10)#实际上会把10作为*args的一部分自动加到左边,也就是:
        max2(5, 6, 7)相当于args = (10, 5, 6, 7)
                          max(*args)
      
    • 模块

      1.一个.py文件就是一个模块
      2.if __name__=='__main__':  #运行本模块会为True,在其他模块导入这个模块时会为False
      3.作用域:
            正常的函数和变量名是公开的(public)eg:a、b、c
            类似_xxx和__xxx这样的函数或变量就是非公开的(private)eg:_a、__b
      
    • 面向对象编程

      1.类(class)和实例:
        class Student(object):#表示Student类继承object
            def __init__(self, name, score):#第一个参数必须是self,init前后有两个下划线,代表初始化必须传name、score两个参数
                self.name = name#public 
                self.__score = score#private
          不能直接访问__score是因为Python解释器对外把__score变量改成了_Student__score,所以,仍然可以通过_Student__score来访问__score变量(不建议!!)
          bart.__score = 20 # 设置__score变量!是给bart新增了一个变量__score
      2.type()获取对象的类型
      3.类属性(类似java的静态变量)
        class Student(object):
            name = 'Student'
      4.在类中定义的函数第一个参数永远是实例变量self(self指向创建的实例本身),并且调用时不用传递该参数
      5.__init__类似于构造方法,用于创建类时必须传递的参数
      6.变量名类似__xxx__的是特殊变量,特殊变量是可以直接访问的,不是private变量
        7.dir()获得一个对象的所有属性和方法
        8.类似__xxx__的属性和方法在Python中都是有特殊用途的,调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__() eg:
            len('ABC') == 'ABC'.__len__()
        我们自己写的类,如果也想用len(myObj)的话,就自己写一个__len__()方法
      9.给实例绑定属性的方法是通过实例变量,或者通过self变量
      10.给类动态绑定方法:
        def set_age(self, age): # 定义一个函数作为实例方法
            self.age = age
        from types import MethodType
        s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
        s.set_age(25) # 调用实例方法
        s.age # 测试结果 输出25
          但是,给一个实例绑定的方法,对另一个实例是不起作用的,解决方法给class绑定:
              def set_score(self, score):
                  self.score = score
              Student.set_score = set_score
      
    • 面向对象高级编程

      1.动态绑定允许我们在程序运行的过程中动态给class加上功能:
      def set_score(self, score):
           self.score = score
      Student.set_score = set_score #动态绑定方法
      s = Student()
      s.set_score(100)
      s.score 
      2.__slots__限制实例可绑定的属性(仅对当前类实例起作用,对继承的子类不起作用)
        class Student(object):
            __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
         s = Student() # 创建新的实例
          s.name = 'Michael' # 绑定属性'name'
          s.age = 25 # 绑定属性'age'
          s.score = 99 # 绑定属性'score'会报错
      3.多继承 class Dog(Mammal, Runnable):
      4.__str__ 类似java 的toString方法
        class Student(object):
            def __init__(self, name):
            self.name = name
            def __str__(self):
            return 'Student object (name: %s)' % self.name
            使用:print(Student('Michael')) 输出 Student object (name: Michael)
          直接显示变量调用的不是__str__(),而是__repr__()(可以令__repr__ = __str__)
      5.__iter__ 使一个类可用于for ... in循环
        class Fib(object):
            def __init__(self):
                self.a, self.b = 0, 1 # 初始化两个计数器a,b
            def __iter__(self):
                return self # 实例本身就是迭代对象,故返回自己
            def __next__(self):
                self.a, self.b = self.b, self.a + self.b # 计算下一个值
                if self.a > 100000: # 退出循环的条件
                    raise StopIteration()
                return self.a # 返回下一个值
      6.__getitem__使一个类可按照下标取出元素
      7.__getattr__使可以访问一个非类的属性
        class Student(object):
            def __init__(self):
                self.name = 'Michael'
            def __getattr__(self, attr):
                if attr=='score':
                    return 99
                Student().score
         实例:链式调用
        class Chain(object):
            def __init__(self, path=''):
                self._path = path
            def __getattr__(self, path):
                return Chain('%s/%s' % (self._path, path))
            def __str__(self):
                return self._path
            __repr__ = __str__
              Chain().status.user.timeline.list #输出:'/status/user/timeline/list'
      8.__call__ 使得对象方便的调用方法
        class Student(object):
            def __init__(self, name):
                self.name = name
            def __call__(self):
                print('My name is %s.' % self.name)
      调用:s = Student('neo')
           s() #输出My name is neo
      所以你完全可以把对象看成函数,把函数看成对象
      通过callable()函数,我们就可以判断一个对象是否是“可调用”对象.
      9.枚举
      from enum import Enum
      Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
      直接使用Month.Jan来引用一个常量,枚举它的所有成员:
        for name, member in Month.__members__.items():
            print(name, '=>', member, ',', member.value)
      10.type()函数既可以返回一个对象的类型,又可以创建出新的类型
            返回类型:
        from hello import Hello
        h = Hello()
        h.hello()#Hello, world.
        print(type(Hello))#<class 'type'> Hello是一个class,它的类型就是type
        print(type(h))#<class 'hello.Hello'> h是一个实例,它的类型就是hello.py模块下的 Hello类
            创建类型:
        def fn(self, name='world'): # 先定义函数
            print('Hello, %s.' % name)
            Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
            h = Hello()
            h.hello()#Hello, world.
            print(type(Hello))#<class 'type'>
            print(type(h))#<class '__main__.Hello'> # __main__模块的Hello类
          type()函数参数:
                  1.class的名称;
                  2.继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
                  3.class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
      11.元类metaclass(可以把类看成是metaclass创建出来的“实例”)
        # metaclass是类的模板,所以必须从`type`类型派生:
        class ListMetaclass(type):
            def __new__(cls, name, bases, attrs):
                attrs['add'] = lambda self, value: self.append(value)
                return type.__new__(cls, name, bases, attrs)
        class MyList(list, metaclass=ListMetaclass):#说明Python创建MyList会去调用元类ListMetaclass的__new__方法
            pass
        L = MyList()
        L.add(1)
        print(L)#输出[1]
      __new__()方法接收到的参数依次是:
        1.当前准备创建的类的对象;
        2.类的名字;
        3.类继承的父类集合;
        4.类的方法集合。
      12.使用@property:@property装饰器就是负责把一个方法变成属性调用。
        class Student(object):
            @property
            def birth(self):
                return self._birth#下划线开头的变量名是可以外部直接方法的(但是不建议这么做)
            @birth.setter #@property内部创建的:方法名.setter
            def birth(self, value):
                self._birth = value
            @property
            def age(self):
                return 2015 - self._birth
          birth是可读写属性,而age就是一个只读属性
          s = Student()
          s.birth = 12#等同于s.birth(12)   .方法名
          s.birth #等同于s.birth()
      13.python可以多继承
      
    • 错误、调试、测试

      1.
        try:
            print('try...')
            r = 10 / int('2')
            print('result:', r)
        except ValueError as e:
            print('ValueError:', e)
        except ZeroDivisionError as e:
            print('ZeroDivisionError:', e)
        else:
            print('no error!')
        finally:
            print('finally...')
      2. raise类似java的throw
          logging类似Log
      3. pdb命令行方式进行调试
      
    • IO编程

      1.文本文件(默认utf-8)
        try:
            f = open('/Users/neo/fps.txt', 'r',encoding='gbk')#'r'表示读
            print(f.read())
        finally:
            if f:
                f.close()#及时关闭
      等价于
        with open('/Users/neo/fps.txt', 'r') as f:
            print(f.read())#不用close
        read()一次性读取全部内部到内存有危险,可反复调用read(size)方法
      2.二进制文件
        f = open('/Users/michael/test.jpg', 'rb')
      3. StringIO:在内存中读写str
        from io import StringIO
        f = StringIO()
        f.write('hello')
        f.write(' ')
        f.write('world!')
        print(f.getvalue())#输出hello world!
      
        from io import StringIO
        f = StringIO('Hello!\nHi!\nGoodbye!')
        while True:
            s = f.readline()
            if s == '':
                break
            print(s.strip())#输出Hello!
                                Hi!
                                Goodbye!
      4.BytesIO:用法和StringIO类似,是内存中读写字节
      5.import os
        os.path.abspath('.')# 查看当前目录的绝对路径:
        os.path.join('/Users/neo', 'testdir')# 在某个目录下创建一个新目录,首先把新目录的完整路径表示出来:
        os.mkdir('/Users/neo/testdir')# 然后创建一个目录:
        os.rmdir('/Users/neo/testdir')# 删掉一个目录:
        os.rename('test.txt', 'test.py')# 对文件重命名:
        os.remove('test.py')# 删掉文件:
      5.列出所有的.py文件
        [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
      6. pickling序列化(利用pickle模块)
          对象到JSON格式的转换(json模块)
        import json
        d = dict(name='Bob', age=20, score=88)
        print(json.dumps(d))#输出{"name": "Bob", "age": 20, "score": 88}
          JSON转为对象
        import json
        json_str = '{"age": 20, "score": 88, "name": "Bob"}'
        persion = json.loads(json_str)
        print(persion['age'])#输出20
      7.json模块序列化类
        import json
        class Student(object):
            def __init__(self, name, age, score):
                self.name = name
                self.age = age
                self.score = score
        def student2dict(std):
                return {
                    'name': std.name,
                    'age': std.age,
                    'score': std.score}
      
        s = Student('Bob', 20, 88)
        print(json.dumps(s,default=student2dict))
        print(json.dumps(s, default=lambda obj: obj.__dict__))#把任意class的实例变为dict
      反序列化:
        import json
        class Student(object):
            def __init__(self, name, age, score):
                self.name = name
                self.age = age
                self.score = score
        def dict2student(d):
            return Student(d['name'], d['age'], d['score'])
        json_str = '{"age": 20, "score": 88, "name": "Bob"}'
        print(json.loads(json_str, object_hook=dict2student))
      
    • 进程和线程

      1.Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,
        但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程(返回子进程id)和子进程(返回0)内返回
        import os
        print('Process (%s) start...' % os.getpid())
        # Only works on Unix/Linux/Mac:
        pid = os.fork()
        if pid == 0:
            print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))
        else:
            print('I (%s) just created a child process (%s).' % (os.getpid(), pid))
       输出Process (1812) start...
          I (1812) just created a child process (1813).
          I am child process (1813) and my parent is 1812.
      2.Windows没有fork,可使用multiprocessing模块
        from multiprocessing import Process
        import os
        # 子进程要执行的代码
        def run_proc(name):
            print('Run child process %s (%s)...' % (name, os.getpid()))
        if __name__=='__main__':
            print('Parent process %s.' % os.getpid())
            p = Process(target=run_proc, args=('test',))
            print('Child process will start.')
            p.start()
            p.join()#等待子进程结束后再继续往下运行
            print('Child process end.')
      3.多线程(使用threading模块)
        import time, threading
        # 新线程执行的代码:
        def loop():
            print('thread %s is running...' % threading.current_thread().name)
            n = 0
            while n < 5:
                n = n + 1
                print('thread %s >>> %s' % (threading.current_thread().name, n))
                time.sleep(1)
            print('thread %s ended.' % threading.current_thread().name)
        
        print('thread %s is running...' % threading.current_thread().name)
        t = threading.Thread(target=loop, name='LoopThread')
        t.start()
        t.join()#主线程等待子线程执行完毕
        print('thread %s ended.' % threading.current_thread().name)
      
      4.锁:lock = threading.Lock()
             lock.acquire()#获取锁
            lock.release()#一定要手动释放锁
      5.Python解释器由于设计时有GIL全局锁,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,
        解释器就自动释放GIL锁,让别的线程有机会执行,导致了多线程无法利用多核(可以使用多进程)
      6. ThreadLocal
        import threading
        # 创建全局ThreadLocal对象:
        local_school = threading.local()
        def process_student():
            # 获取当前线程关联的student:
            std = local_school.student
            print('Hello, %s (in %s)' % (std, threading.current_thread().name))
        def process_thread(name):
            # 绑定ThreadLocal的student:
            local_school.student = name
            process_student()
        t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
        t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
        t1.start()
        t2.start()
        t1.join()
        t2.join()
      输出Hello, Alice (in Thread-A)
         Hello, Bob (in Thread-B)
      
    • 正则表达式

      1. \d:匹配一个数字
         \w:匹配一个字母或数字
         \s:匹配一个空格(也包括Tab等空白符)
      2.匹配变长的字符:
        *表示任意个字符(包括0个)
        +表示至少一个字符
        ?表示0个或1个字符
        {n}表示n个字符,用{n,m}表示n-m个字符
      3.需要转义的字符:
        _ :\_
      4.表示范围:[]
          [0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线
          [0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'1','a100','0_Z','Py3000'等等
      5.^表示行的开头,^\d表示必须以数字开头。
        $表示行的结束,\d$表示必须以数字结束。
      6.re模块
      判断是否匹配:   
        import re
        if re.match(r'^\d{3}\-\d{3,8}$', '010-12345'):
            print('yes')
        else:
            print('no')
          输出yes
      �切分字符串:
      
    • 网络编程

      1.网络通信其实就是两个进程通信
      2.如果一台计算机同时接入到两个或更多的网络,比如路由器,它就会有两个或多个IP地址,所以,IP地址对应的实际上是计算机的网络接口,通常是网卡
      3.IP地址实际上是一个32位整数(称为IPv4),以字符串表示的IP地址如192.168.0.1实际上是把32位整数按8位分组后的数字表示,目的是便于阅读
      4.IPv6地址实际上是一个128位整数
      5.IP协议负责把数据从一台计算机通过网络发送到另一台计算机
      6.TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过握手建立连接,然后,对每个IP包编号,确保对方按顺序收到,如果包丢掉了,就自动重发
      7.HTTP协议基于TCP协议
      8.端口的作用:同一台计算机上跑着多个网络程序。一个IP包来了之后,到底是交给浏览器还是QQ,就需要端口号来区分
      9、端口号小于1024的是Internet标准服务的端口,端口号大于1024的,可以任意使用
      10.UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包,不可靠、速度快
      
    • 电子邮件

      1.Email从MUA(Mail User Agent--电子邮件软件)发出去,发到发件人邮箱所属的MTA:Mail Transfer Agent——邮件传输代理(Email服务提供商),
        从发件人所属的MTA发送到目标邮件地址所属的MTA(这个过程中间可能还会经过别的MTA),
        目标地址所属的MTA会把邮件发送到最终目的地MDA:Mail Delivery Agent——邮件投递代理,Email到达MDA后,就静静地躺在目标服务器,等待MUA从MDA中取邮件
      2.发邮件时,MUA和MTA使用的协议就是SMTP
      3.收邮件时,MUA和MDA使用的协议有两种:POP3、IMAP4
      4.MUA在发邮件时,要先配置SMTP服务器,也就是你要发到哪个MTA上
          假设你正在使用163的邮箱,你就不能直接发到新浪的MTA上,因为它只服务新浪的用户,
          所以,你得填163提供的SMTP服务器地址:smtp.163.com,为了证明你是163的用户,SMTP服务器还要求你填写邮箱地址和邮箱口令
          类似的,从MDA收邮件时,Outlook之类的邮件客户端会要求你填写POP3或IMAP服务器地址、邮箱地址和口令
        from email.mime.text import MIMEText
        msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
        # 输入Email地址和口令:
        from_addr = '755766986@qq.com'
        password = 'iwfcltqyzjbpbbjj'
        # 输入收件人地址:
        to_addr = '578179809@qq.com'
        # 输入SMTP服务器地址:
        smtp_server = 'smtp.qq.com'
      
        import smtplib
        server = smtplib.SMTP(smtp_server, 587) # SMTP协议默认端口是25
        server.set_debuglevel(1)
        server.starttls()
      
        server.login(from_addr, password)
        server.sendmail(from_addr, [to_addr], msg.as_string())
        server.quit()
      
    • 访问数据库

        # -*- coding: utf-8 -*- 
        # 导入MySQL驱动:
        import mysql.connector
        # 注意把password设为你的root口令:
        conn = mysql.connector.connect(user='root', password='zq112hf', database='test')
        cursor = conn.cursor()
        # 创建user表:
        cursor.execute('create table IF NOT EXISTS user (id varchar(20) primary key, name varchar(20))')
        # 插入一行记录,注意MySQL的占位符是%s:
        cursor.execute('insert into user (id, name) values (%s, %s)', ['2', 'Michael'])
        print('cursor.rowcount = %d'%cursor.rowcount)
        # 提交事务:
        conn.commit()
        cursor.close()
        # 运行查询:
        cursor = conn.cursor()
        cursor.execute('select * from user where id = %s', ('2',))
        values = cursor.fetchall()
        print(values)
        # 关闭Cursor和Connection:
        cursor.close()
        conn.close()
      
    • Web开发

    1.Python内置了一个WSGI(Web Server Gateway Interface)服务器:wsgiref模块,效率比较低,仅供开发和测试使用
        # server.py
        # 从wsgiref模块导入:
        from wsgiref.simple_server import make_server
        # 导入我们自己编写的application函数:
        from hello import application
        # 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
        httpd = make_server('', 8000, application)
        print('Serving HTTP on port 8000...')
        # 开始监听HTTP请求:
        httpd.serve_forever()
    
        # hello.py
        def application(environ, start_response):
            start_response('200 OK', [('Content-Type', 'text/html')])
            return [b'<h1>Hello, web!</h1>']
      运行server.py来启动WSGI服务器
    2.Web框架-Flask。每个请求对于一个方法
    from flask import Flask
    from flask import request
    
    app = Flask(__name__)
    
    @app.route('/', methods=['GET', 'POST'])
    def home():
        return '<h1>Home</h1>'
    
    @app.route('/signin', methods=['GET'])
    def signin_form():
        return '''<form action="/signin" method="post">
                  <p><input name="username"></p>
                  <p><input name="password" type="password"></p>
                  <p><button type="submit">Sign In</button></p>
                  </form>'''
    
    @app.route('/signin', methods=['POST'])
    def signin():
        # 需要从request对象读取表单内容:
        if request.form['username']=='admin' and request.form['password']=='password':
            return '<h3>Hello, admin!</h3>'
        return '<h3>Bad username or password.</h3>'
    
    if __name__ == '__main__':
        app.run()
    3. 使用模板
      在Jinja2模板中:
        {{ name }}:需要替换的变量
        {% ... %}:指令
    
    • 异步IO
    1.异步IO模型需要一个消息循环,在消息循环中,主线程不断地重复“读取消息-处理消息”过程
      当遇到IO操作时,代码只负责发出IO请求,不等待IO结果,然后直接结束本轮消息处理,进入下一轮消息处理过程。
      当IO操作完成后,将收到一条“IO完成”的消息,处理该消息时就可以直接获取IO操作结果
    2.协程:一个线程执行,效率高(子程序切换不是线程切换、不需要锁)
      协程通过generator实现(包含yield关键字的方法就是一个generator,不知道这样理解对不对)
        def consumer():#generator
            r = ''
            while True:
                n = yield r
                if not n:
                    return
                print('[CONSUMER] Consuming %s...' % n)
                r = '200 OK'
    
        def produce(c):#参数是一个generator
            c.send(None)
            n = 0
            while n < 5:
                n = n + 1
                print('[PRODUCER] Producing %s...' % n)
                x = c.send(n)
                print('[PRODUCER] Consumer return: %s' % x)
            c.close()
    
        c = consumer()#把generator赋值给变量c
        produce(c)
      执行过程:
          1.首先调用c.send(None)启动生成器(generator);
          2.然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
          3.consumer通过yield拿到消息,处理,又通过yield把结果传回(就是给consumer()的r赋值);
          4.produce拿到consumer处理的结果(上面的x),继续生产下一条消息;
          5.produce决定不生产了,通过c.close()关闭consumer,整个过程结束
    3. asyncio内置了对异步IO的支持(消息循环)
        import asyncio
        @asyncio.coroutine#标记为coroutine
        def hello():
            print("Hello world!")
            # 异步调用asyncio.sleep(1):
            r = yield from asyncio.sleep(1)#执行到这里会直接中断并去执行EventLoop中其他可以执行的coroutine
                                           #过了1秒返回一个None(r = None),CPU再来执行后面的代码
            print("Hello again!")
        # 获取EventLoop:
        loop = asyncio.get_event_loop()
        # 执行coroutine
        loop.run_until_complete(hello())#把协程放到消息队列里执行,如果有多个使用wait:asyncio.wait([hello(),A(),B()])
        loop.close()#记得关闭循环
    4.Python 3.5开始
        @asyncio.coroutine = async
        yield from = await
    5. aiohttp则是基于asyncio实现的HTTP框架
        import asyncio
    
        from aiohttp import web
    
        async def index(request):
            await asyncio.sleep(0.5)
            return web.Response(body=b'<h1>Index</h1>')
    
        async def hello(request):
            await asyncio.sleep(0.5)
            text = '<h1>hello, %s!</h1>' % request.match_info['name']
            return web.Response(body=text.encode('utf-8'))
    
        async def init(loop):
            app = web.Application(loop=loop)
            app.router.add_route('GET', '/', index)
            app.router.add_route('GET', '/hello/{name}', hello)
            srv = await loop.create_server(app.make_handler(), '127.0.0.1', 8000)
            print('Server started at http://127.0.0.1:8000...')
            return srv
    
        loop = asyncio.get_event_loop()
        loop.run_until_complete(init(loop))
        loop.run_forever()
    
    • 其他
    1.with关键字的用法:
          with expression as variable:
              with block
      该代码快的执行过程是: 1.先执行expression,然后执行该表达式返回的对象实例的__enter__函数,然后将该函数的返回值赋给as后面的变量。(注意,是将__enter__函数的返回值(返回expression的值)赋给变量) 
                         2.然后执行with block代码块,不论成功,错误,异常,在with block执行结束后,会执行第一步中的实例的__exit__函数。)
    2.

    相关文章

      网友评论

        本文标题:缪雪峰python笔记

        本文链接:https://www.haomeiwen.com/subject/gopudxtx.html