变量赋值
赋值运算符
=是主要的赋值运算符,其他的是增量赋值运算符。
aint = 12
astring = 'python'
afloat = 3.14
alist = [1,3,4]
赋值并不是将一个值赋给一个变量。python中对象是通过引用传递的,是将对象的应用传递给变量。
>>> x=1
>>> id(x)
31162760L
>>> y=x
>>> id(y)
31162760L
C语言中赋值当成一个表达式,可以返回值。python中不是这样,不会返回值。以下非法:
>>> a=(b=1)File "<stdin>", line 1a=(b=1)^
SyntaxError: invalid syntax
多重赋值
可以多重赋值,如下:
对象的同一个引用被赋值给a、b
>>> a=b=2
>>> a
2
>>> b
2
>>> id(a) #查看对象引用地址
31162736L
>>> id(b)
31162736L
增量赋值
+= -= *= /= %= **= <<= >>= &= ^=
增量赋值相对普通赋值不仅是写法上的改变,有意义的是第一个对象仅被处理一次。可变对象就地修改(无修拷贝引用),不可变对象则和A=A+B结果一样(分配一个新对象)
python不支持x++或++x这样的自运算。
>>> m = 12
>>> m %=7
>>> m
5
>>> m **=2
>>> m
25
>>> alist = [123, 'xyz']
>>> alist += [456]
>>> alist
[123, 'xyz', 456]
多元赋值
多个变量同时赋值成为多元赋值。等号两边的对象都是元组
>>> x,y,z = 1,2,3
>>> x
1
>>> y
2
>>> z
3
通常用括号括起来:
(x,y,z) = (1,2,3)
C语言中交换变量,需要临时变量。python的多元赋值可以无需中间变量交换变量值。
C语言
tmp = x
x = y
y = tmppython多元赋值
x,y = y,x
标识符
合法标识符
- 第一个字符为字母或下划线
- 其余字符可以是字母、下划线或数字
- 大小写敏感
关键字
关键字列表和iskeyword()函数在keyword模块。
>>> import keyword
>>> keyword.kwlist
['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is','lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
>>> keyword.iskeyword('or')
True
‘and’, ‘as’, ‘assert’, ‘break’, ‘class’, ‘continue’, ‘def’, ‘del’, ‘elif’, ‘else’, ‘except’, ‘exec’, ‘finally’, ‘for’, ‘from’, ‘global’, ‘if’, ‘import’, ‘in’, ‘is’, ‘lambda’, ‘not’, ‘or’, ‘pass’, ‘print’, ‘raise’, ‘return’, ‘try’, ‘while’, ‘with’, ‘yield’
内建
python除了关键字还有可以在任何一级代码使用的内建的名字集合。这些名字可以由解释器设置或使用。虽然build-in不是关键字,但应该把它当做系统保留字,不做他用。
专用下划线标识符
- _xxx 不用’from module import *'导入
- __xxx__ 系统定义名字
- __xxx 类中的私有变量名
变量名_xxx被看作是私有的,在模块或类外不可以使用
内存管理
- 变量无须事先申明
- 变量无须指定类型
- 程序员不用关心内存管理
- 变量名会被回收
- del语句能够直接释放资源
变量定义
python中无须显示申明变量,变量在第一次赋值时自动申明。变量只有在被创建和赋值后才能被使用
动态类型
python中不仅变量无须事先申明,而且也无须类型申明。对象的类型和内存占用都是运行时确定的。在赋值时创建变量,解释器根据语法和右侧的操作数类决定新对象的类型。对象创建后,一个该对象的应用被赋值给左侧的变量。
内存分配
python解释器承担了内存管理的任务,不需要关心底层的事情
引用计数
要保持跟踪内存中的对象,python使用了引用计数技术。python记录所有使用中的对象各有多少引用。一个内部跟踪变量称为一个引用计数器。对象创建时,就创建一个引用计数,当这个对象不需要时,即当对象的引用计数为0,它被垃圾回收。
增加引用计数
- 赋值给多个变量
x=3.14
y=x
- 对象作为参数被函数调用
i = 1def fun(i):print id(i)print id(i)
fun(i)30964552
30964552
- 成为容器对象的一个元素
i = 1
alist = [1,i,3]print(id(i))
print(id(alist[1]))31554376
31554376
减少引用计数
- 一个本地引用离开了作用范围,如foo()函数结束
- 对象的别名被显示的销毁
del y - 对象的一个别名被赋值给其他的对象
x=123 - 对象呗从一个窗口对象中移除
mylist.remove(x) - 窗口对象本身被销毁
del mylist
del语句
del语句会删除对象的一个引用
垃圾收集
解释器跟踪对象的引用计数,垃圾收集器负责释放内存。垃圾收集器寻找引用计数为0的对象,也负责检查哪些虽然引用计数大于0但也应该被销毁的对象。特定情形会导致循环利用。
一个循环利用发生在当有至少两个对象相互引用时,也就是说所有的引用都消失时,这些引用仍然存在。
垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。当一个对象的引用计数变为0,解释器会暂停,释放掉这个对象和仅有这个对象可访问的其他对象。作为引用计数的补充,垃圾收集器也会留心被分配的总量很大的对象。
python对象
所有python对象都有三个特性:身份、类型和值
身份
每一个对象都有一个唯一的身份标识自己,任何对象的身份都可以使用内建函数id()得到。
类型
对象的类型决定了该对象可以保存什么类型的值,可以进行什么样的操作。可以用type()查看对象类型。python中类型也是对象,type返回的是对象而不是简单的字符串。
值
对象表示的数据项。对象的值是否可以可以更改被称为对象的可改变性。
对象属性
常用的属性是函数和方法,不过有些python类型也有数据属性。含有数据属性的对象包括但不限于:类、类实例、模块、复数和文件。
标准类型
- 数字,分为几个子类型,其中有三个是整型
- 整型
- 布尔型
- 长整型
- 浮点型
- 复数型
- 字符串
- 列表
- 元组
- 字典
其他内建类型
- 类型
- Null对象(None)
- 文件
- 集合/固定集合
- 函数/方法
- 模块
- 类
类型对象和Type类型对象
通过type()函数可以得到特定对象的类型信息。
整数对象的类型是一个类型对象。
>>> type(4)
<type 'int'>
所有类型对象的类型是type
>>> type(type(4))
<type 'type'>
type是所有python类型的根和所有python标准类的默认元类。
None,Python的Null对象
python有一个特殊的类型,成为Null对象或者NoneType,它只是一个值,那就是None。它不支持任何运算没有任何内建方法。
标准对象的布尔值
下列对象的布尔值是False。
- None
- False(布尔类型)
- 所有的值为零的数
- 0(整型)
- 0.0(浮点型)
- 0L(长整型)
- 0.0+0.0j(复数)
- “”(空字符串)
- [](空列表)
- ()(空元组)
- {}(空字典)
用户创建的实例如果定义了nonzero(__nonzero__())或length(__len__())且值为0,那么他们的布尔值就是False
内部类型
- 代码对象
- 帧对象
- 跟踪记录对象
- 切片对象
- 省略对象
- Xrange对象
代码对象
代码对象是编译过的python源代码片段,他是可执行对象。通过调用内建函数compile()可以得到代码对象。
代码对象可以被exec命令或eval()内建函数来执行。
代码对象是函数的一个属性,一个函数除了有代码队形属性以外,还有一些函数必须的其他属性,包括函数名,文档字符串,默认参数,以及全局命名空间。
帧对象
帧对象是python的执行栈帧。帧对象包含python解释器在运行时所需要知道的所有信息。
他的属性包括指向上一帧的链接,正在被执行的代码对象,本地及全局名字空间字典以及当前指令等。
每次函数调用产生一个新的帧,每一个帧对象都会相应创建一个C栈帧。用到帧对象的一个点是跟踪记录对象。
跟踪记录对象
当代码出错时,python引发一个异常,如果异常未被捕获和处理,解释器就会退出脚本处理,显示类似下面信息:
Traceback (most recent call last):File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
异常发生时,一个包含针对异常的栈跟踪信息的跟踪记录对象被创建。如果一个异常有自己的处理程序,处理程序就可以访问这个跟踪记录对象
切片对象
使用切片语法时,创建切片对象。
>>> str = 'python'
>>> str[::-1]
'nohtyp'
省略对象
省略对象用于扩展切片语法中,起记号作用。
这个对象在切片语法中表示省略号。类似Null对象None,省略对象有一个唯一的名字Ellipsis,他的布尔值始终为True。
Xrange对象
调用内建函数xrange()会生成一个Xrange对象。
标准类型比较
对象值的比较
数字类型根据数值的大小和符号比较,字符串按照字符序列值进行比较
>>> 'bbc' >= 'ab'
True
>>> 3 >= 3
True
>>> 2+3j == 2+3j
True
>>> [3, 'abc'] == [3,'abc']
True
多个比较操作可以在同一行进行,顺序为从左到右
>>> 3 < 4 < 7 # 等于 (3<4) and (4<7)
True
>>> 4 > 3 == 3 # 等于(4>3) and (3==3)
True
>>> 4 < 3 < 5 != 2 < 7 # 等于 (4<3) and (3<5) and (5!=2) and (2<7)
False
比较操是针对对象的值进行的,比较的是对象的数值而不是对象本身。
比较符号:
< > <= >= != ==
对象身份比较
is和is not运算符测试两个变量是否指向同一个对象。
a is b
等同于
id(a) == id(b)
>>> a= [1,2,3]
>>> b=a
>>> id(a)
40383880L
>>> id(b)
40383880L
>>> a is b
True>>> a=[1,2,3]
>>> b=[1,2,3]
>>>> id(a)
40392200L
>>> id(b)
40383880L
>>> a is b
False
注意可变对象与不可变对象的区别
整数对象和字符串对象是不可变对象,python创建时,如果值相同,只创建一个对象,其他的只增加引用。
>>> a = 1
>>> b = 1
>>> id(a)
31162760L
>>> id(b)
31162760L
当对象值改变时,会重新创建新对象。
>>> a = 1
>>> id(a)
31162760L
>>> a = a+1
>>> id(a)
31162736L
当整数值过大时,也会创建新对象,而不是增加引用。
>>> a = 10000
>>> b = 10000
>>> a is b
False
可变对象,没创建就会生生成一个新对象。
>>> a = 2.0
>>> b = 2.0
>>> id(a)
31224000L
>>> id(b)
31224024L
标准类型内建函数
python提供一些内建函数用于这些基本对象类型。
type()
type()接受一个对象作为参数,并返回它的类型,返回值是一个类型对象。
>>> type(3)
<type 'int'>
>>> type('a')
<type 'str'>
>>> type(type(3))
<type 'type'>
cmp()
比较两个对象obj1和obj2,如果obj1小于obj2,返回一个负整数,如果obj1大于obj2,返回一个正整数,如果相等,返回0。
比较是在两个对象间进行的,不管是标准类型还是自定义对象。如果是自定义对象,cmp()会调用该类的特殊方法__cmp__()。
>>> a,b = 1,2
>>> cmp(a,b)
-1
>>> a,b = 'abc','bcd'
>>> cmp(a,b)
-1
>>> b = 'abc'
>>> cmp(a,b)
0
str()、repr()及``运算符
str()、repr()及``运算符可以方便的以字符串的方式获取对象的内容、类型、数值属性等信息。
str()得到的字符串可读性好,repr()函数得到的字符串通常可以用来重新获得该对象,通常ojb == eval(repr(obj))等式成立。
>>> str([1,2,3])
'[1, 2, 3]'
>>> repr([1,2,3])
'[1, 2, 3]'
>>> `[1,2,3]`
'[1, 2, 3]'
repr()和``是一样的,返回一个对象的官方字符串表示,也就是说大多数情况下,可以通过求值运算(eval())重新得到该对象。
str()不同,str()用于生成一个对象的可读性好的字符串表示,返回结果通常无法用于eval()求值,但适合于print输出。
并不是所有repr()返回的字符串都能用eval()得到原来的对象。
>>> eval(`type(type)`)
Traceback (most recent call last):File "<stdin>", line 1, in <module>File "<string>", line 1<type 'type'>^
type()和isinstance()判断类型
def dispType(num):if isinstance(num, (int, long, float, complex)):print 'a number of type:', type(num).__name__
修改为使用简单的方法:
def dispType(num):print num,'is'if type(num) == type(0):print 'an integer'if type(num) == type(0L):print 'a long'
减少type()调用次数:
import types
if type(num) == types.IntType:print 'int'
运行时,只有一个类型对象表示整数类型,type(0),type(10),type(-100)都是同一个对象:<type ‘int’>。types.IntType也是这个对象。可以修改成对象身份比较。
if type(num) is types.IntType:print 'int'
标准类型的分类
存储模型
一个能保存单个字面对象的类型,称为原子或标量存储。可容纳多个对象的类型,称之为容器存储。
- 标量/原子类型:数值,字符串
- 容器类型:列表、元组、字典
更新模型
可变对象允许值更新,不可变对象值不能更改。
- 可变类型:列表,字典
- 不可变类型:数字、字符串、元组
访问模型
根据访问存储的数据的方式对数据类型分类,共有三种访问方式:直接存储、顺序、和映射。
非容器类型可以直接访问。所有的数值类型都归到这一类。
序列类型指容器按从0开始的索引顺序访问。
映射类型类似序列的索引属性,不过索引并不适用顺序的数字,他的元素无序存放。通过key访问。
- 直接访问:数字
- 顺序访问:字符串、列表、元组
- 映射访问:字典
数据类型 | 存储模型 | 更新模型 | 访问模型 |
---|---|---|---|
数字 | 原子 | 不可变 | 直接访问 |
字符串 | 原子 | 不可变 | 顺序访问 |
列表 | 容器 | 可变 | 顺序访问 |
元组 | 容器 | 不可变 | 顺序访问 |
字典 | 容器 | 可变 | 映射访问 |
数字
python数字类型有整型、长整型、布尔型、双精度浮点型、十进制浮点型和复数。
- 删除数字 无法删除数字,还是不在引用。 del anInt。引用被删除对象的引用引发NameError对象。
整型
python内置内属性
- __dict__ : 类的属性,包含一个字典,由类的数据属性组成
- __doc__ : 类的文档字符串
- __name__ : 类名
- __module__ : 类定义所在的模块,类的全名是’__main__.classname’,如果类位于一个导入模块mymod中,那么classname.__module__等于mymod
- __bases__ : 类的所有父类构成元素,包含了一个由所有父类组成的元组
基础方法重载
方法 | 描述 |
---|---|
__init__(self [,args]) | 构造函数,实例化时调用: obj = classname(args) |
__del__(self) | 析构方法,删除一个对象,调用方法:del obj |
__repr__(self) | 转换为公解释器读取的字符串,调用:repr(obj) |
__str__(self) | 将值转换成字符串,调用:str(obj) |
__cmp__(self, x) | 对象比较,调用:cmp(obj, x) |
单下划线、双下划綫、头尾双下划线
- __foo__ : 定义特殊方法,一般是系统定义名字,类似__init__()之类的
- _foo :单下划线开头的表示类似protected变量,只能允许其本身与子类进行访问,不能用于
from module import *
- __foo : 双下划綫开头的表示私有类型变量,智能允许这个类本身进行访问
正则表达式
re.match()函数
语法
re.match(pattern, string, flags=0
匹配成功返回一个匹配的对象
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要操作的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如是否区分大小写,多行匹配。 |
group()和groups()
re.search()
扫描整个字符串,返回第一个成功的匹配。
语法
re.search(pattern, string, flags=0)
参数
参数 | 描述 |
---|---|
pattern | |
string | |
flags |
re.match()与re.search()区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;re.search匹配整个字符串,知道找到一个匹配。
re.sub
用正则表达式查找字符串并进行替换。
语法
re.sub(pattern, replacestr, string, count=0, flags=0)
参数
参数 | 描述 |
---|---|
pattern | |
replacestr | 用来替换的字符串,也可是函数 |
string | 用户查找并进行替换的原始字符串 |
count | 模式匹配后替换的最大次数,默认0表示替换所有的匹配 |
re.compile()
用于编译正则表达式,生成一个正则表达式对象,供match()和search()函数使用。
语法
re.compile(pattern[, flags])
参数
参数 | 描述 |
---|---|
pattern | 正则表达式字符串 |
flags | 可选,表示匹配模式,比如忽略大小写,多行模式. |
flags参数值:
- re.I:忽略大小写
- re.L:表示特殊字符集\w,\W,\b,\B,\s,\S依赖于当前环境
- re.M :多行模式
- re.S:即为.并且包括换行符在内的任意字符(.不包括换行符)
- re.U:表示特殊字符集\w,\W,\b,\B,\s,\S依赖于Unicode字符属性数据库
- re.X:为了增加可读性,忽略空格和#后面的注释
匹配对象的操作
对于返回的匹配对象可以有如下操作
- group([num1, …]) 用于获得一个或多个分组匹配的字符串,如果要获得所有匹配的子串时,可直接用group()或group(0)
- start([num]) 用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认为0
- end([num]) 用户获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认为0
- span([num]) 方法返回(start(num), end(num))
测试:
>>>import re
>>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写
>>> m = pattern.match('Hello World Wide Web')
>>> print m # 匹配成功,返回一个 Match 对象
<_sre.SRE_Match object at 0x10bea83e8>
>>> m.group(0) # 返回匹配成功的整个子串
'Hello World'
>>> m.span(0) # 返回匹配成功的整个子串的索引
(0, 11)
>>> m.group(1) # 返回第一个分组匹配成功的子串
'Hello'
>>> m.span(1) # 返回第一个分组匹配成功的子串的索引
(0, 5)
>>> m.group(2) # 返回第二个分组匹配成功的子串
'World'
>>> m.span(2) # 返回第二个分组匹配成功的子串
(6, 11)
>>> m.groups() # 等价于 (m.group(1), m.group(2), ...)
('Hello', 'World')
>>> m.group(3) # 不存在第三个分组
Traceback (most recent call last):File "<stdin>", line 1, in <module>
IndexError: no such group
findall()
从字符串中查找正则表达式匹配的所有子串并返回一个列表,如果没有匹配,则返回空列表。
match和search是匹配一次,fandall是匹配所有。
语法
findall(string[, pos[, endpos]])
re.finditer()
和findall类似,在字符串中找到正则表达式所匹配的所有子串,并把他们作为一个迭代器返回。
re.finditer(pattern, string, flags=0)
# -*- coding: UTF-8 -*-import reit = re.finditer(r"\d+","12a32bc43jf3")
for match in it: print (match.group() )
结果
12
32
43
3
正则表达式模式
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符 |
[…] | 用来表示匹配一组字符中的任意一个,如[abc]匹配’a’,‘b’或’c’ |
[^…] | 不再[]中的字符。[^abc]表示匹配a,b,c之外的字符 |
re* | 匹配0个或多个re表达式 |
re+ | 匹配1个或多个re表达式 |
re? | 匹配0个或1个re表达式 |
re{n} | 精确匹配n个re表达式。如o{2}不能匹配bob中的o,能匹配food中的o |
re{n,} | 匹配至少n个re表达式 |
re{n,m} | 匹配n到m个re表达式 |
a|b | 匹配a或者b |
(re) | 对正则表达式分组并记住匹配的文本 |
(?imx) | 正则表达式包含三种可选标志:i,m,x。只影响括号中的区域 |
(?-imx) | 正则表达式关闭i,m,x可选标志,只影响括号中的区域 |
(?: re) | 类似(…),但是不表示一个组 |
(?imx: re) | 在括号找那个使用i,m,x标志 |
(?-imx: re) | 在括号中不适用i,m,x标志 |
(?#…) | 注释 |
(?= re) | 前向肯定界定符。如果所含正则表达式,以…表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边 |
(?! re) | 前向否定界定符,与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功 |
(?> re | 匹配的独立模式,省去回溯 |
\w | 匹配字母数字及下划线 |
\W | 匹配非字母数字及下划线 |
\s | 匹配任意空白字符,等价于[ \t\n\r\f] |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于[0-9] |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果存在换行,只匹配到换行前的结束字符串 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置 |
\b | 匹配一个单词便捷,也就是指单词和空格间的位置。如‘er\b’可以匹配’nerver’中的‘er’但不能匹配‘verb’中的‘er’ |
\B | 匹配非单词边界 |
\n, \t,等 | 匹配一个换行符。匹配一个制表符,等 |
\1 … \9 | 匹配第n个分组的内容 |
\10 | 匹配第n个分组的内容,如果它已经匹配。否则指的是八进制字符码的表达式 |
多线程
使用线程有2中方式,函数或者用类来包装线程。
函数:调用thread模块中的start_new_thread()函数来产生新线程。语法如下:
thread.start_new_thread(function, args[, kwargs])
参数
- function:线程函数
- args:传递给线程函数的参数,必须是tuple类型
- kwargs:可选参数
线程的结束一般依靠线程函数的自然结束;也可以在线程函数中调用thread.exit(),抛出SystemExit exception,达到退出线程的目的。
相关模块
python有两个标准库thread和threading提供对线程的支持。thread提供低级别、原始的线程以及一个简单点锁。
threading提供其他方法:
-
threading.currentThread():返回当前线程变量。
-
threading.enumerate():返回一个包含正在运行的线程的list。
-
threading.activeCount():返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法,线程模块同样提供了Thread类来处理线程,Thread类提供了一下方法: -
run():线程启动后,通过run()运行线程具体业务。
-
start():启动线程
-
join([time]):等待线程终止。
-
isActive():返回线程是否活动
-
getName():返回线程名
-
setName():设置线程名
线程锁
两个线程同时对同一个数据处理时,需要先获得线程锁,使用完数据释放线程锁。
#!/usr/bin/python
# -*- coding: UTF-8 -*-import threading
import timeclass myThread (threading.Thread):def __init__(self, threadID, name, counter):threading.Thread.__init__(self)self.threadID = threadIDself.name = nameself.counter = counterdef run(self):print "Starting " + self.name# 获得锁,成功获得锁定后返回True# 可选的timeout参数不填时将一直阻塞直到获得锁定# 否则超时后将返回FalsethreadLock.acquire()print_time(self.name, self.counter, 3)# 释放锁threadLock.release()def print_time(threadName, delay, counter):while counter:time.sleep(delay)print "%s: %s" % (threadName, time.ctime(time.time()))counter -= 1threadLock = threading.Lock()
threads = []# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)# 开启新线程
thread1.start()
thread2.start()# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)# 等待所有线程完成
for t in threads:t.join()
print "Exiting Main Thread"
线程优先级队列(queque)
python的queue模块提供了同步的、线程安全的队列类,包括FIFO队列Queue,LIFO队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列实现线程间的同步。