【注】书籍作者:Mark Lutz (原书第五版)
# Python
Python 是一门通用型的编程语言,而它时常扮演着脚本语言的角色。一般来说,它可定义为一门面型对象的脚本语言,是一门融合了面向过程,函数式和面向对象编程方式的多目标语言。
Python的传统运行时执行模型是,输入的源代码转换为字节码,之后字节码在Python虚拟机中运行。代码自动被编译之后再被执行
Python中, 一个以扩展名.py
结尾的源代码文件都是一个模块。一个Python程序往往由多个模块文件构成,通过import
连接在一起。其中的一个文件被指定为主文件,或叫顶层文件,或脚本
--就是那个启动后能够运行整个程序的文件,至此之下,全部都是模块导入模块。
模块往往就是变量名的包,即众所周知的命名空间,而在那个包中的变量名称为属性。模块中的变量之间不会发生冲突
# Python 自测试办法
控制台启动Python交互式命令模式,在控制台中执行实验和测试代码
# 几个用法
- 打印输出:
print('Hello world!')
- 退出Python执行环境:
或exit()
- 注释: Python 采用
#
实现注释内容 - 导入模块:
import
, 它是一个语句,不需要括号,用法如:import math
- 导入模块中的属性:
from - import
。用法如:from myfile import title
- 重载模块:
reload()
他是一个函数, 用法如:reload(script.py)
。3.X移到imp标准库中
# Python 核心数据类型
Python具有一些内置的类型, 它们使程序更容易编写,比自己实现的数据结构效率更高一些,他们也可扩展,是在语言标准的一部分。常见的对象类型及可变性如下所示:
除此之外,还有 程序单元类型:函数、模型、类;Python实现相关类型: 已编译代码、调用栈跟踪。
# 数据类型详解及方法
Python的变量是动态语言,可以自动适应不同类型的对象。它允许对一个已经赋值为数字类型的变量重新赋值覆盖成一个字符串类型,如s = 20
,s = 'str'
。
1. 数字
- 支持一般的数学运算:(+)代表加法,(*)代表乘法,(**)代表幂
- 浮点数显示有
repr函数
和str形式
,repr函数的显示有时会比预期更加精确,这不是bug。另外,浮点数之所以称之为浮点数,是因为科学计数法法时小数点位置是可变的。如下
>>> 3.1415 * 2
6.2830000000000004
>>> print(3.1415 * 2)
6.283
- 支持导入常用的数学模块
import math
;import random
>>> import random
>>> random.random()
0.7082048489415987
>>> random.choice([1,2,3,4])
3
2. 字符串
(1)序列操作:除字符串外,列表和元组也同样有序列操作
- 获取字符串长度:
len(s)
- 根据索引下标获取元素。正向索引 :
s[0]
;反向索引:s[-1]
。反向索引的原理是s[-1]
其实等同于s[len(s)-1]
- 字符串中,方括号内可以是任意表达式,如:
s[10-2]
- 字符串分片,也称截取。规则:左闭右开:如
s[1:3]
获取第二个到第三个元素。分片规则默认左边界为0,右边界为分片序列的长度 - 字符串拼接:(+)表示拼接,(*)表示重复复制
- 不可变性: 字符串的不可变性比较难理解,指的是创建后不能在原位置修改,指的是字符串本身不能被修改,而不是字符串所对应的那个变量不能被修改,如下案例
>>> S = 'Spam'
>>> S
Spam # 已经获得变量 S的值为字符串 Spam
>>> S[0] = 'z'
...error text omitted...
TypeError: 'str' object doe not support item assignment
>>> S = 'z' + S[1:]
zspm # 先获取S切片,在利用字符串拼接生成新的字符串,并用该值覆盖原变量
【分析】 案例中试图通过S[0]
的重新赋值修改原字符串,执行时报错。但通过s[1:]
获取字符串切片后拼接字符串z
,再赋值给变量S
,则执行成功。这个案例充分表现了Python字符串不可变性的特征和工作范围。通俗的说,不可变性就是通过下标方式只能获取到字符串元素,而不能设置它,因为此时作用对象是字符串本身。但是允许我们对表示字符串的那个变量重新赋值,因为Python变量是动态语言,允许被重新赋值和覆盖。
- 字符串按单个字符转成列表:
list()
- 字符串根据特定字符分割成列表:
split()
。注意使用的区别
>>> str = 'Hi,zfs'
>>> list(str) # list()中参数是要操作的对象
['H','i','z','f','s']
>>> str.split(',') # split()主语是操作对象,参数是识别分割的字符
['Hi', 'zfs']
- 列表转字符串:
join()
,注意用法, 如使用杠拼接列表'-'.join(L)
- 字节编码:
decode()
,如:B.decode()
(2)特定类型操作;字符串独享
- 子字符串序列查找:
find()
。 返回一个传入子字符串的偏移量,没找到返回-1
- 子字符串全局搜索和替换:
replace()
,不修改原对象
>>> S = 'Spam'
>>> S.find('pa')
1
>>> S.replace('pa', 'ZFS')
'SZFSm'
- 大写格式化:
upper()
,如:S.upper()
- 小写格式化:
lowercase()
,如:S.lowercase()
- 是否是首字母大写:
isalpha()
, 如:'Span'.isapha()
,返回 true - 移除右侧不可视字符:
rstrip()
,如:'aa,bb,cc,dddd,dd\n' = rstrip()
, - 链式调用操作:
line.rstrip().split(',')
>>> line = 'aa,bb,c,dd\n'
>>> line = rstrip()
'aa,bb,c,dd'
>>> line.rstrip().split(',')
['aa', 'bb', 'c', 'dd']
- 高级替换操作
>>> '%s, eggs, add %s' % ('spam', 'SPAM') # %形式
'spam, eggs. and SPAM'
>>> '{0}, eggs, and {1}'.format('spam', 'SPAM') # format形式1
'spam, eggs, and SPAM'
>>> '{}, eggs, and {}'.format('spam', 'SPAM') # format形式2
'spam, eggs, and SPAM'
- 字符串格式化(用于数字形式):
>>> '{:,.2f}'.format(296999.3766)
'296,999.37'
>>> '%.2f | %+05d' % (3.14159, -42)
'3.14 | -0042'
- 单引号表示法
''
等同于 双引号表示法""
;另外,三引号'''
或"""
支持字符串换行书写 - 模式匹配: 需要导入
re
模块,调用re.match()
。超纲,读者可自行了解
3. 列表 -List
(1)序列操作:列表也是序列,各元素存在顺序关系
创建一个列表直接赋值即可,如L = [123, 'spam', 1.23]
- 获取长度;
len()
; 如:len(L)
- 列表切片:
L[start:end]
;如:L[:-1]
,注意当出现赋值时,Python将自动为其加上len(L)
值 - 列表拼接:使用加号,如:
L + ['abc', 12]
;运行结果[123, 'spam', 1.23, 'abc', 12]
- 列表重复:使用星号, 如:
L * 2
;运行结果[123, 'spam', 1.23, 123, 'spam', 1.23]
【注】这些操作都不会改变原列表
(2)特定类型操作;列表独享
- 在列表最后压入一个元素:
append('NI')
;运行结果[123, 'sapm', 1.23, 'NI']
- 根据下标弹出元素,返回弹出的职:
pop(2)
;执行结果1.23
- 根据下标插入一个元素:
insert(2, ‘abc’)
- 根据元素内容移除一个元素,但只会移除第一个匹配项:
remove('Ni')
>>> L = [123, 'spam']
>>> L.append('Ni')
[123, 'spam', 'Ni']
>>> L.pop(1)
[123, 'Ni']
>>> L.insert(2, 'abc')
[123, 'Ni', 'abc']
>>> L.remove('Ni')
[123, 'abc']
- 重排序办法:
sort()
; 规则:按照字母表排序 - 逆序输出办法:
reserve()
【注】这些操作都会改变原列表
(3)边界检查
Python 的列表边界检查很严格,它不允许引用不存在的元素,也就是说引用超出列表末尾之外的索引会报错,无论是获取还是赋值
>>> L = [123, 'spam', 'Ni']
>>> L[8]
# ...error text omitted...
# IndexError: list index out of range
>>> L[8] = 1 # error...
(4)嵌套 与 推导
列表中允许嵌套列表,看起来像是其他语言中的二维数组:
>>> M = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> M[0]
[1, 2, 3]
>>> M[1][2]
6
Python中存在一种处理像矩阵这样结构的强大工具,称作为 列表推导表达式,他的格式如下:
[表达式 for 变量 in 列表]
或者[表达式 for 变量 in 列表 if 条件]
含义:在矩阵(或列表)中遍历出‘变量’,如果有‘if条件’,则对‘变量’执行过滤,最后对该变量执行‘表达式’操作,执行结束后返回一个新列表
>>> M = [[1,2,3],[4,5,6],[7,8,9]]
>>> [row[1] for row in M if row[1] % 2 == 0]
[2, 8]
>>> double = [c * 2 for c in 'spam']
>>> double
['ss', 'pp', 'aa', 'mm']
【解释】in
执行循环遍历,if
执行过滤操作,row[1]
执行针对每个的row
表达式
(5)扩展:list()结合range() 生成连续整数
range()
用来指定一个数据范围,遵循左闭右开原则,可接受1,2,3个参数。结合list()
执行后返回一个列表。
>>> list(range(4)) # 一个参数,表示 0-4
[0, 1, 2, 3]
>>> list(range(-4, 5, 2)) # 开始范(闭),结束范围(开),步长
[-4, -2, 0, 2, 4]
>>> [[x**2, x**3] for x in range(3)] # range()也可以用在列表推导表达式中
[[0, 0], [1, 1], [4, 8]]
(6)其他
- 内置求和函数:
sum()
- 内置高阶函数:
map()
4. 字典
字典,不是序列,而是一种映射(mapping
)。它是通过键(key
)而不是相对位置来存储对象的。对象与列表不同,没有它没有边界限制。当对一个新的字典的键赋值时会创建该键
(1)字典赋值办法
常见的对象赋值办法有1. 直接创建法;2. 根据键值对赋值;3. zip整体赋值法
>>> D = {'a': 1, 'b': 2, 'c': 3 }
>>> bob1 = dict(name='Bob', Job='dev', age=40)
>>> bob1
{ 'age': 40, 'name': 'Bob', 'job': 'dev' }
>>> bob2 = dict(zip(['name', 'job', 'age'], ['Bob', 'dev', 40]))
>>>bob2
{ 'age': 40, 'name': 'Bob', 'job': 'dev' }
(2)重访嵌套
字典允许嵌套存储,即在字典的某个键属性上存储另一个字典,或者存储其他类型的数据结构,如 列表等。对这些嵌套的数据结果,他们的用法和其本身没有区别。
>>> res = ['name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr']]
>>> rec['job'].append('janitor')
['name': {'first': 'Bob', 'last': 'Smith'}, 'job': ['dev', 'mgr', 'janitor']]
(3)垃圾回收机制GC
Python具有一种叫做垃圾回收的特性,在程序运行时可以清理不在使用的内存。一旦一个对象的最后一次引用被移除,即变量引用数为0时,空间将立即被回收。
(4)键值存在性检查
>>> D = { 'a': 1, 'b': 2, 'c': 3 }
- in 关系表达式
'f' in D
===>false
- get() 方法
D.get('x', 0)
===>0
;因为x
不存在与D
中,因此获取默认值0
- try语句 捕获异常工具
- if/else 三元表达式:
>>> value = D['x'] if 'x' in D else 0
(5)键的排序 与 循环
字典不是序列,他们并不包含任何可靠的从左至右的顺序, 对齐简单的输出其顺序并不能得到保证。我们可以通过keys()
方法收集一个键的列表。使用列表的sort()
进行排序
>>> D = { 'a': 1, 'b': 2, 'c': 3 }
>>> Ks = list(D.keys())
>>> Ks
{ 'a', 'c', 'b' } # 输出顺序是乱的
>>> Ks.sort()
{ 'a', 'b', 'c' } # sort() 使其按照字母顺序输出
>>> for key in Ks:
print (key, '=>', D[key])
与 for
循环相近的还有 while
循环
>>> x = 4
>>> while x > 0:
print ('spam' * 4)
x -= 1
(6)迭代和优化
Python中循环工作于任意的遵守迭代协议的可迭代对象中。
一个可迭代对象可以是在内存中物理存储的序列,也可以是一个在迭代操作情况下每次产生元素的新对象:一种“虚拟”的序列。这两种类型的对象都被认为是可迭代的。因为他们都支持碟台协议: 他们在响应next
之前先用一个对象对iter
内置函数做出响应,并在结束时触发一个异常
迭代使用循环 如 :for
来实现,尽管如此很高效,列表推导和相关的函数编程工具(如map和filter)在某些代码上通常运行比for
快甚至两倍。 因此编程原则是:首先根据简单和可读性编写,在可以工作并证明确实有必要考虑性能是,在进行以上优化