课程链接

Python教程

Python基础

  1. 整数
    • 对于很大的数,例如10000000000,很难数清楚0的个数。Python允许在数字中间以_分隔,即10_000_000_00010000000000是一样的
  2. 浮点数
    • 对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,1.23×1091.23×10^9就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5
  3. 字符串
    • 若字符串内部既包含'又包含"则可以用转义字符\来标识,如I'm "OK"!可以写成:
      'I\'m \"OK\"!'
      
    • 若字符串里面有很多字符都需要转义,为了简化,Python还允许用r''表示''内部的字符串默认不转义:
      >>> print('\\\t\\')
      \       \
      >>> print(r'\\\t\\')
      \\\t\\
      
  4. Python中的两种除法
    • /除法计算结果是浮点数,即使两个整数整除
    • //除法只取结果的整数部分
  5. 字符编码
    • Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符:
      >>> ord('A')
      65
      >>> chr(66)
      'B'
      
    • 以Unicode表示的str通过encode()方法可以编码为指定的bytes:
      >>> 'ABC'.encode('ascii')
      b'ABC'
      >>> '中文'.encode('utf-8')
      b'\xe4\xb8\xad\xe6\x96\x87'
      
    • 相反,从网络或磁盘上读取了的字节流数据就是bytes。要把bytes变为str,就需要用decode()方法:
      >>> b'ABC'.decode('ascii')
      'ABC'
      >>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
      '中文'
      
    • Python源代码文件头:
      #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      
    第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码
  6. 格式化
    • 使用%
      >>> 'Hello, %s' % 'world'
      'Hello, world'
      >>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
      'Hi, Michael, you have $1000000.'
      
    • 使用format()函数 :
      >>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
      'Hello, 小明, 成绩提升了 17.1%'
      
    • 使用f-string :
      >>> r = 2.5
      >>> s = 3.14 * r ** 2
      >>> print(f'The area of a circle with radius {r} is {s:.2f}')
      The area of a circle with radius 2.5 is 19.62
      
  7. 有序列表listtuple
    • list可以随时添加,删除和更改元素;tuple一经初始化就不能修改
      >>> classmates = ['Michael', 'Bob', 'Tracy'] # list
      >>> classmates = ('Michael', 'Bob', 'Tracy') # tuple
      
  8. range()函数
    • 生成一个整数序列,再通过list()函数转换为list
      >>> list(range(5))
      [0, 1, 2, 3, 4]
      
  9. dict字典类型
    • 使用键-值(key-value)存储
      >>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
      >>> d['Michael']
      95
      
  10. set集合类型
    • set也是一组key的集合,但不存储value,且key不能重复:
      >>> s = set([1, 1, 2, 2, 3, 3])
      >>> s
      {1, 2, 3}
      
    • set可进行交集、并集等操作:
      >>> s1 = set([1, 2, 3])
      >>> s2 = set([2, 3, 4])
      >>> s1 & s2
      {2, 3}
      >>> s1 | s2
      {1, 2, 3, 4}
      

函数

  1. 空函数
    • pass语句什么都不做,可用来作为占位符让程序先跑起来
  2. 参数检查
    • 数据类型检查可以使用内置函数isinstance()实现:
      def my_abs(x):
          if not isinstance(x, (int, float)):
              raise TypeError('bad operand type')
          if x >= 0:
              return x
          else:
              return -x
      
  3. 默认参数
    • 设置默认参数时,必选参数在前,默认参数在后
    • 有多个默认参数时,调用时既可以按顺序提供默认参数,又可以不按顺序提供部分默认参数。当不安顺序提供部分默认参数时,需要把参数名写上
  4. 可变参数
    • 对于参数个数不确定的函数可将参数变为可变参数:
      def calc(*numbers):
      sum = 0
      for n in numbers:
          sum = sum + n * n
      return sum
      
      >>> calc(1, 2)
      5
      >>> calc()
      0
      >>> nums = [1, 2, 3]
      >>> calc(*nums)
      14
      
  5. 关键字参数
    • 关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict:
      def person(name, age, **kw):
          print('name:', name, 'age:', age, 'other:', kw)
      
      >>> person('Bob', 35, city='Beijing')
      name: Bob age: 35 other: {'city': 'Beijing'}
      >>> person('Adam', 45, gender='M', job='Engineer')
      name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
      >>> extra = {'city': 'Beijing', 'job': 'Engineer'}
      >>> person('Jack', 24, **extra)
      name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
      
  6. 参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数

高级特性

  1. 切片
    >>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
    >>> L[0:3]
    ['Michael', 'Sarah', 'Tracy']
    >>> L[:3]
    ['Michael', 'Sarah', 'Tracy']
    >>> L[1:3]
    ['Sarah', 'Tracy']
    >>> L[-2:]
    ['Bob', 'Jack']
    >>> L[-2:-1]
    ['Bob']
    
    >>> L = list(range(100))
    >>> L[:10:2]
    [0, 2, 4, 6, 8]
    >>> L[::5]
    [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
    
  2. 迭代
    • dict迭代:
      >>> d = {'a': 1, 'b': 2, 'c': 3}
      >>> for key in d:
      ...
      >>> for value in d.values():
      ...
      >>> for k, v in d.items():
      ...
      
    • list实现下标循环:
      >>> for i, value in enumerate(['A', 'B', 'C']):
      ...     
      
  3. 列表生成式
    • 生成list
      >>> list(range(1, 11))
      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      
    • 根据特定规则生成list
      >>> [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']
      
    • 调用函数:
      >>> L = ['Hello', 'World', 'IBM', 'Apple']
      >>> [s.lower() for s in L]
      ['hello', 'world', 'ibm', 'apple']
      
    • if...else:
      在一个列表生成式中,for前面的if ... else是表达式,而for后面的if是过滤条件,不能带else
      >>> [x if x % 2 == 0 else -x for x in range(1, 11)]
      [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]
      
  4. 生成器
    若列表元素可以按照某种算法推算出来,可在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间
    • 创建generator
      >>> g = (x * x for x in range(10))
      >>> g
      <generator object <genexpr> at 0x1022ef630>
      >>> next(g)
      0
      >>> next(g)
      1
      ...
      
  • 通过循环遍历生成器
    python >>> g = (x * x for x in range(10)) >>> for n in g: ... print(n) ...
  • 函数式创建generator
    def fib(max):
        n, a, b = 0, 0, 1
        while n < max:
            yield b
            a, b = b, a + b
            n = n + 1
        return 'done'
    >>> f = fib(6)
    >>> f
    <generator object fib at 0x104feaaa0>
    
    变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

函数式编程

  1. 高阶函数
    • 变量可以指向函数,即函数本身可以赋值给变量
    • 接受另一个函数作为参数的函数称为高阶函数
      def add(x, y, f):
          return f(x) + f(y)
      
    • map()函数和reduce()函数
      • map()函数接受两个参数,一个是函数,另一个是Iterable, map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回:
        >>> def f(x):
        ...     return x * x
        ...
        >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
        >>> list(r)
        [1, 4, 9, 16, 25, 36, 49, 64, 81]
        
      • reduce()函数把一个函数作用在一个序列上,且这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算,效果为:
        reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
        
    • filter()函数
      filter()函数用于过滤序列,接收一个函数和一个序列,并将传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素,例如:
      def is_odd(n):
          return n % 2 == 1
      
      list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
      # 结果: [1, 5, 9, 15]
      
    • sorted()函数
      • 直接对list进行排序:
        >>> sorted([36, 5, -12, 9, -21])
        [-21, -12, 5, 9, 36]
        
      • 通过key函数实现自定义排序:
        >>> sorted([36, 5, -12, 9, -21], key=abs)
        [5, 9, -12, -21, 36]
        
      • 若要反向排序,可传入第三个参数reverse=True
  2. 匿名函数
    • 关键字lambda表示匿名函数,冒号前面的x表示函数参数
    • 只能有一个表达式,返回值即为表达式的结果
    • 匿名函数也是一个函数对象,可赋值给一个变量,再利用变量来调用该函数
  3. 装饰器
    • 在代码运行期间动态增加功能的方式称为"装饰器"(Decorator)
    • 示例:
      # 定义decorator
      def log(func):
          def wrapper(*args, **kw):
              print('call %s():' % func.__name__)
              return func(*args, **kw)
          return wrapper
      # 通过@,将decorator置于函数定义处
      @log # 相当于执行了now = log(now)
      def now():
          print('2015-3-25')
      
      >>> now()
      call now():
      2015-3-25
      
  4. 偏函数
    • 根据需要将一个函数的某些参数固定(即设置默认值),返回新的函数
    • 示例:
      >>> import functools
      >>> int2 = functools.partial(int, base=2)
      >>> int2('1000000')
      64
      # int2()函数base默认值为10
      

模块

  1. 使用模块
    • Python模块的标准文件模板
      #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      
      ' a test module ' # 表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释
      
      __author__ = 'Michael Liao'
      ...
      
    • 有关if __name__=='__main__:
      当我们在命令行运行模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该模块时,if判断将失败
    • 作用域
      • 正常的函数和变量名是公开的(public),可以被直接引用
      • 类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途
      • 类似_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用

面向对象编程

  1. 类和实例
    • 通过class关键字定义类
      class Student(object): # object表示该类从object类继承而来,默认为object,支持多继承
          pass
      >>> bart = Student()
      >>> bart.name = 'Bart Simpson' # 可自由地给一个实例绑定属性
      >>> bart.name
      'Bart Simpson'
      
    • "构造函数"
      class Student(object):
      
          def __init__(self, name, score):
              self.name = name
              self.score = score
      # 这样再创建实例时就不能传入空的参数
      
  2. 访问限制
    • 为防止外部代码自由修改内部属性,可把属性改为私有变量:
      class Student(object):
      
          def __init__(self, name, score):
              self.__name = name
              self.__score = score
      
          def print_score(self):
              print('%s: %s' % (self.__name, self.__score))
      
  3. 继承和多态
    • 当子类和父类都存在相同的方法时,子类的方法覆盖了父类的方法
    • 静态语言 vs 动态语言
      • 对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用其中的run()方法
      • 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了
  4. 获取对象信息
    • type()函数
      判断对象类型
    • isinstance()函数
      判断一个对象是否是该类型本身或位于该类型的父继承链上
    • dir()函数
      获取一个对象的所有属性和方法,返回一个list
  5. 实例属性和类属性
    • 相同的实例属性将屏蔽掉类属性

面向对象高级编程

  1. 使用__slots__
    • 给实例绑定方法:
      >>> def set_age(self, age): # 定义一个函数作为实例方法
      ...     self.age = age
      ...
      >>> from types import MethodType
      >>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
      
    • 给类绑定方法:
      >>> def set_score(self, score):
      ...     self.score = score
      ...
      >>> Student.set_score = set_score
      
    • 限制实例的属性:
      class Student(object):
          __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
      # 此时只能对创建的实例绑定name, age属性,绑定其他属性将报错
      
      注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用
  2. 使用@property
    • Python内置的@property装饰器就是负责把一个方法变成属性调用的
      class Student(object):
          @property
          def score(self):
              return self._score
      
          @score.setter
          def score(self, value):
              if not isinstance(value, int):
                  raise ValueError('score must be an integer!')
              if value < 0 or value > 100:
                  raise ValueError('score must between 0 ~ 100!')
              self._score = value
      
      >>> s = Student()
      >>> s.score = 60 # OK,实际转化为s.set_score(60)
      >>> s.score # OK,实际转化为s.get_score()
      60
      
      把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
  3. 使用枚举类
    from enum import Enum
    
     Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
    
     for name, member in Month.__members__.items():
     print(name, '=>', member, ',', member.value)  # valule属性默认从1开始计数
    
  4. 使用元类
    • 利用type()动态创建类
      • type()函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object)...的定义:
        >>> def fn(self, name='world'): # 先定义函数
        ...     print('Hello, %s.' % name)
        ...
        >>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
        >>> h = Hello()
        >>> h.hello()
        Hello, world.
        
      • 要创建一个class对象,type()函数依次传入3个参数:
        • class的名称
        • 继承的父类集合,如果只有一个父类,注意tuple的单元素写法
        • class的方法名称与函数绑定

IO编程

  1. 文件读写
    • 读文件
      with open('/path/to/file', 'r') as f:
          print(f.read())
      
      # 常用函数
      read() # 一次性读取文件的全部内容
      read(size) # 每次最多读取size个字节的内容
      readline() # 每次最多读取size个字节的内容
      readlines() # 一次读取所有内容并按行返回list
      
    • 写文件
      with open('/Users/michael/test.txt', 'w') as f:
          f.write('Hello, world!')
      
  2. 操作文件和目录
    • 创建一个目录:os.mkdir('filepath')
    • 删除一个目录:os.rmdir('filepath')
    • 合并两个路径:os.path.join('path1', 'path2')
    • 拆分路径(后一部分为最后级别的目录或文件名):os.path.split()

正则表达式

  1. 直接给出字符就是精确匹配,\d可以匹配一个数字,\w可以匹配一个字母或数字,\s可以匹配一个空格或Tab等空白符
  2. .可以匹配任意字符
  3. *表示任意个字符,+表示至少一个字符,表示0个或1个字符,{n}表示n个字符,{n, m}表示n-m个字符
  4. 特殊字符需要用\转义
  5. 精确匹配
    • [0-9a-zA-Z\_]可以匹配一个数字、字母或者下划线
    • [0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或者下划线组成的字符串
    • [a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串
    • [a-zA-Z\_][0-9a-zA-Z\_]{0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)
    • A|B可以匹配A或B
    • ^表示行的开头,^\d表示必须以数字开头
    • $表示行的结束,\d$表示必须以数字结束