[关闭]
@WillireamAngel 2017-08-26T07:06:24.000000Z 字数 23402 阅读 2388

Python基础教程

python


第一个Python程序

  1. print()可以实现数字和字符串打印,之间插入,可以实现字符串间空格;
  2. 输入设置变量:
  1. >>> name = input()
  2. Michael
  3. >>> name
  4. 'Michael'
  1. name=input('please enter your name:')
  2. print('hello', name)
  3. please enter your name:michael
  4. hello michael

变量不仅可以为整数或浮点数,还可以是字符串。通过使用Input+提示,可以实现更加优化的界面。

Python基础

  1. Python使用缩进来组织代码块,需要使用4个空格的缩进。#是注释,当语句以冒号:结尾时,缩进的语句视为代码块。
  2. 数据类型:
    1.十六进制整数:0x前缀+ 0-9 + a-f
    2.浮点数:对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代(1.23×10^9=1.23e^9
    3.字符串:"" ''
    转义字符\用于标示既包含'又包含"的情况,转义字符加在'"上:I\'m
转义字符 描述
(在行尾时) 续行符
\ 反斜杠符号
\' 单引号
\" 双引号
\a 响铃
\b 退格(Backspace)
\e 转义
\000
\n 换行
\v 纵向制表符
\t 横向制表符
\r 回车
\f 换页
\b 退格(Backspace)
\e 转义
\000
\oyy 八进制数yy代表的字符,例如:\o12代表换行
\xyy 十进制数yy代表的字符,例如:\x0a代表换行
\other 其它的字符以普通格式输出

利用r''表示''不转义,Python允许用'''...'''的格式表示多行内容。
4.布尔值:True or False两种值,and&or&not运算,布尔值运算常用在条件判断中。
5.空值:None一个特殊的空值,与零无关。
6.变量:英文大小写+数字+_,Python属于变量不固定类型语言(动态语言)
7.常量:全部大写的变量表示:PI(π)(暂未实现π的书写)
Python除法:/浮点数除法,//地板除保留整数
3. 字符串和编码
1.ASCII编码;
2.GB2312编码;
3.Unicode编码;
4.UTF-8编码(可变长度);
在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
文件读取与保存:

记事本编码转换

网页Unicode转换:

网页Unicode转换

5.Python字符串:Python3.x以Unicode编码
(1)ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符。
(2)Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes
(3)Python中的bytes类型用b''或者b""表示。
(4)以Unicode表示的str通过encode(编码类型)方法可以编码为指定的bytes

  1. >>> 'ABC' .encode('utf-8')
  2. b'ABC'

(5)纯英文的str可以用ASCII编码为bytes,内容是一样的,含有中文的str可以用UTF-8编码为bytes。
(6)要把bytes变为str,就需要用decode()

  1. >>> b'ABC' .decode('ascii')
  2. 'ABC'

(7)len()函数计算的是str的字符数,计算bytes的字节数。

  1. >>> len('中文')
  2. 2
  3. >>> len(b'\xe4\xb8\xad\xe6\x96\x87')
  4. 6

6.格式化:利用%实现

%d 整数
%f 浮点数
%s 字符串
%x 十六进制整数
  1. >>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
  2. 'Hi, Michael, you have $1000000.'

其中,格式化整数和浮点数还可以指定是否补0和整数与小数的位数。
当不确定使用哪个转义符时,%s永远起作用,它会把任何数据类型转换为字符串。

  1. >>> 'Age: %s. Gender: %s' % (25, True)
  2. 'Age: 25. Gender: True'

当存在想表示%为一个普通字符时,利用%%

  1. >>> 'growth rate: %d %%' %7
  2. 'growth rate: 7 %'

7.注释Python程序和编码

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-

作业:
小明的成绩从去年的72分提升到了今年的85分,请计算小明成绩提升的百分点,并用字符串格式化显示出'xx.x%',只保留小数点后1位

  1. # -*-coding: utf-8 -*-
  2. s1= 72
  3. s2= 85
  4. r=(s2-s1)/s1*100
  5. print('%.1f%%' %r)
  1. 使用list和tuple
    1.list:有序集合,可以任意删减修改其中的元素(索引从0开始)或者索引从最后一个-1开始
    .apend追加元素
    .insert(i, 元素)指定位置插入元素
    .pop()删除list末尾的元素
    .pop(i)删除指定索引位置元素
    赋值索引元素可直接替换
    多个list嵌套时,可使用p[1]或者s[2][1]格式,实现多维数组索引
  1. classmates=['michael','bob','ova']
  2. classmates.pop(1)
  3. print(classmates[0])
  4. print(classmates[-2])
  5. print(classmates)
  6. L=[]
  7. print(len(L))

运行结果:

  1. michael
  2. michael
  3. ['michael', 'ova']
  4. 0

2.tuple(元组):初始化列表指向不可变(没有append和insert等方法),但嵌套列表可变,其它呈现方式与list相同。
定义若干元素tuple:

  1. >>> t=(1.2)
  2. >>> t
  3. 1.2

定义空元素tuple:

  1. >>> t=()
  2. >>> t
  3. ()

定义一个元素tuple(单独元素做运算优先,加,表示单元素)

  1. >>> t=(1)
  2. >>> t
  3. 1
  1. >>> t=(1,)
  2. >>> t
  3. (1,)

调整嵌套list

  1. >>> t = ('a', 'b', ['A', 'B'])
  2. >>> t[2][0] = 'X'
  3. >>> t[2][1] = 'Y'
  4. >>> t
  5. ('a', 'b', ['X', 'Y'])
  1. 条件判断:
    1.if、else、elif(else if)
    判断条件后添加有:,执行从前到后,当判断为True后就停止运行
  1. if <条件判断1>:
  2. <执行1>
  3. elif <条件判断2>:
  4. <执行2>
  5. elif <条件判断3>:
  6. <执行3>
  7. else:
  8. <执行4>

判断条件的简写:

  1. if x:
  2. print('True')

只要x是非零数值、非空字符串、非空list等,就判断为True,否则为False。

2.input
使用input来读取用户输入,可以自己输入,但是input()返回的数据类型是str,要与所比较的类型匹配,需要一些函数来完成。

  1. s = input('birth:')
  2. age = int(s)
  3. if age >= 6:
  4. print('Teenager')
  5. else:
  6. print('Kid')
  1. 循环
    1.for...in...(list)
    此循环是将每个元素带入变量x,然后执行缩进块的语句。
    range(n)函数是生成从0到n-1的序列
    range(n1,n2,d):生成从n1到n2间隔为d的序列
    2.while循环:只要条件满足,就不断循环,条件不满足就退出。
    习题:
    请利用循环依次对list中的每个名字打印出Hello, xxx!
  1. # -*- coding: utf-8 -*-
  2. L = ['Bart', 'Lisa', 'Adam']
  3. for n in L:
  4. print('Hello, %s!' %(n))
  1. dict和set
    1.dict=dictionary,实现key-value查找(键值查找),一个key对应一个value。
    避免key不存在:in判断,输出True/False;get方法,如果key不存在,可以返回None,或者自己指定的value.
    删除key:pop(key)
    dict&list:
    dict查找和插入的速度极快,不会随着key的增加而变慢;需要占用大量的内存,内存浪费多。
    list查找和插入的时间随着元素的增加而增加;占用空间小,浪费内存很少。
    为了实现key计算的Hash算法,key不能变,字符串、整数等可以实现,list无法实现。
    2.set算法:不储存value的key值集合(不能储存list),元素不重复,可以使用add``remove等算法添加元素,多个set还可实现集合运算(&:交集,|:并集)
    python的set集合运算

    3.对于不变对象来说,调用对象自身的任意方法,也不会改变该对象自身的内容。但是,这些方法会创建新的对象并返回,就保证了不可变对象本身永远是不可变的。
  1. >>> a = 'abc'
  2. >>> a.replace('a', 'A')
  3. 'Abc'
  4. >>> a
  5. 'abc'

函数

  1. 计算机代码抽象函数;
  2. 调用函数
    Python内置函数:http://docs.python.org/3/library/functions.html#abs
    1.Python内置的常用函数包括数据类型转换函数,函数名对象可赋值。
    2.函数名是指向一个函数对象的引用,完全可以把函数名赋给变量。
  3. 定义函数
    1.定义函数用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
    没有return语句,返回为None。return None可以简写为return。
    2.定义空函数用pass语句
  1. def nop():
  2. pass

pass用作占位符,暂不运行函数。
3.TypeErrorPython解释器,数据类型检查用isinstance()实现

  1. def my_abs(x):
  2. if not isinstance(x, (int, float)):
  3. raise TypeError('bad operand type')
  4. if x >= 0:
  5. return x
  6. else:
  7. return -x
  1. >>> my_abs('A')
  2. Traceback (most recent call last):
  3. File "<pyshell#17>", line 1, in <module>
  4. my_abs('A')
  5. File "<pyshell#16>", line 3, in my_abs
  6. raise TypeError('bad operand type')
  7. TypeError: bad operand type

显示了错误类型
4.import math语句表示导入math包,并允许后续代码引用math包里的sin、cos等函数。
函数可以同时返回多个值,但其实就是一个tuple(语法上,返回tuple可以省略括号)。

  1. import math
  2. def move(x, y, step, angle=0):
  3. nx = x + step * math.cos(angle)
  4. ny = y - step * math.sin(angle)
  5. return nx, ny
  1. 函数的参数
    1.位置参数:定义一个函数,调用函数时,传入的两个值按照位置顺序依次赋给参数。
    定义x^n的函数:
  1. def power(x, n):
  2. s = 1
  3. while n > 0:
  4. n = n - 1
  5. s = s * x
  6. return s
  1. def power(x, n):
  2. s = 1
  3. while n > 0:
  4. n = n - 1
  5. s = s * x
  6. return s

第二个条件循环未闭合,return无条件退出函数,所以第一个函数起作用而第二个函数没有作用。
2.默认参数
默认参数可以简化函数的调用。
设置默认参数时,必选参数在前,默认参数在后;变化大的参数放在前面,变化小的参数放后面。
使用默认参数时,当传入参数设为定值时,传入值与设定值相同时,可以直接省略;当传入值与设定值不同时,可直接补充。

  1. def vab(name, gender, age=6, city = 'beijing'):
  2. print('name:', name)
  3. print('gender:', gender)
  4. print('age:', age)
  5. print('city:', city)
  6. print(vab('Tom','A'))
  7. print(vab('Sarah','F',7))
  8. print(vab('Mary','B',city ='Tianjing'))

3.可变参数:
定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,函数代码完全不变。调用该函数时,可以传入任意个参数(包括0个参数)
4.关键字参数:
**kw是关键字参数,kw接收的是一个dict。
5.命名关键字参数:
命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。如果含有可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符。
6.调用函数时传入可变参数和关键字参数的语法:
可变参数既可以直接传入:func(1, 2,3),又可以先组装list或tuple,再通过*args传入:func(*(1, 2, 3))
关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{'a': 1, 'b': 2})
使用*args**kw是Python的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。
命名的关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。
定义命名的关键字参数在没有可变参数的情况下不要忘了写分隔符*,否则定义的将是位置参数。
6.参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

函数参数

order 表示 含义
位置参数 x 与位置有关的参数,从前向后调用
默认参数 c=0 设定默认值,可改变默认值
可变参数 *args 传入多个参数,接收一个tuple
命名关键字参数 ,*,(含有可变参数可忽略) 限制传入关键字参数的名称
关键字参数 **kw 传入多个参数,接收一个dict

5. 递归函数:函数内部调用自身函数

  1. def fact(n):
  2. if n==1:
  3. return 1
  4. return n * fact(n - 1)

1.使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。函数调用通过栈(stack)实现,栈的大小是有限的,所以需要防止栈溢出。
2.针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。
3.Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。

  1. def move(n, A, B, C):
  2. if(n == 1):
  3. print(A,"->",C)
  4. return
  5. move(n-1, A, C, B)
  6. move(1, A, B, C)
  7. move(n-1, B, A, C)

高级特性

  1. 切片
    实现:利用特定标识,索引取用元素,效果类似于循环。
    L[n1:n2:d]:L可为list、tuple、字符串等
    当n1=0时,可省略n1;当选取全部元素,可省略n1、n2;当d=1时,可省略:d;实际上可以实现负值倒数取值(最后一个值为-1)
  1. L = list(range(100))
  2. a = L[:10:2]
  3. print(a)

运行结果:

  1. [0, 2, 4, 6, 8]
  1. 迭代
    for循环的遍历list or tuple实现,称为迭代。
    1.for ** in L
    print(**)
    默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()
    L可为list、tuple、字符串等可迭代对象可使用key-value实现:
  1. >>> d = {'a': 1, 'b': 2, 'c': 3}
  2. >>> for key in d:
  3. print(key)
  4. a
  5. c
  6. b

2.迭代对象判断:collections模块的Iterable类型判断。具体实现如下:

  1. >>> from collections import Iterable #引入模块类型
  2. >>> isinstance([1,2,5],Iterable) #isinstance(object,type),对象是否为类型,返回布尔值
  3. True #返回结果

3.将list变成索引-元素对:enumerate函数。
for ** in emumerate(L,n):L为列,n为初始序列值,默认为0,省略,n
代码示例:

  1. L = [(1, 1), (2, 4), (3, 9)]
  2. for i,value in enumerate(L,2):
  3. print(i,value)
  4. for item in enumerate(L,2):
  5. print(item)

运行结果:

  1. 2 (1, 1)
  2. 3 (2, 4)
  3. 4 (3, 9)
  4. (2, (1, 1))
  5. (3, (2, 4))
  6. (4, (3, 9))
  1. 列表生成式(List Comprehensions)
    列表生成式简化循环:
  1. >>> [x * x for x in range(1, 11)]
  2. [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

加入判断if

  1. >>> [x * x for x in range(1, 11) if x % 2 == 0] # %表示余
  2. [4, 16, 36, 64, 100]

if实现:

  1. L = ['Hello', 'World', 18, 'Apple', None]
  2. L1 = [s.lower() for s in L if isinstance(s,str)]
  3. print(L1) #if判断后面自动设置为布尔值为true的选项

加入多重循环

  1. >>> [m + n for m in 'ABC' for n in 'XYZ'] #+的含义是组合
  2. ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

列出目录名的列表实现

  1. >>> import os #导入模块
  2. >>> [d for d in os.listdir('.')] #os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表,这个列表以字母顺序,不包括 '.' 和'..' 文件(即使有)。
  3. ['DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'NEWS.txt', 'python.exe', 'python.pdb', 'python3.dll', 'python36.dll', 'python36.pdb', 'python36_d.dll', 'python36_d.pdb', 'python3_d.dll', 'pythonw.exe', 'pythonw.pdb', 'pythonw_d.exe', 'pythonw_d.pdb', 'python_d.exe', 'python_d.pdb', 'Scripts', 'tcl', 'Tools', 'vcruntime140.dll']

字符串变成小写:

  1. >>> L = ['HELLO']
  2. >>> [s.lower() for s in L]
  3. ['hello']
  1. 生成器(generator):Python中一边循环一边计算的机制。
    创建generator方法:
    1.修改list中[]为(),打印的时候利用next()函数实现调用函数,直到出现StopIteration,可使用for循环实现
    菲波那切数列:
  1. def fib(max):
  2. n, a, b = 0, 0, 1
  3. while n < max:
  4. print(b)
  5. a, b = b, a + b
  6. n = n + 1
  7. return 'done'

2.将print改成yield关键字:yield功能类似于return,返回生成器。变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
捕获返回值:

  1. g = fib(6)
  2. >>> while True:
  3. ... try:
  4. ... x = next(g)
  5. ... print('g:', x)
  6. ... except StopIteration as e:
  7. ... print('Generator return value:', e.value)
  8. ... break
  9. #try...except...可以跳过异常继续执行程序
  10. #break 跳出循环
  1. try: # 可能会出现异常的一段代码
  2. command_1 # 如果command_1出现异常,则不执行command_1以及之后的语句
  3. command_2 # command_1如果正常,则会执行
  4. except: # try中任意一行语句出现异常,直接跳转至except,程序继续运行
  5. command_3
  6. command_4

杨辉三角实践:

  1. # -*- coding: utf-8 -*-
  2. def triangles(): #命名函数
  3. L = [1] #引入首个list
  4. while True: #无报错执行
  5. yield L #创建generator
  6. L = [1]+[L[x]+L[x+1] for x in range(len(L)-1)]+[1] #generator执行完成(第一次执行)后,进行下一步执行,定义新的L,并且引用原来的L list数值,由于原来的引用使用x+1实现,故需要长度-1
  7. n = 0
  8. for t in triangles():
  9. print(t)
  10. n = n + 1 #每次print,n=n+1
  11. if n == 10: #比较对象是否相等(判断)
  12. break
  1. 迭代器
    1.凡是可作用于for循环的对象都是Iterable类型;
    2.凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
    3.集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象;
    4.Python的for循环本质上就是通过不断调用next()函数实现。
  1. >>> from collections import Iterator
  2. >>> isinstance((x for x in range(10)), Iterator)
  3. True

函数式编程

函数式编程,可归结为面向对象的编程,思想接近于数学计算,允许把函数本身作为参数传入另一个函数,还允许返回一个函数。
1. 高阶函数
把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。
变量可以指向函数,函数名也是变量,常用的函数在import builtins模块中,常用的函数引用可以通过以下的方式实现:

  1. import builtins; builtins.abs = 10

1.map/reduce
map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
map(function,[list])
reduce把一个函数作用在一个序列上,结果继续和序列的下一个元素做累积计算:

  1. reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

首字母大写的实现:
1.直接运用函数:

  1. def normalize(name):
  2. return name.capitalize()
  3. L1=['adam','LISA','barT']
  4. L2=list(map(normalize,L1))
  5. print(L2)

2.利用普通函数lowerupper实现:

  1. def normalize(name):
  2. return name[:1].upper() + name[1:].lower()
  3. L1 = ['adam', 'LISA', 'barT']
  4. L2 = list(map(normalize, L1))
  5. print(L2)

if __name__ == '__main__'的用法:
当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。

实现字符串转换为浮点数:

  1. from functools import reduce
  2. def str2float(s):
  3. def fn(x, y):
  4. return x * 10 + y
  5. n = s.index('.') #调用index函数,实现浮点数查找
  6. s1 = list(map(int, [x for x in s[:n]]))
  7. s2 = list(map(int, [x for x in s[n+1:]]))
  8. return reduce(fn, s1) + reduce(fn, s2) /10 **len(s2)
  9. print('\'123.4567\'=', str2float('123.4567'))

2.filter
filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

寻找素数:

  1. def _odd_iter():
  2. n = 1
  3. while True:
  4. n = n + 2
  5. yield n
  6. def _not_divisible(n):
  7. return lambda x: x % n > 0 #lambda是一个参数函数实现的函数,定义一个匿名函数来实现,类似于`def...return...`
  8. def primes():
  9. yield 2
  10. it = _odd_iter() # 初始序列
  11. while True:
  12. n = next(it) # 返回序列的第一个数
  13. yield n
  14. it = filter(_not_divisible(n), it) # 构造新序列
  15. # 打印1000以内的素数:
  16. for n in primes():
  17. if n < 1000:
  18. print(n)
  19. else:
  20. break

寻找回数:

  1. # -*- coding: utf-8 -*-
  2. def is_palindrome(n):
  3. s = str(n)
  4. for i in range(len(s)):
  5. if s[i] ==s[len(s)-1-i]:
  6. return True
  7. else:
  8. return False
  9. output = filter(is_palindrome, range(1, 1000))
  10. print(list(output))

3.sorted
sorted可对list进行排序,也可引入key=function进行排序

  1. >>> sorted([36, 5, -12, 9, -21], key=abs)
  2. [5, 9, -12, -21, 36]

反向排序,引入reverse=True

  1. >>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
  2. ['Zoo', 'Credit', 'bob', 'about']

调用组内元素:

  1. # -*- coding: utf-8 -*-
  2. def by_name(t):
  3. return t[0]
  4. L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
  5. L2 = sorted(L, key=by_name)
  6. print(L2)
  1. 返回函数
    函数作为返回值,每次调用都会返回一个新的函数。
    当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,即所谓的闭包。
    一个函数可以返回一个计算结果,也可以返回一个函数。
    返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。
  2. 匿名函数
    关键字lambda表示匿名函数,匿名函数避免了函数名冲突。
    匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数,也可以返回一个匿名函数。
  3. 装饰器
    在代码运行期间动态增加功能的方式。
    wrapper()函数的参数定义是(*args, **kw),,因此,wrapper()函数可以接受任意参数的调用。
    函数也是对象,它有__name__等属性。
    利用python的@语法,将@放在函数定义之前,相当于执行了函数。
    Python除了能支持OOP的decorator外,直接从语法层次支持decorator。Python的decorator可以用函数实现,也可以用类实现。
  4. 偏函数
    当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。
    int(x, base=n):将字符串转换为n进制数。

模块

一个.py文件就称之为一个模块(Module)。
按目录来组织模块的方法,称为包(Package)。
一个包的度量在于存在一个可有无内容的__init__.py,该文件本身就是一个模块,而它的模块名就是包名。
创建模块时,不要与python自带模块冲突。
1. 使用模块
sys.argv:一个元组,项为用户输入的参数,此参数从程序外部输入的,而非代码本身。
作用域:
正常的函数和变量名是公开的(public);
类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途;
类似_xxx__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,不是不能应用,只是编程习惯上不引用。
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。
2. 安装第三方模块

  1. pip install labname

添加自身搜索路径:
1.直接修改路径,设置添加路径,在运行时修改,运行结束后失效:

  1. >>> import sys
  2. >>> sys.path.append('/Users/michael/my_py_scripts')

2.使用环境变量方法添加相关路径,类似于添加path。

面向对象编程

  1. 简介
    面向对象
    将程序视作一组对象集合,程序设计是一系列消息在对象中传播,难点在于抽象出类(Class),利用类建立实例(Instance)。
    面向对象的三大特点:数据封装、继承和多态。
    面向过程
    程序视作一系列命令集合,即一组函数的顺序执行。
  2. 类和实例
    类是抽象的模板,实例是根据类创建的一个具体对象,各个实例拥有的数据都相互独立,互不影响。Python允许对实例变量绑定任何数据,同一个类的实例的变量名称可能不同。
    在Python中,定义类是通过class关键字:
  1. class Student(object):
  2. pass
![继承树](https://www.liaoxuefeng.com/files/attachments/001390363904103deecc02634aa4406a41692237be32861000/0)
  1. >>> type(abs)
  2. <class 'builtin_function_or_method'>
  1. >>> type('abs') ==str
  2. True
  1. >>> isinstance(h, Dog)
  2. True
  1. >>> isinstance((1, 2, 3), (list, tuple, str))
  2. True
  1. >>> import types
  2. >>> dir(types)
  3. ['AsyncGeneratorType', 'BuiltinFunctionType', 'BuiltinMethodType', 'CodeType', 'CoroutineType', 'DynamicClassAttribute', 'FrameType', 'FunctionType', 'GeneratorType', 'GetSetDescriptorType', 'LambdaType', 'MappingProxyType', 'MemberDescriptorType', 'MethodType', 'ModuleType', 'SimpleNamespace', 'TracebackType', '_GeneratorWrapper', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_ag', '_calculate_meta', '_collections_abc', '_functools', 'coroutine', 'new_class', 'prepare_class']
  1. >>> hasattr(types, 'y')
  2. False
  3. >>> setattr(types, 'y', 9)
  4. >>> getattr(types, 'y')
  5. 9
  6. >>> types.y
  7. 9

面向对象高级编程

  1. 使用__slots__
    1.class添加属性
    对于一个类的所有实例来说,要想实现给一个实例绑定的方法对另一个实例起作用,可以用class给所有实例都绑定方法:
  1. >>> def set_score(self, score):
  2. self.score = score
  3. >>> Student.set_score = set_score

2.使用__slots__
利用__slots__可以对实例的属性进行限制,使它只具有我们设定的属性:

  1. >>> class Student(object):
  2. __slots__ = ('name', 'age')
  3. >>> s = Student()
  4. >>> s.name = 'Michael'
  5. >>> s.age = 25
  6. >>> s.score = 99
  7. Traceback (most recent call last):
  8. File "<pyshell#22>", line 1, in <module>
  9. s.score = 99
  10. AttributeError: 'Student' object has no attribute 'score'

使用__slots__时,需要特别注意,__slots__定义的属性仅对当前类实例有效,继承的子类是不起作用的,除非在子类也定义__slots__,子类允许定义的属性就是自身的和父类的。

  1. >>> class Student(object):
  2. __slots__ = ('name', 'age')
  3. >>> class Graduate(Student):
  4. __slots__ = ('name', 'dream')
  5. >>> g = Graduate()
  6. >>> g.age = 96
  7. >>> g.name = 'Will'
  8. >>> g.dream = 'Forever'
  9. >>> g.end = 1
  10. Traceback (most recent call last):
  11. File "<pyshell#38>", line 1, in <module>
  12. g.end = 1
  13. AttributeError: 'Graduate' object has no attribute 'end'
  1. 使用@property
    @property的主要作用是广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
    @property装饰器负责把一个方法变成属性调用。
  1. # _*_ coding: utf-8 _*_
  2. class Screen(object):
  3. @property
  4. def width(self):
  5. return self._width
  6. @property
  7. def height(self):
  8. return self._height
  9. @property
  10. def resolution(self):
  11. return self.width * self.height
  12. @width.setter
  13. def width(self,value):
  14. if not isinstance(value, int):
  15. raise ValueErrror('width must be an interger!')
  16. if value < 0:
  17. raise ValueError('width must > 0!')
  18. self._width = value
  19. @height.setter
  20. def height(self,value):
  21. if not isinstance(value, int):
  22. raise ValueErrror('height must be an interger!')
  23. if value < 0:
  24. raise ValueError('height must > 0!')
  25. self._height = value
  26. s = Screen()
  27. s.width = 1024
  28. s.height = 768
  29. print(s.resolution)
  30. assert s.resolution == 786432, '1024 * 768 = %d ?' % s.resolution
  1. 多重继承
    多重继承:
    先定义根类,再定义父类,再定义子类,再设计功能,定义多重实例继承。
  1. class College(object):
  2. pass
  3. class Student(College):
  4. pass
  5. class Teacher(College):
  6. pass
  7. class Study(object):
  8. def study(self):
  9. print('student..')
  10. class Teach(object):
  11. def teach(self):
  12. print("teach...")
  13. class Man(Teacher, Teach):
  14. pass

由于Python允许使用多重继承,因此,MixIn就是一种常见的设计。
只允许单一继承的语言(如Java)不能使用MixIn的设计。
4. 定制类
try...except...else&if...raise ...else&try...finally区别:
try...except...else:当没有异常发生时,else后的语句将被执行;如果在try部份引发了名为'**'的异常,则执行except后面的代码;
if...raise ...else:如果if判断错误,则会引发raise后面异常;
try...finally:无论是否发生错误,都要执行finally后面的代码。

  1. 使用枚举类
    Enum实现为枚举类型定义一个class类型,每个常量都是class的一个唯一实例。
    @unique装饰器可以帮助我们检查保证没有重复值。
    其中的value属性则是自动赋给成员的int常量,默认从1开始计数。
  2. 使用元类
    type()函数可以查看一个类型或变量的类型,也可以创建新的类型;
    type传入的参数类型:
    type('Hello', (object,), dict(hello=fn))
    1.class的名称;
    2.继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
    3.class的方法名称与函数绑定。

metaclass:先定义metaclass,就可以创建类,最后创建实例。
__new__()方法接收到的参数依次是:
当前准备创建的类的对象;类的名字;类继承的父类集合;类的方法集合。

  1. __new__(cls, name, bases, attrs)

ORM框架:Object Relational Mapping(对象-关系映射)

错误、调试和测试

  1. 错误处理
    try...except...finally...
    调用堆栈、记录错误、抛出错误
  2. 调试
    print();
    断言(assert);
    logging:不会抛出错误,而且可以输出到文件;
    pdb:程序以单步方式运行,可以随时查看运行状态;
    pdb.set_trace():我们只需要import pdb,然后,在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点;
  3. 单元测试
    测试驱动开发:TDD:Test-Driven Development
    单元测试可以有效地测试某个程序模块的行为,是未来重构代码的信心保证。
    单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。
    单元测试代码要非常简单,如果测试代码太复杂,那么测试代码本身就可能有bug。
    单元测试通过了并不意味着程序就没有bug了,但是不通过程序肯定有bug。
    setUp与tearDown
  4. 文档测试
    re模块就带了很多示例代码
    doctest非常有用,不但可以用来测试,还可以直接作为示例代码。通过某些文档生成工具,就可以自动把包含doctest的注释提取出来。用户看文档的时候,同时也看到了doctest。

IO编程

同步IO&异步IO:使用异步IO的效率会高于同步IO;
stream:流
1. 文件读写
读文件:open(),使用close()关闭;
file-like Object:含有read()方法的对象,StringIO就是内存中创建的file-like Object,常用作临时缓冲。
二进制文件:rb模式打开:

  1. f = open('/Users/michael/gbk.txt', 'rb')

字符编码:非utf-8编码文本,传入encoding参数:

  1. f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')

写文件:调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件
使用with语句操作文件IO是个好习惯。
2. StringIO和BytesIO
StringIO:内存读写str,getvalue()方法用于获得写入后的str。
BytesIO:内存中操作bytes。
3. 操作文件和目录
Python的os模块封装了操作系统的目录和文件操作,要注意这些函数有的在os模块中,有的在os.path模块中。
os.name获取操作系统类型,posix说明系统是Linux、Unix或Mac OS X,nt,就是Windows系统。
环境变量:os.environ,获取环境变量:os.environ.get('key')
4. 序列化
Python语言特定的序列化模块是pickle,但如果要把序列化搞得更通用、更符合Web标准,就可以使用json模块。
json模块的dumps()loads()函数是定义得非常好的接口的典范。当我们使用时,只需要传入一个必须的参数。但是,当默认的序列化或反序列机制不满足我们的要求时,我们又可以传入更多的参数来定制序列化或反序列化的规则,既做到了接口简单易用,又做到了充分的扩展性和灵活性。

JSON类型 Python类型
{} dict
[] list
"string" str
1234.56 int或float
true/false True/False
null None

进程和线程

对于操作系统来说,一个任务就是一个进程(Process)。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
多任务的实现有3种方式:
- 多进程模式;
- 多线程模式;
- 多进程+多线程模式。
线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。
多进程和多线程的程序涉及到同步、数据共享的问题,编写起来更复杂。
1. 多进程
在Unix/Linux下,可以使用fork()调用实现多进程。
要实现跨平台的多进程,可以使用multiprocessing模块。
要启动大量的子进程,可以利用进程池Pool的方式批量创建子进程。
subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出。
进程间通信是通过QueuePipes等实现的。
在Unix/Linux下,multiprocessing模块封装了fork()调用,使我们不需要关注fork()的细节。由于Windows没有fork调用,因此,multiprocessing需要“模拟”出fork的效果,父进程所有Python对象都必须通过pickle序列化再传到子进程去,所有,如果multiprocessing在Windows下调用失败了,要先考虑是不是pickle失败了。
2. 多线程
Python的标准库提供了两个模块:_threadthreading_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。
启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。
由于锁只有一个,无论多少线程,同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突。
多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离,同时,又要小心死锁的发生。
Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。多线程的并发在Python中就是一个美丽的梦。
3. ThreadLocal
一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题。
ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。
4. 进程 vs. 线程
要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常是一个Master,多个Worker。
如果用多进程实现Master-Worker,主进程就是Master,其他进程就是Worker。
如果用多线程实现Master-Worker,主线程就是Master,其他线程就是Worker。
多进程模式的最大优点是稳定性高,缺点是创建进程的代价大。
多线程的效率比多进程高,但多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。
线程切换,多任务一旦多到一个限度,就会消耗掉系统所有的资源,结果效率急剧下降,所有任务都做不好。
任务分为计算密集型和IO密集型:
计算密集型任务的特点是要进行大量的计算,消耗CPU资源,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。最好用C语言编写。
IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。
单线程的异步编程模型称为协程,有了协程的支持,就可以基于事件驱动编写高效的多任务程序。
5. 分布式进程
Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。



正则表达式

正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
在正则表达式中,如果直接给出字符,就是精确匹配。用\d可以匹配一个数字,\w可以匹配一个字母或数字,.可以匹配任意字符。
要匹配变长的字符,在正则表达式中,用*表示任意个字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n-m个字符。
对于一些特殊字符,需要使用转义符。
要做更精确地匹配,可以用[]表示范围。A|B可以匹配A或B。^表示行的开头,$表示行的结束。
re模块,包含所有正则表达式的功能。
切分字符串:如果用户输入了一组标签,需要用正则表达式来把不规范的输入转化成正确的数组:re.split
()表示的就是要提取的分组(Group),group(0)永远是原始字符串,group(1)group(2)……表示第1、2、……个子串。
正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符,采用加?方法就可以让匹配采用非贪婪匹配。

常用内建模块

  1. datetime
    1.获取当前日期
    datetime是模块,datetime模块还包含一个datetime类,通过from datetime import datetime导入的才是datetime这个类。
    如果仅导入import datetime,则必须引用全名datetime.datetime
    datetime.now()返回当前日期和时间,其类型是datetime
    2.获取指定日期和时间
    3.datetime转换为timestamp:1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数),当前时间就是相对于epoch time的秒数,称为timestampdatetime类型转换为timestamp只需要简单调用timestamp()方法。
    4.timestamp转换为datetime:fromtimestamp()
    5.str转换为datetime:datetime.strptime()
    6.datetime转换为str:strftime()
    7.datetime加减:加减可以直接用+-运算符,不过需要导入timedelta
    8.本地时间转换为UTC时间
    9.时区转换:利用带时区的datetime,通过astimezone()方法,可以转换到任意时区。
  2. collections
    collections模块提供了一些有用的集合类,可以根据需要选用。
    1.namedtuple:用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性来引用tuple的某个元素。
    2.deque:deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。
    3.defaultdict:使用dict时,如果希望key不存在时,返回一个默认值,就可以用defaultdict
    4.OrderedDict:对dict做迭代时,保证Key的顺序。
    OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key。
    5.Counter:计数器,用于统计字符出现的个数。
  3. base64
    Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。Base64是一种用64个字符来表示任意二进制数据的方法。
  4. struct
    struct模块来解决bytes和其他二进制数据类型的转换。pack函数把任意数据类型变成'bytes'。
    官网参考:https://docs.python.org/3/library/struct.html#format-characters
  5. hashlib
    Python的hashlib提供了常见的摘要算法,如MD5,SHA1等。摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。
    要注意摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
  6. itertools
    count()会创建一个无限的迭代器,ctrl+c退出;
    cycle()会把传入的一个序列无限重复下去;
    repeat()负责把一个元素无限重复下去,不过如果提供第二个参数就可以限定重复次数;
    takewhile()等函数根据条件判断来截取出一个有限的序列;
    chain()可以把一组迭代对象串联起来,形成一个更大的迭代器;
    groupby()把迭代器中相邻的重复元素挑出来放在一起;
    itertools模块提供的全部是处理迭代功能的函数,它们的返回值不是list,而是Iterator,只有用for循环迭代的时候才真正计算。
  7. contextlib
    @contextmanager:
    @closing:
  8. XML
  9. HTMLParser
    利用HTMLParser,可以把网页中的文本、图像等解析出来。
  10. urllib
    urllibrequest模块可以非常方便地抓取URL内容,也就是发送一个GET请求到指定的页面,然后返回HTTP的响应。
    通过一个Proxy去访问网站,我们需要利用ProxyHandler来处理。
    urllib提供的功能就是利用程序去执行各种HTTP请求。如果要模拟浏览器完成特定功能,需要把请求伪装成浏览器。伪装的方法是先监控浏览器发出的请求,再根据浏览器的请求头来伪装,User-Agent头就是用来标识浏览器的。

常用第三方模块

PIL:Python Imaging Library,是Python平台事实上的图像处理标准库了。PIL提供了操作图像的强大功能,可以通过简单的代码完成复杂的图像处理。

virtualenv

virtualenv为应用提供了隔离的Python运行环境,解决了不同应用间多版本的冲突问题。

图形界面

Python内置的Tkinter可以满足基本的GUI程序的要求,如果是非常复杂的GUI程序,建议用操作系统原生支持的语言和库来编写。
python支持的第三方图形库:Tk、wxWidgets、Qt、GTK。

网络编程

  1. TCP/IP简介
  2. TCP编程
    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
    用TCP协议进行Socket编程在Python中十分简单,对于客户端,要主动连接服务器的IP和指定端口,对于服务器,要首先监听指定端口,然后,对每一个新的连接,创建一个线程或进程来处理。通常,服务器程序会无限运行下去。
    同一个端口,被一个Socket绑定了以后,就不能被别的Socket绑定了。
  3. UDP编程
    UDP的使用与TCP类似,但是不需要建立连接。此外,服务器绑定UDP端口和TCP端口互不冲突,也就是说,UDP的9999端口与TCP的9999端口可以各自绑定。

电子邮件

一封电子邮件的旅程就是:

发件人 -> MUA -> MTA -> MTA -> 若干个MTA -> MDA <- MUA <- 收件人

  1. SMTP发送邮件
    Python对SMTP支持有smtplibemail两个模块,email负责构造邮件,smtplib负责发送邮件。
    构造一个邮件对象就是一个Message对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。

    Message
    +- MIMEBase
    +- MIMEMultipart
    +- MIMENonMultipart
    +- MIMEMessage
    +- MIMEText
    +- MIMEImage

  2. POP3收取邮件
    用Python的poplib模块收取邮件分两步:第一步是用POP3协议把邮件获取到本地,第二步是用email模块把原始邮件解析为Message对象,然后,用适当的形式把邮件内容展示给用户即可。

访问数据库

  1. 使用SQLite
    在Python中操作数据库时,要先导入数据库对应的驱动,然后,通过Connection对象和Cursor对象操作数据。
    要确保打开的Connection对象和Cursor对象都正确地被关闭,否则,资源就会泄露。
    try:...except:...finally:...用来确保出错的情况下也关闭掉Connection对象和Cursor对象。
  2. 使用MySQL
    执行INSERT等操作后要调用commit()提交事务;
    MySQL的SQL占位符是%s
  3. 使用SQLAlchemy
    ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。
    正确使用ORM的前提是了解关系数据库的原理。

Web开发

  1. HTTP协议简介
    HTML是一种用来定义网页的文本,会HTML,就可以编写网页;
    HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通信。
  2. HTML简介
  3. WSGI接口
    Web应用的本质就是:
    • 浏览器发送一个HTTP请求;
    • 服务器收到请求,生成一个HTML文档;
    • 服务器把HTML文档作为HTTP响应的Body发送给浏览器;
    • 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
      WSGI:Web Server Gateway Interface。
      无论多么复杂的Web应用程序,入口都是一个WSGI处理函数。HTTP请求的所有输入信息都可以通过environ获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。
      复杂的Web应用程序,光靠一个WSGI函数来处理还是太底层了,我们需要在WSGI之上再抽象出Web框架,进一步简化Web开发。
  4. 使用Web框架
    常见的Python Web框架还有:
    Flask;
    Django:全能型Web框架;
    web.py:一个小巧的Web框架;
    Bottle:和Flask类似的Web框架;
    Tornado:Facebook的开源异步Web框架。
    有了Web框架,我们在编写Web应用时,注意力就从WSGI处理函数转移到URL+对应的处理函数,这样,编写Web App就更加简单了。
    在编写URL处理函数时,除了配置URL外,从HTTP请求拿到用户数据也是非常重要的。Web框架都提供了自己的API来实现这些功能。Flask通过request.form['name']来获取表单的内容。
  5. 使用模板
    有了MVC,我们就分离了Python代码和HTML代码。HTML代码全部放到模板里,写起来更有效率。
    常见的模板还有:
    Jinja2;
    Mako:用<% ... %>和{xxx}的一个模板;
    Django:Django是一站式框架,内置一个用{% ... %}和{{ xxx }}的模板。

异步IO

  1. 协程
    协程,又称微线程,纤程。英文名Coroutine。
  2. asyncio
    asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
    asyncio提供了完善的异步IO支持;
    异步操作需要在coroutine中通过yield from完成;
    多个coroutine可以封装成一组Task然后并发执行。
  3. async/await
    @asyncio.coroutine替换为async;
    yield from替换为await。
  4. alohttp
    asyncio实现了TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注