缪雪峰python笔记

  • 基础

    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.

推荐阅读更多精彩内容