Python 基础知识快速入门学习
ubuntu创建 ***.py ,运行python ***.py
1、print 打印
1.1、输入打印
1)、打印hell oword :
print “hello word”
2)、打印 3.14
print 3.14
1.2、计算打印
1)、1+2*3
print 1+2*3 (7)
1.3、比较打印
1)比较2和3
print 2>3 (false)
print 2<3 (true)
2、变量
name = ‘Crossin’ (字符串,需要用’’或者””引起来)
myVar = 123 (整数)
price = 5.99 (浮点数)
visible = True (布尔运算)
‘=’ 号的作用是赋值左边变量
a=123
print a (123)
a=’hello’
print a (hello)
value = 3*4
print value (12)
value =2 <5
print value (true)
name = input()
print name
print “Who do you think I am ?”
you = input()
print “oh,yes ! I am ”
print you
3、运算
>:大于 <:小于 >=:大于等于 <=:小于等于 ==:等于。比较两个值是否相等。之所以用两个等号,是为了和变量赋值区分开来。!=:不等与not:逻辑“非”。如果x 为True,则not x 为False and:逻辑“与”。如果x 为True,且y 为True,则x and y 为True or:逻辑“或” 。如果x、y中至少有一个为True,则x or y 为True
num = 10
print 'Guess what I think?'
answer = input()
result = answer<num
print 'too small?'
print result
result = answer>num
print 'too big?'
print result
result = answer==num
print 'equal?'
print result
4、if语句
if 语句的时候,会去判断它所带条件的真假。
“如果”为True,就会去执行接下来的内容。 “如果”为False,就跳过。
语法为:
if 条件: 选择执行的语句
特别说明:条件后面的冒号不能少,同样必须是英文字符。特别特别说明: if 内部的语句需要有一个统一的缩进, 一般用4 个空格。python 用这种方法
替代了其他很多编程语言中的{}。你也可以选择1/2/3... 个空格或者按一下tab 键,但必须整 个文件中都统一起来。千万不可以tab 和空格混用,不然就会出现各种莫名其妙的错误。所 以建议都直接用4 个空格。
thisIsLove = input()
if thisIsLove: print " 再转身就该勇敢留下来 "
试试看?输入True,就会得到回答。 输入False,什么也没有。(如果你那里输出中文有问题, 请自行改成英文)
所以,我们的游戏可以这样改写:
num = 10
print 'Guess what I think?'
answer = input()
if answer<num:
print 'too small!'
if answer>num:
print 'too big!'
if answer==num:
print 'BINGO!'
4、while 语句
程序执行到while 处,“当”条件为True 时,就去执行while 内部的代码,“当”条件为False 时,就跳过。
语法为:
while 条件: 循环执行的语句
同 if 一样,注意冒号,注意缩进。
a = 1 #先 a设为 1
while a != 0: #a 不等于0 就一直做
print "please input"
a = input()
print "over注意,这里出现了两层缩进,要保持每层缩进的空格数相同。
5、随机数random
之前我们用了很多次的print 和input 方法,它们的作用是实现控制台的输入和输出。除此 之外,python 还提供了很多模块,用来实现各种常见的功能,比如时间处理、科学计算、 网络请求、随机数等等等等。今天我就来说说,如何用python 自带的随机数模块,给我们 的小游戏增加不确定性。
引入模块的方法:
from 模块名 import 方法名
看不懂没关系, 这东西以后我们会反复用到。 今天你只要记住, 你想要产生一个随机的整数, 就在程序的最开头写上:
from random import randint
之后你就可以用randint 来产生随机数了。
还记得input 后面的()吗,我们使用randint 的时候后面也要有()。而且,还要在括号中提供 两个数字,先后分别是产生随机整数范围的下限和上限。例如:
randint(5, 10)
这样将会产生一个 5 到 10 之间(包括 5 和 10)的随机整数。
写一个才随机数的小游戏:
from random import randint
num = randint(1,10)
print “guss 1~10 what num I think ”
answer = input()
result = answer == num
while not result:
print“wrong”
print“go ahead”
answer= input()
result = answer == num
print “God you cangusss it !”
6、变量2深入补充
变量这东西,我们已经用过。有了变量,就可以存储和计算数据。今天来讲点变量的细节。
#==== 变量命名规则====# 变量名不是你想起就能起的:
第一个字符必须是字母或者下划线“_”
剩下的部分可以是字母、下划线“_”或数字(0-9)
变量名称是对大小写敏感的,myname 和myName 不是同一个变量。 几个有效的栗子:
i
__my_name
name_23
a1b2_c3
几个坏掉的栗子(想一下为什么不对) :
2things
this is spaced out
my-name
#==== 变量的运算====#
我们前面有用到变量来存储数据:num = 10
answer = input()
也有用到变量来比较大小:answer < num
除此之外,变量还可以进行数学运算:a = 5 b = a + 3 c = a + b
python 中运算的顺序是,先把“=”右边的结果算出了,再赋值给左边的变量。下面这个例 子:a = 5 a = a + 3 print a 你会看到,输出了8,因为先计算出了右边的值为8,再把8 赋给左边的a。 通过这种方法,可以实现累加求和的效果。它还有个简化的写法:a += 3这个和a = a + 3是一样的。
于是,利用变量、 循环、累加,可以写一个程序, 来完成传说中高斯大牛在小时候做过的题:1+2+3+...+100=?从1 加到100 等于多少?
提示:你可以用一个变量记录现在加到几了,再用一个变量记录加出来的结果,通过while 来判断是不是加到100 了。
num =1;
sum =0;
while num<=100 :
sum=sum+num;
num=num+1;
print sum
6、for 循环
for ... in ...
for 循环,则可以这么写:
for i in range(1, 101):
print i
解释一下,range(1, 101)表示从1 开始,到101 为止(不包括101),取其中所有的整数。for i in range(1, 101) 就是说,把这些数,依次赋值给变量i。相当于一个一个循环过去,第一次i = 1,第二次i = 2,,,,直到i = 100。当i = 101 时跳出循环。所以,当你需要一个循环10 次的循环,你就只需要写:
for i in range(1, 11)
或者
for i in range(0, 10)
区别在于前者i 是从1 到10,后者i 是从0 到9。当然,你也可以不用i 这个变量名。 比如一个循环n 次的循环:
for count in range(0, n)
for 循环的本质是对一个序列中的元素进行递归。什么是序列,以后再说。先记住这个最简
单的形式:
for i in range(a, b)
从 a 循环至 b-1
for I in range(0,100):
print i
7、字符串
python 中最常用的字符串表示方式是单引号(‘’)和双引号( "" )。我还是要再说:一定得 是英文字符!
'string'和“ string”的效果是一样的。
可以直接输出一个字符串print ‘good’
也可以用一个变量来保存字符串,然后输出str = ‘bad’print str
如果你想表示一段带有英文单引号或者双引号的文字, 那么表示这个字符串的引号就要与内 容区别开。
内容带有单引号,就用双引号表示 "It's good" 反之亦然‘You are a "BAD" man’
python 中还有一种表示字符串的方法:三个引号(‘’‘)或者( """ )
在三个引号中,你可以方便地使用单引号和双引号,并且可以直接换行
'''
"What's your name?" Iasked.
"I'm Han Meimei."
'''
还有一种在字符串中表示引号的方法,就是用 ,可以不受引号的限制
\'表示单引号, \" 表示双引号 ‘I\'ma \"good\" teacher ’
被称作转译字符,除了用来表示引号,还有比如用 表示字符串中的\ \n 表示字符串中的换行
还有个用处,就是用来在代码中换行,而不影响输出的结果:"this is the\
same line"
这个字符串仍然只有一行,和
"this is thesame line" 是一样的,只是在代码中换了行。当你要写一行很长的代码时,这个会派上用场。
1.
He said, "I'm yours!"
print‘He said, "I'm yours!" ’
2.
print ‘’’\\\_v_//‘’‘
3.
Stay hungry,
stay foolish.
-- Steve Jobs
print ‘’’ Stay hungry,
stay foolish.
-- Steve Jobs
’’’
4.
*
***
*****
***
*
print ‘’’
*
***
*****
***
*
’’’
8、字符串格式化
我们在输出字符串的时候,如果想对输出的内容进行一些整理,比如把几段字符拼接起来, 或者把一段字符插入到另一段字符中间,就需要用到字符串的格式化输出。
1)先从简单的开始,如果你想把两段字符连起来输出
str1 = 'good'
str2 = 'bye'
你可以
print str1 + str2
或者还可以把字符变量一个字符串相加
print 'very' + str1
print str1 + ' and ' + str2
2)但如果你想要把一个数字加到文字后面输出,比如这样
num = 18
print 'My age is' + num 程序就会报错。因为字符和数字不能直接用+相加。
一种解决方法是,用 str()把数字转换成字符串
print 'My age is' + str(18) 或
num = 18
print 'My age is' + str(num)
还有一种方法,就是用 %对字符串进行格式化
num = 18
print 'My age is %d' % num 输出的时候, %d 会被%后面的值替换。输出
My age is 18
这里, %d只能用来替换整数。如果你想格式化的数值是小数,要用%f print ‘Price is %f’ % 4.99
输出
Price is 4.990000
如果你想保留两位小数,需要在 f 前面加上条件:%.2f print ‘Price is %.2f’ % 4.99 输出
Price is 4.99
另外,可以用 %s来替换一段字符串
name = 'Crossin'
print '%s is a good teacher.' %name 输出
Crossin is a good teacher.
或者
print 'Today is %s.' % 'Friday' 输出
Today is Friday.
注意区分: 有引号的表示一段字符, 没有引号的就是一个变量,这个变量可能是字符, 也可 能是数字,但一定要和%所表示的格式相一致。
之前我们说到,可以用 %来构造一个字符串,比如
print '%s is easy to learn' % 'Python'
有时候,仅仅代入一个值不能满足我们构造字符串的需要。假设你现在有一组学生成绩的数据,你要输出这些数据。在一行中,既要输出学生的姓名,又要输出他的成绩。例如 Mike‘s score is 87.
Lily‘s score is 95.
在 python中,你可以这样实现:
print "%s's score is %d" % ('Mike', 87)
或者
name = ‘Lily’
score = 95
print "%s's score is %d" % (name, score)
无论你有多少个值需要代入字符串中进行格式化,只需要在字符串中的合适位置用对应格式的%表示,然后在后面的括号中按顺序提供代入的值就可以了。占位的 %和括号中的值在数 量上必须相等,类型也要匹配。
('Mike', 87) 这种用 ()表示的一组数据在 python 中被称为元组( tuple),是 python 的一种基本数据结构。
9、循环嵌套for循环
设想一样,如果我们要输出 5 个* ,用 for 循环要这么写
for i in range(0, 5):
print '*'
如果想让这 5 个* 在同一行,就在 print 语句后面加上逗号
for i in range(0, 5): print '*',
但如果我想要这样一个图形,怎么办?
* * * * *
* * * * *
* * * * *
* * * * *
* * * * *
当然,你可以循环 5 次,每次输出一行“ * * ** * ”。那如果再进一步,这样呢?
*
**
***
****
*****
除了你自己动手打好一个多行字符串外,也可以让程序帮我们解决这种问题,我们需要的是两个嵌套在一起的循环:
for i in range(0, 5):
for j in range(0, 5):
print i, j
第二个 for 循环在第一个 for 循环的内部,表示每一次外层的循环中,都要进行一遍内层的循环。看一下输出的结果:
0 0
0 1
0 2
0 3
0 4
1 0
...
4 4 内层循环中的 print 语句一共被执行了 25 次。 i 从 0 到 4 循环了 5 次。对应于每一个 i 的值,j 又做了从 0 到 4 五次循环。 所以 5*5 一共 25 次。
所以如果要输出一个 5*5 的方阵图案,我们可以
for i in range(0, 5):
for j in range(0, 5):
print '*',
注意:第二个 print 的缩进和内层的 for 是一样的,这表明它是外层 for 循环中的语句,每次 i 的循环中,它会执行一次。 print 后面没有写任何东西,是起到换行的作用,这样,每输出 5 个*,就会换行。
要输出第二个三角图案时,我们需要根据当前外层循环的序数,设置内层循环应当执行的次数。
for i in range(0, 5): for j in range(0, i+1):
print '*',
内层的 j 每次从 0 到 i+1 进行循环。 这样,当第一次 i=0 时, j 就是 range(0,1),只输出 1 个* 。 而当最后一次 i=4 时, j 就是 range(0,5),输出 5 个*。
10、类型转换
字符串 整数 小数(浮点数)bool 类型
python 在定义一个变量时不需要给它限定类型。变量会根据赋给它的值,自动决定它的类 型。你也可以在程序中,改变它的值,于是也就改变了它的类型。例如
a = 1
print a
a = 'hello'
print a
a = True
print a
变量a 先后成为了整数、字符串、bool 类型。
虽然类型可以随意改变, 但当你对一个特定类型的变量进行操作时, 如果这个操作与它的数 据类型不匹配,就会产生错误。比如以下几行代码
print ‘Hello ’+1 print ‘hello%d’ % '123'
程序运行时会报错。因为第一句里,字符串和整数不能相加;第二句里,%d需要的是一个 整数,而 '123' 是字符串。
这种情况下,python 提供了一些方法对数值进行类型转换:
int(x) # 把x 转换成整数float(x) # 把x 转换成浮点数str(x) # 把x 转换成字符串bool(x) # 把x 转换成bool 值
上述两个例子就可以写成:
print ‘Hello ’+str(1) print ‘hello%d’ % int('123')
以下等式的结果均为真:
int('123') == 123
float('3.3') == 3.3
str(111) == '111'
bool(0) == False
并不是所有的值都能做类型转换, 比如int('abc') 同样会报错,python 没办法把它转成一个整 数。
另外关于bool 类型的转换,我们会专门再详细说明。大家可以先试试以下结果的值,自己 摸索一下转换成bool 类型的规律:
bool(-123) true
bool(0) False
bool('abc') true
bool('False') true
bool('') false
因为在python 中,以下数值会被认为是 False: 为 0 的数字,包括 0,0.0 空字符串,包括 '',"" 表示空值的 None 空集合,包括(),[],{} 其他的值都认为是True。
None 是python 中的一个特殊值,表示什么都没有,它和0、空字符、False、空集合都不一 样。关于集合,我们后面的课程再说。
所以,‘False’是一个不为空的字符串,当被转换成bool 类型之后,就得到True。同样 bool(' ') 的结果是True,一个空格也不能算作空字符串。 bool('') 才是 False。
11、函数
如果我们要自己写一个函数,就需要去定义它。python 里的关键字叫
def(define的缩写),格式如下:
def sayHello():
print 'hello world!'
sayHello 是这个函数的名字,后面的括号里是参数,这里没有,表示不
需要参数。但括号和后面的冒号都不能少。下面缩进的代码块就是整个
函数的内容,称作函数体。
然后我们去调用这个函数:
sayHello()
得到和直接执行 print 'hello world!' 一样的结果。
12、函数的参数
如果我们希望自己定义的函数里允许调用者提供一些参数, 就把
这些参数写在括号里,如果有多个参数,用逗号隔开,如:
def sayHello(someone):
print someone + ' says Hello!'
或者
def plus(num1, num2):
print num1+num2
参数在函数中相当于一个变量, 而这个变量的值是在调用函数的时候被
赋予的。在函数内部,你可以像过去使用变量一样使用它。
调用带参数的函数时,同样把需要传入的参数值放在括号中, 用逗号隔
开。要注意提供的参数值的数量和类型需要跟函数定义中的一致。 如果
这个函数不是你自己写的,你需要先了解它的参数类型,才能顺利调用
它。
比如上面两个函数,我们可以直接传入值:
sayHello('Crossin') 还是注意,字符串类型的值不能少了引号。
或者也可以传入变量:
x = 3
y = 4
plus(x, y)
在这个函数被调用时, 相当于做了num1=x, num2=y 这么一件事。 所以
结果是输出了7
13、函数应用示例,判断值大小返回结果
def isEqual(num1, num2):
if num1<num2:
print 'too small'
return False;
if num1>num2:
print 'too big'
return False;
if num1==num2:
print 'bingo'
return True
from random import randint
num = randint(1, 100)
print 'Guess what I think?'
bingo = False
while bingo == False:
answer = input()
bingo = isEqual(answer, num)
14、if,elif, else
之前说的if,是: “如果”条件满足,就做xxx,否则就不做。
else 顾名思义,就是: “否则”就做yyy。
当if 后面的条件语句不满足时,与之相对应的else 中的代码块将被执
行。
if a == 1:
print 'right' else print 'wrong'
elif 意为else if ,含义就是: “否则如果 ”条件满足,就做yyy。elif后面
需要有一个逻辑判断语句。
当if 条件不满足时,再去判断elif 的条件,如果满足则执行其中的代码
块。
if a == 1:
print 'one'
elif a == 2:
print 'two'
if, elif, else 可组成一个整体的条件语句。
if 是必须有的;
elif 可以没有,也可以有很多个,每个 elif 条件不满足时会进入下一个
elif 判断;
else 可以没有,如果有的话只能有一个,必须在条件语句的最后。
if a == 1:
print 'one'
elif a == 2:
print 'two'
elif a == 3:
print 'three'
else:
print 'too many'
我们昨天刚改写的小游戏中的函数isEqual ,用了三个条件判断,我们
可以再改写成一个包含if...elif...else 的结构:
def isEqual(num1, num2):
if num1<num2:
print 'too small'
return False
elif num1>num2:
print 'toobig'
return False
else:
print 'bingo'
return True
15、list列表
今天要说一个新概念--list,中文可以翻译成列表,是用来处理一组有序
项目的数据结构。
for i in range(1, 10): #此处略过数行代码
看出来list 在哪里了吗?你试一下:
print range(1,10)
得到的结果是:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
这就是一个 list。它由 range 产生。把上面那个 for 循环语句写成:
l = range(1, 10)
for i in l:
效果是一样的。
于是可以看出,for 循环做的事情其实就是遍历一个列表中的每一项,
每次循环都把当前项赋值给一个变量(这里是i),直到列表结束。
我们也可以定义自己的列表,格式就是用中括号包围、逗号隔开的一组
数值:
l = [1, 1, 2, 3, 5, 8, 13]
可以用print 输出这个列表:
print l
同样也可以用for...in 遍历这个列表,依次输出了列表中的每一项:
for i in l:
print l,
列表中的元素也可以是别的类型,比如:
l = ['meat', 'egg', 'fish', 'milk']
甚至是不同类型的混合:
l = [365, 'everyday', 0.618, True]
l 身为一个列表,有一些特有的功能:
假设我们现在有一个list:
l = [365, 'everyday', 0.618, True]
除了用for...in 遍历l 中的元素,我们还能做点啥?
1).访问list 中的元素
list 中的每个元素都对应一个递增的序号。与现实中习惯的序号不同在
于,计算机中的计数通常都是从 0 开始,python 也不例外。
要访问l 中的第1 个元素365,只要用l[0]就可以了。依次类推,
print l[1] 就会输出 'everyday'
注意,你不能访问一个不存在的元素,比如 l[10],程序就会报错,提示
你index 越界了。
2).修改list 中的元素
修改list 中的某一个元素,只需要直接给那个元素赋值就可以了:
l[0] = 123
输出l,得到[123, 'everyday', 0.618, True] ,第 1 个元素已经从 365 被
改成了123。
3).向list 中添加元素
list 有一个append 方法,可以增加元素。以l 这个列表为例,调用的方
法是:
l.append(1024)
输出l,你会看到[123, 'everyday', 0.618, True, 1024] ,1024 被添加到
了l,成为最后一个元素。(第一个元素在上一步被改成了123)
然后同样可以用l[4]得到1024 。
4).删除list 中的元素
删除list 中的某一个元素,要用到del:
del l[0]
输出l,得到['everyday', 0.618, True, 1024] 。这时候再调用 l[0],会得
到'everyday',其他元素的序号也相应提前。
以上这些命令,你可以直接在python shell 中尝试
16、列表的索引和切片
我打算从今天开始,每天说一点这个小游戏的做法。方法有很多种,我
只是提供一种参考。 你可以按照自己喜欢的方式去做, 那样她才是属于
你的游戏。
先说一下方向的设定。我的想法比较简单,就是左中右三个方向,用字
符串来表示。射门或者扑救的时候,直接输入方向。所以这里我准备用
raw_input 。有同学是用1-8 的数字来表示八个方向,每次输入一个数
字,这也是可以的。不过这样守门员要扑住的概率可就小多了。
至于电脑随机挑选方向,如果你是用数字表示,就用我们之前讲过的
randint 来随机就行。不过我这次打算用random 的另一个方法:choice。
它的作用是从一个list 中随机挑选一个元素。
于是,罚球的过程可以这样写:
from random import choice
print 'Choose one side to shoot:'
print 'left, center, right'
you = raw_input() #你选择的方向
print 'You kicked ' + you direction = ['left', 'center','right']
com = choice(direction) #电脑随机抽取方向
print 'Computer saved' + com
if you != com: #比对比们的方向
print 'Goal!'
else:
print 'Oops...'
反之亦然,不赘述。
list 有两类常用操作:索引(index) 和切片(slice) 。
我们说的用 []加序号访问的方法就是索引操作。
除了指定位置进行索引外,list 还可以处理负数的索引。
例子:
l = [365, 'everyday', 0.618, True]
l[-1]表示 l 中的最后一个元素。
l[-3]表示倒数第 3 个元素。
切片操作符是在[]内提供一对可选数字,用:分割。冒号前的数表示切片
的开始位置,冒号后的数字表示切片到哪里结束。 同样,计数从 0开始。
注意,开始位置包含在切片中,而结束位置不包括。
l[1:3]
得到的结果是 ['everyday', 0.618] 。
如果不指定第一个数,切片就从列表第一个元素开始。
如果不指定第二个数,就一直到最后一个元素结束。
都不指定,则返回整个列表的一个拷贝。
l[:3] l[1:] l[:]
同索引一样,切片中的数字也可以使用负数。比如:
l[1:-1]
得到['everyday',0.618]
17、字符串的分割
我们先从最基本的开始。 假设你现在拿到了一个英语句子, 需要把这个
句子中的每一个单词拿出来单独处理。
sentence = 'I am an Englist sentence'
这时就需要对字符串进行分割。
sentence.split()
split()会把字符串按照其中的空格进行分割,分割后的每一段都是一个
新的字符串,最终返回这些字符串组成一个list。于是得到
['I', 'am', 'an', 'Englist','sentence']
原来字符串中的空格不再存在。
除了空格外,split()同时也会按照换行符\n,制表符\t 进行分割。所以应
该说,split 默认是按照空白字符进行分割。
之所以说默认,是因为split 还可以指定分割的符号。比如你有一个很
长的字符串
section = 'Hi. I am the one. Bye.'
通过指定分割符号为'.',可以把每句话分开
section.split('.')
得到
['Hi', ' I am the one', ' Bye', '']
这时候,'.'作为分割符被去掉了,而空格仍然保留在它的位置上。
注意最后那个空字符串。每个 '.'都会被作为分割符,即使它的后面没有
其他字符,也会有一个空串被分割出来。例如
'aaa'.split('a')
将会得到['', '', '', ''] ,由四个空串组成的list
18、字符串连接
join和split正好相反:split 是把一个字符串分割成很多 字符串组成的list ,而join 则是把一个list 中的所有字符串连接成一个字符串。
join 的格式有些奇怪,它不是list 的方法,而是字符串的方法。首先你需要有一个字符串 作为list 中所有元素的连接符,然后再调用这个连接符的join 方法,join 的参数是被连 接的list :
s = ';'
li = ['apple', 'pear', 'orange']
fruit = s.join(li)
print fruit
得到结果 'apple;pear;orange' 。 从结果可以看到,分号把list 中的几个字符串都连接了起来。
你也可以直接在shell 中输入:
';'.join(['apple', 'pear', 'orange'])
得到同样的结果。
用来连接的字符串可以是多个字符,也可以是一个空串:
''.join(['hello', 'world'])
得到 'helloworld' ,字符串被无缝连接在一起
19、字符串和列表比较
1).遍历 通过for...in 可以遍历字符串中的每一个字符。
word = 'helloworld'
for c in word:
print c
2).索引访问 通过[] 加索引的方式,访问字符串中的某个字符。
print word[0]
print word[-2]
与 list 不同的是,字符串能通过索引访问去更改其中的字符。
word[1] = 'a' 这样的赋值是错误的。
3).切片 通过两个参数,截取一段子串,具体规则和list 相同。
print word[5:7]
print word[:-5]
print word[:]
4).连接字符join 方法也可以对字符串使用,作用就是用连接符把字符串中的每个字符重新连接成一个 新字符串。不过觉得这个方法有点鸡肋,不知道在什么场景下会用到。
20、读文件
打开一个文件的命令很简单:
file(' 文件名')
这里的文件名可以用文件的完整路径, 也可以是相对路径。 因为我们把要读取的文件和代码 放在了同一个文件夹下,所以只需要写它的文件名就够了。
f = file('data.txt')
但这一步只是打开了一个文件, 并没有得到其中的内容。 变量f 保存了这个文件, 还需要去 读取它的内容。你可以通过read() 函数把文件内所有内容读进一个字符串中。
data = f.read()
做完对文件的操作之后,记得用close() 关闭文件,释放资源。虽然现在这样一个很短的程 序,不做这一步也不会影响运行结果。但养成好习惯,可以避免以后发生莫名的错误。
完整程序示例:
f = file('data.txt')
data = f.read()
print data
f.close()
读取文件内容的方法还有
readline() # 读取一行内容
readlines() # 把内容按行读取至一个list 中
去替换程序的第二行,看看它们的区别
21、写文件
打开文件我们昨天已经讲过。但python 默认是以只读模式打开文件。如果想要写入内容, 在打开文件的时候需要指定打开模式为写入:
f = file('output.txt', 'w')
'w' 就是 writing ,以这种模式打开文件,原来文件中的内容会被你新写入的内容覆盖掉, 如果文件不存在,会自动创建文件。 不加参数时, file 为你默认为'r' ,reading ,只读模式,文件必须存在,否则引发异常。 另外还有一种模式是 'a' ,appending 。它也是一种写入模式,但你写入的内容不会覆盖之前的内容,而是添加到文件中。
打开文件还有一种方法,就是open() ,用法和 file() 是一致的。
写入内容的方法同样简单:
f.write('a string you want to write')
write 的参数可以是一个字符串,或者一个字符串变量。
示例程序:
data = 'I will be in a file.\nSocool!'
out = open('output.txt', 'w')
out.write(data)
out.close()
在你的程序保存目录下,打开output.txt 就会看到结果。
22、处理文件里面的数据
比如我现在拿到一份文档, 里面有某个班级里所有学生的平时作业成绩。 因为每个人交作业 的次数不一样, 所以成绩的数目也不同, 没交作业的时候就没有分。 我现在需要统计每个学 生的平时作业总得分。
看一下我们的文档里的数据:
#-- scores.txt
刘备23 35 44 47 51
关羽60 77 68
张飞 97 99 89 91
诸葛亮100
曹操100 100 100 100 100
1).先把文件读进来:
f = file('scores.txt')
2).取得文件中的数据。因为每一行都是一条学生成绩的记录,所以用readlines ,把每 一行分开,便于之后的数据处理:
lines = f.readlines()
f.close()
提示:在程序中,经常使用print 来查看数据的中间状态, 可以便于你理解程序的运行。 比如这里你可以print lines ,看一下内容被存成了什么格式。
3).对每一条数据进行处理。按照空格,把姓名、每次的成绩分割开:
for line in lines:
data = line.split()
接下来的4、5两个步骤都是针对一条数据的处理,所以都是在for 循环的内部。
4).整个程序最核心的部分到了。如何把一个学生的几次成绩合并,并保存起来呢?我的 做法是:对于每一条数据, 都新建一个字符串, 把学生的名字和算好的总成绩保存进去。 最后再把这些字符串一起保存到文件中:
sum = 0
for score in data[1:]:
sum += int(score)
result = '%s\t: %d\n' % (data[0], sum)
这里几个要注意的点: 对于每一行分割的数据,data[0] 是姓名,data[1:] 是所有成绩组成的列表。
每次循环中,sum都要先清零。 score 是一个字符串,为了做计算,需要转成整数值 int 。 result 中,我加了一个制表符 \t 和换行符 \n ,让输出的结果更好看些。
5. 得到一个学生的总成绩后,把它添加到一个list 中。
results.append(result)
results 需要在循环之前初始化 results = []
6. 最后,全部成绩处理完毕后,把results 中的内容保存至文件。因为results 是一个 字符串组成的list ,这里我们直接用 writelines 方法:
output = file('result.txt', 'w')
output.writelines(results)
outpus.close()
大功告成,打开文件检验一下结果吧。
以下是完整程序, 把其中print 前面的注释符号去掉, 可以查看关键步骤的数据状态。 不过 因为字符编码的问题,list 的中文可能会显示为你看不懂的字符。
f = file('scores.txt')
lines = f.readlines()
#print lines
f.close()
results = []
for line in lines:
#print line
data = line.split()
#print data
sum = 0
for score in data[1:]:
sum += int(score)
result = '%s \t: %d\n' %(data[0], sum)
#print result
results.append(result)
#print results
output = file('result.txt', 'w')
output.writelines(results)
output.close()
23、break and continue
如果在循环条件仍然满足或序列没有遍历完的时候, 想要强行跳出循环, 就需要用到break
语句。
while True:
a = raw_input()
if a == 'EOF':
break
上面的程序不停接受用户输入。当用户输入一行“ EOF”时,程序结束。
for i in range(10):
a = raw_input()
if a == 'EOF':
break
break 是彻底地跳出循环,而 continue 只是略过本次循环的余下内容,直接进入下一次循
环。
在我们前面写的那个统计分数的程序里,如果发现有成绩不足 60 分,就不记入总成绩。当
然,你可以用 if 判断来实现这个效果。但我们今天要说另一种方法:continue 。
for score in data[1:]:
point =int(score)
if point< 60:
continue
sum += point
注意:无论是 continue 还是 break,其改变的仅仅是当前所处的最内层循环的运行,如果外
层还有循环,并不会因此略过或跳出。
24、异常处理
在程序运行时,如果我们的代码引发了错误,python 就会中断程序,并且输出错误提示。
比如我们写了一句:
print int('0.5')
运行后程序得到错误提示:
Traceback (most recent call last):
File "C:/Python27/test.py", line 1, in<module>
print int('0.5')
ValueError: invalid literal for int() with base 10: '0.5'
意思是,在 test.py 这个文件,第 1 行, print int('0.5') 这里,你拿了一个不是 10 进制
能够表示的字符,我没法把它转成 int 值。
上面的错误可以避免,但在实际的应用中,有很多错误是开发者无法控制的,例如用户输
入了一个不合规定的值,或者需要打开的文件不存在。这些情况被称作“异常”,一个好
的程序需要能处理可能发生的异常,避免程序因此而中断。
例如我们去打开一个文件:
f = file('non-exist.txt')
print 'File opened!'
f.close()
假如这个文件因为某种原因并没有出现在应该出现的文件夹里,程序就会报错:
IOError: [Errno 2] No such file or directory:'non-exist.txt'
程序在出错处中断,后面的print 不会被执行。
在python 中,可以使用 try...except 语句来处理异常。做法是,把可能引发异常的语句
放在try- 块中,把处理异常的语句放在except- 块中。
把刚才那段代码放入try...except 中:
try:
f = file('non-exist.txt')
print 'File opened!'
f.close()
except:
print 'File not exists.'
print 'Done'
当程序在try 内部打开文件引发异常时,会跳过try 中剩下的代码,直接跳转到except 中
的语句处理异常。 于是输出了 “Filenot exists. ”。如果文件被顺利打开, 则会输出 “File
opened! ”,而不会去执行except 中的语句。
但无论如何,整个程序不会中断,最后的“ Done”都会被输出。
在try...except 语句中,try 中引发的异常就像是扔出了一只飞盘, 而except 就是一只灵
敏的狗,总能准确地接住飞盘。
25、字典
字典这种数据结构有点像我们平常用的通讯录,有一个名字和这个名字对应的信息。在字
典中,名字叫做“键”,对应的内容信息叫做“值”。字典就是一个键/ 值对的集合。
它的基本格式是( key 是键, alue 是值):
d = {key1 : value1, key2 : value2 }
键/ 值对用冒号分割,每个对之间用逗号分割,整个字典包括在花括号中。
关于字典的键要注意的是:
1. 键必须是唯一的;
2. 键只能是简单对象,比如字符串、整数、浮点数、bool 值。
list 就不能作为键,但是可以作为值。
举个简单的字典例子:
score = {
' 萧峰': 95,
' 段誉': 97,
' 虚竹': 89
}
python 字典中的键/ 值对没有顺序, 我们无法用索引访问字典中的某一项, 而是要用键来访
问。
print score[' 段誉']
注意,如果你的键是字符串, 通过键访问的时候就需要加引号, 如果是数字作为键则不用。 字典也可以通过 for...in 遍历:
for name in score :
print score[name]
注意,遍历的变量中存储的是字典的键。
如果要改变某一项的值,就直接给这一项赋值:
score[' 虚竹 '] = 91
增加一项字典项的方法是,给一个新键赋值:
score[' 慕容复 '] = 88
删除一项字典项的方法是 del :
del score[' 萧峰 ']
注意,这个键必须已存在于字典中。
如果你想新建一个空的字典,只需要 :
d = {}
26、模块
python 自带了功能丰富的标准库, 另外还有数量庞大的各种第三方库。 使用这些“巨人的”
代码,可以让开发事半功倍,就像用积木一样拼出你要的程序。
使用这些功能的基本方法就是使用模块。通过函数,可以在程序里重用代码;通过模块,
则可以重用别的程序中的代码。
模块可以理解为是一个包含了函数和变量的py 文件。在你的程序中引入了某个模块,就可
以使用其中的函数和变量。 来看一个我们之前使用过的模块:
import random
import 语句告诉 python ,我们要用 random 模块中的内容。然后便可以使用 random 中的方法,比如:
random.randint(1, 10)
random.randchoic([1, 3, 5])
注意,函数前面需要加上“ random. ”,这样 python 才知道你是要调用 random 中的方法。
想知道 random 有哪些函数和变量,可以用 dir() 方法:
dir(random)
如果你只是用到 random中的某一个函数或变量,也可以通过 from...import... 指明:
from math import pi
print pi
为了便于理解和避免冲突,你还可以给引入的方法换个名字:
from math import pi as math_pi
print math_pi
想要了解python 有哪些常用库,可自行搜索。
27、给函数提供默认参数
def hello(name):
print 'hello ' + name
然后我们去调用这个函数:
hello('world')
程序就会输出
hello world
如果很多时候, 我们都是用world 来调用这个函数,少数情况才会去改参数。那么,我们就 可以给这个函数一个默认参数:
def hello(name = 'world'):
print 'hello ' + name
当你没有提供参数值时,这个参数就会使用默认值;如果你提供了,就用你给的。
这样,在默认情况下,你只要调用
hello()
就可以输出
hello world
同样你也可以指定参数:
hello('python')
输出
hello python
注意,当函数有多个参数时, 如果你想给部分参数提供默认参数, 那么这些参数必须在参数的末尾。比如:
def func(a, b=5) 是正确的
def func(a=5, b) 就会出错
28、面向对象
面向对象编程最主要的两个概念就是: 类(class )和对象 (object )
类是一种抽象的类型,而对象是这种类型的实例。
举个现实的例子: “笔”作为一个抽象的概念, 可以被看成是一个类。 而一支实实在在的笔, 则是“笔”这种类型的对象。
一个类可以有属于它的函数,这种函数被称为类的“方法”。一个类/ 对象可以有属于它的 变量,这种变量被称作“域”。 域根据所属不同, 又分别被称作“类变量”和“实例变量”。
继续笔的例子。 一个笔有书写的功能, 所以“书写”就是笔这个类的一种方法。 每支笔有自 己的颜色,“颜色”就是某支笔的域,也是这支笔的实例变量。
而关于“类变量”, 我们假设有一种限量版钢笔, 我们为这种笔创建一种类。 而这种笔的“产 量”就可以看做这种笔的类变量。 因为这个域不属于某一支笔, 而是这种类型的笔的共有属 性。
域和方法被合称为类的属性。
python 是一种高度面向对象的语言,它其中的所有东西其实都是对象。所以我们之前也一 直在使用着对象。看如下的例子:
1). s = 'how are you' #s 被赋值后就是一个字符串类型的对象
2). l = s.split() #split 是字符串的方法,这个方法返回一个list 类型的对象 5. #l 是一个list 类型的对象
通过 dir() 方法可以查看一个类 / 变量的所有属性:
dir(s)
dir(list)
现在我们创建一个类:
class MyClass:
pass
mc = MyClass()
print mc
关键字 class加上类名用来创建一个类。 之后缩进的代码块是这个类的内部。 在这里, 我们用 pass 语句,表示一个空的代码块。
类名加圆括号 () 的形式可以创建一个类的实例, 也就是被称作对象的东西。 我们把这个对象 赋值给变量 mc。于是, mc现在就是一个MyClass 类的对象。
看一下输出结果:
<__main__.MyClass instance at 0x7fd1c8d01200>
这个意思就是说, mc是__main__模块中 MyClass 来的一个实例( instance ),后面的一串十六进制的数字是这个对象的内存地址。
我们给这个类加上一些域:
class MyClass:
name = 'Sam'
def sayHi(self):
print 'Hello%s' % self.name
mc = MyClass()
print mc.name
mc.name = 'Lily'
mc.sayHi()
我们给 MyClass 类增加了一个类变量 name,并把它的值设为'Sam' 。然后又增加了一个类方 法sayHi 。
调用类变量的方法是“对象 . 变量名”。你可以得到它的值,也可以改变它的值。
注意到,类方法和我们之前定义的函数区别在于,第一个参数必须为 self 。而在调用类方 法的时候,通过“对象. 方法名() ”格式进行调用,而不需要额外提供self 这个参数的值。 self 在类方法中的值,就是你调用的这个对象本身。
输出结果:
1. Sam
2. Hello Lily
之后,在你需要用到 MyClass 这种类型对象的地方,就可以创建并使用它。
用一个例子来展示两种程序设计方式的不同。 假设我们有一辆汽车,我们知道它的速度(60km/h) ,以及 A、B两地的距离 (100km) 。要算出 开着这辆车从 A地到 B地花费的时间。(很像小学数学题是吧?)
面向过程的方法:
speed = 60.0
distance = 100.0
time = distance /speed
print time
面向对象的方法:
class Car:
speed = 0
def drive(self, distance):
time = distance / self.speed
print time
car = Car()
car.speed = 60.0
car.drive(100.0)
看上去似乎面向对象没有比面向过程更简单,反而写了更多行代码。 但是,如果我们让题目再稍稍复杂一点。假设我们又有了一辆更好的跑车,它的速度是
150km/h,然后我们除了想从 A到B,还要从 B到 C(距离200km)。要求分别知道这两种车 在这两段路上需要多少时间。
面向过程的方法:
speed1 = 60.0
distance1 = 100.0
time1 = distance1/ speed1
print time1
distance2 = 200.0
time2 = distance2 / speed1
print time2
speed2 = 150.0
time3 = distance1 / speed2
print time3
time4 = distance2/ speed2
print time4
面向对象的方法:
class Car:
speed = 0
defdrive(self, distance):
time = distance / self.speed
print time
car1 = Car()
car1.speed = 60.0
car1.drive(100.0)
car1.drive(200.0)
car2 = Car()
car2.speed = 150.0
car2.drive(100.0)
car2.drive(200.0)
对比两种方法,面向过程把数据和处理数据的计算全部放在一起, 当功能复杂之后, 就会显 得很混乱, 且容易产生很多重复的代码。而面向对象,把一类数据和处理这类数据的方法封装在一个类中,让程序的结构更清晰,不同的功能之间相互独立。 这样更有利于进行模块化 的开发方式。
我们就来举一个稍稍再复杂一点的例子。
仍然是从 A地到 B地,这次除了有汽车,我们还有了一辆自行车! 自行车和汽车有着相同的属性:速度( speed)。还有一个相同的方法( drive ),来输出行 驶/ 骑行一段距离所花的时间。但这次我们要给汽车增加一个属性:每公里油耗( fuel )。 而在汽车行驶一段距离的方法中,除了要输出所花的时间外,还要输出所需的油量。
面向过程的方法, 你可能需要写两个函数, 然后把数据作为参数传递进去, 在调用的时候要 搞清应该使用哪个函数和哪些数据。 有了面向对象, 你可以把相关的数据和方法封装在一起, 并且可以把不同类中的相同功能整合起来。 这就需要用到面向对象中的另一个重要概念:继
承。
我们要使用的方法是, 创建一个叫做 Vehicle 的类,表示某种车, 它包含了汽车和自行车所 共有的东西:速度,行驶的方法。然后让 Car 类和 Bike 类都继承这个 Vehicle类,即作为 它的子类。在每个子类中,可以分别添加各自独有的属性。
Vehicle 类被称为基本类或超类, Car 类和 Bike 类被成为导出类或子类。
class Vehicle:
def __init__(self, speed): #__init__ 函数会在类被创建的时候自动调用, 用来初始化类
self.speed = speed
def drive(self, distance):
print 'need %fhour(s)' % (distance / self.speed)
classBike(Vehicle): #就是说Bike 是继承自 Vehicle 中的子类。
pass #因为 Bike 不需要有额外的功 能,所以用 pass 在类中保留空块,什么都不用写。
class Car(Vehicle):
def __init__(self,speed, fuel): #我们又重新定义了 __init__ 和 drive 函数,这样会覆盖掉它继承自 Vehicle 的同 名函数。
Vehicle.__init__(self, speed) #“ Vehicle. 函数名”来调用它的超类方法
self.fuel = fuel #我们又给Car 增加了一个fuel 属性,并且在 drive 中多输出一行信息
def drive(self, distance):
Vehicle.drive(self,distance)
print 'need %f fuels'% (distance * self.fuel)
b = Bike(15.0)
c = Car(80.0,0.012)
b.drive(100.0)
drive(100.0)
解释一下代码: __init__ 函数会在类被创建的时候自动调用,用来初始化类。它的参数,要在创建类的时候提供。于是我们通过提供一个数值来初始化speed 的值。
class 定义后面的括号里表示这个类继承于哪个类。Bike(Vehicle) 就是说 Bike 是继承自Vehicle 中的子类。 Vehicle 中的属性和方法,Bike 都会有。因为 Bike 不需要有额外的功 能,所以用 pass 在类中保留空块,什么都不用写。
Car 类中,我们又重新定义了__init__ 和 drive 函数,这样会覆盖掉它继承自Vehicle 的同 名函数。但我们依然可以通过“Vehicle. 函数名”来调用它的超类方法。 以此来获得它作为Vehicle 所具有的功能。注意,因为是通过类名调用方法,而不是像之前一样通过对象来调 用,所以这里必须提供self 的参数值。在调用超类的方法之后,我们又给Car 增加了一个
fuel 属性,并且在 drive 中多输出一行信息。
最后,我们分别创建一个速度为15 的自行车对象,和一个速度为 80、耗油量为0.012 的汽 车,然后让它们去行驶100 的距离
29、andor 技巧
看下面这段代码:
a ="heaven"
b ="hell"
c = True and a orb
print c
d = False and a orb
print d
输出:
heaven
hell
结果很奇怪是不是? 表达式从左往右运算,1 和"heaven" 做 and 的结果是"heaven" ,再与 "hell" 做or 的结果是 "heaven" ;0和"heaven" 做 and 的结果是0,再与 "hell" 做 or 的结果是"hell" 。 抛开绕人的and 和 or 的逻辑,你只需记住,在一个bool and a or b 语句中,当 bool 条件 为真时,结果是a;当 bool 条件为假时,结果是b。 有学过 c/c++ 的同学应该会发现,这和bool?a:b 表达式很像。
有了它,原本需要一个 if-else 语句表述的逻辑:
if a > 0:
print "big"
else:
print "small"
就可以直接写成:
print (a > 0) and "big" or "small"
然而不幸的是,如果直接这么用,有一天你会踩到坑的。 和 c 语言中的 ?: 表达式不同, 这里 的and or 语句是利用了 python 中的逻辑运算实现的。当 a 本身是个假值(如0,"")时,结果就不会像你期望的那样。
比如:
a = ""
b = "hell"
c = True and a orb
print c
得到的结果就是"hell" 。因为 "" 和"hell"做 and 的结果是"hell" 。
所以,and-or 真正的技巧在于, 确保 a 的值不会为假。 最常用的方式是使a 成为 [a] 、 b 成为[ b ] ,然后使用返回值列表的第一个元素:
a = ""
b = "hell"
c = (True and [a] or [b])[0]
print c
由于 [a] 是一个非空列表,所以它决不会为假。即使 a 是 0 或者 '' 或者其它假值,列表 [a] 也为真,因为它有一个元素。
在两个常量值进行选择时,and-or 会让你的代码更简单。但如果你觉得这个技巧带来的副 作用已经让你头大了,没关系,用if-else 可以做相同的事情。不过在 python 的某些情况 下,你可能没法使用 if 语句,比如lambda 函数中,这时候你可能就需要 and-or 的帮助了。
30、元组
上一次pygame的课中有这样一行代码:
x, y =pygame.mouse.get_pos()
复制代码 这个函数返回的其实是一个“元组”,今天我们来讲讲这个东西。
元组( tuple )也是一种序列,和我们用了很多次的 list 类似,只是元组中的元素在创建之后就不能被修改。
如:
postion = (1, 2)
geeks = ('Sheldon','Leonard', 'Rajesh', 'Howard')
复制代码 都是元组的实例。它有和list 同样的索引、切片、遍历等操作
print postion[0]
for g in geeks:
print g
print geeks[1:3]
复制代码 其实我们之前一直在用元组,就是在print 语句中:
print '%s is %d years old' % ('Mike', 23)
('Mike', 23) 就是一个元组。这是元组最常见的用处。
再来看一下元组作为函数返回值的例子:
def get_pos(n):
return (n/2, n*2)
得到这个函数的返回值有两种形式,一种是根据返回值元组中元素的个数提供变量:
x, y = get_pos(50)
print x
print y
这就是我们在开头那句代码中使用的方式。
还有一种方法是用一个变量记录返回的元组:
pos = get_pos(50)
print pos[0]
print pos[1]
31、数学运算
在用计算机编程解决问题的过程中,数学运算是很常用的。python 自带了一些基本的数学 运算方法
python 的数学运算模块叫做 math,再用之前,你需要
import math
math 包里有两个常量:
math.pi
圆周率 π:3.141592...
math.e 自然常数: 2.718281...
数值运算:
math.ceil(x) 对 x 向上取整,比如 x=1.2,返回2
math.floor(x) 对 x 向下取整,比如 x=1.2,返回1
math.pow(x,y) 指数运算,得到 x 的y 次方
math.log(x) 对数,默认基底为e。可以使用第二个参数,来改变对数的基底。比如 math.log(100, 10)
math.sqrt(x) 平方根
math.fabs(x) 绝对值
三角函数 :
math.sin(x)
math.cos(x)
math.tan(x)
math.asin(x)
math.acos(x)
math.atan(x) 注意:这里的 x 是以弧度为单位,所以计算角度的话,需要先换算
角度和弧度互换 :
math.degrees(x) 弧度转角度
math.radians(x) 角度转弧度
32、真值表
逻辑判断是编程中极为常用的知识。之前的课我们已经说过,见第6 课和第 11 课。但鉴于 逻辑运算的重要性,今天我再把常用的运算结果总结一下,供大家参考。
这种被称为 “真值表 ”的东西,罗列了基本逻辑运算的结果。你不一定要全背下来,但应该对 运算的规律有所了解。
为了便于看清,我用 <=>来表示等价关系。 <=>左边表示逻辑表达式, <=>右边表示它的结果。
NOT
not False <=> True
not True <=> False (not的结果与原值相反)
OR
True or False <=> True
True or True <=> True
False or True <=> True
False or False <=> False (只要有一个值为True,or 的结果就是True)
AND
True and False <=> False
True and True <=> True
False and True <=> False
False and False <=> False (只要有一个值为False,or 的结果就是False)
NOT OR
not (True or False) <=> False
not (True or True) <=> False
not (False or True) <=> False
not (False or False) <=> True
NOT AND
not (True and False) <=> True
not (True and True) <=> False
not (False and True) <=> True
not (False and False) <=> True
!=
1 != 0 <=> True
1 != 1 <=> False
0 != 1 <=> True
0 != 0 <=> False
==
1 == 0 <=> False
1 == 1 <=> True
0 == 1 <=> False
0 == 0 <=> True
以上就是基本的逻辑运算, 你会在编程中反复用到它们。 就算刚开始搞不清也没关系, 多写 几段代码就会熟悉了
33、正则表达式
什么是正则表达式?在回答这个问题之前,先来看看为什么要有正则表达式。
在编程处理文本的过程中,经常会需要按照某种规则去查找一些特定的字符串。 比如知道一个网页上的图片都是叫做'image/8554278135.jpg' 之类的名字,只 是那串数字不一样; 又或者在一堆人员电子档案中, 你要把他们的电话号码全部 找出来,整理成通 讯录。诸如此类工作,如果手工去做,当量大的时候那简直 就是悲剧。但你知道这些字符信息有一定的规律, 可不可以利用这些规律, 让程 序自动来做这些无聊的事 情?答案是肯定的。这时候,你就需要一种描述这些规律的方法,正则表达式就是干这事的。
正则表达式就是记录文本规则的代码。
所以正则表达式并不是python 中特有的功能,它是一种通用的方法。python 中的正则表达式库,所做的事情是利用正则表达式来搜索文本。要使用它, 你必 须会自己用正则表达式来描述文本规则,我们就从正则表达式的基本 规则开始说起。
1). 首先说一种最简单的正则表达式,它没有特殊的符号,只有基本的字母或数字的字符。
来看如下的一段文字: Hi, I am Shirley Hilton. I amhis wife.
如果我们用“ hi ”这个正则表达式去匹配这段文字, 将会得到两个结果。 因为是 完全匹配,所以每个结果都是“hi ”。这两个“ hi ”分别来自“Shirley ”和 “his ”。默认情况下正则表达式是严格区分大小写的,所以“Hi”和“Hilton ” 中的“Hi”被忽略了。
为了验证正则表达式匹配的结果,你可以用以下这段代码做实验:
import re
text = "Hi, Iam Shirley Hilton. I am his wife."
m = re.findall(r"hi", text)
if m:
print m
else:
print 'not match'
暂时先不解释这其中代码的具体含义,你只要去更改text 和 findall 中的字符 串,就可以用它来检测正则表达式的实际效果。
2). 如果我们只想找到“hi ”这个单词, 而不把包含它的单词也算在内, 那就可以使用“ b”这个正则表达式。 在以前的字符串处理中, 我们已经见过类似“n” 这种特殊字符。在正则表达式中,这种字符更多,以后足以让你眼花缭乱。
“ b”在正则表达式中表示单词的开头或结尾,空格、标点、换行都算是单词的分割。而“b”自身又不会匹配任何字符, 它代表的只是一个位置。 所以单词前 后的空格标点之类不会出现在结果里。
在前面那个例子里, “b”匹配不到任何结果。 但“bhi ”的话就可以匹配 到1 个“hi ”,出自“his ”。用这种方法,你可以找出一段话中所有单词“Hi”, 想一下要怎么写。
3). 最后再说一下[] 这个符号。在正则表达式中, [] 表示满足括号中任一字符。 比如 “[hi]”,它就不是匹配“ hi ”了,而是匹配“ h”或者“i ”。
在前面例子中,如果把正则表达式改为“[Hh]i ”,就可以既匹配“ Hi”,又匹 配“hi”了。
解释下上面代码意思:
r"hi"
这里字符串前面加了 r,是 raw 的意思,它表示对字符串不进行转义。为什么要加这个?你 可以试试 print "\bhi" 和 r"\bhi" 的区别。
>>> print"\bhi"
hi
>>> printr"\bhi"
\bhi
可以看到, 不加r 的话,\b 就没有了。因为 python 的字符串碰到“”就会转义它后面的字符。如果你想在字符串里打“”,则必须要打“”。
>>> print"\\bhi"
\bhi
这样的话,我们的正则表达式里就会多出很多 “”,让本来就已经复杂的字符串混乱得像五 仁月饼一般。但加上了 “r”,就表示不要去转义字符串中的任何字符,保持它的原样。
re.findall(r"hi", text)
re 是 python 里的正则表达式模块。 findall 是其中一个方法,用来按照提供的正则表达式,去匹配文本中的所有符合条件的字符串。返回结果是一个包含所有匹配的 list。
主要说两个符号 “. ” 和“*”,顺带说下 “S” 和“?” 。 “. ”在正则表达式中表示除换行符以外的任意字符。在提供的那段例子文本中: Hi, I amShirley Hilton. I am his wife.
如果我们用 “i. ”去匹配,就会得到
['i,', 'ir', 'il', 'is', 'if']
你若是暴力一点,也可以直接用 “.”去匹配,看看会得到什么。
与“. ”类似的一个符号是 “S”,它表示的是不是空白符的任意字符。注意是大写字符 S。
在很多搜索中, 会用 “?”表示任意一个字符, “*”表示任意数量连续字符, 这种被称为通配符。 但在正则表达式中,任意字符是用“. ”表示,而“*”则不是表示字符,而是表示数量:它表示前面的字符可以重复任意多次(包括 0 次),只要满足这样的条件,都会被表达式匹配上。
结合前面的 “.*” ,用“I.*e ”去匹配,想一下会得到什么结果?
['I am Shirley Hilton. I am his wife']
是不是跟你想的有些不一样?也许你会以为是
['I am Shirle', 'I am his wife']
这是因为 “*”在匹配时,会匹配尽可能长的结果。如果你想让他匹配到最短的就停止,需要用“.*? ”。如“I.*?e ”,就会得到第二种结果。这种匹配方式被称为懒惰匹配,而原本尽可能长的方式被称为贪婪匹配。
匹配手机号,其实就是找出一串连续的数字。更进一步,是11 位,以 1 开头的 数字。
还记得正则第1 讲里提到的 []符号吗?它表示其中任意一个字符。所以要匹配数 字,我们可以用
[0123456789]
由于它们是连续的字符,有一种简化的写法: [0-9]。类似的还有 [a-zA-Z] 的用法。
还有另一种表示数字的方法:
\d
要表示任意长度的数字,就可以用
[0-9]*
或者
\d*
但要注意的是, *表示的任意长度包括0,也就是没有数字的空字符也会被匹配 出来。一个与*类似的符号 +,表示的则是 1 个或更长。
所以要匹配出所有的数字串,应当用
[0-9]+
或者
\d+
如果要限定长度,就用{}代替+,大括号里写上你想要的长度。 比如 11 位的数字:
\d{11}
想要再把第一位限定为 1,就在前面加上1,后面去掉一位:
1\d{10}
OK. 总结一下提到的符号:
[0-9]
\d
+
{}
现在你可以去一个混杂着各种数据的文件里, 抓出里面的手机号, 或是其他你感 兴趣的数字了
1). 我们已经了解了正则表达式中的一些特殊符号,如\b 、\d 、. 、\S 等等。这些具 有特殊意义的专用字符被称作“元字符”。常用的元字符还有:
\w - 匹配字母或数字或下划线或汉字(我试验下了,发现3.x 版本可以匹配汉 字,但2.x 版本不可以) \s - 匹配任意的空白符 ^ - 匹配字符串的开始$ - 匹配字符串的结束
2). \S 其实就是\s 的反义,任意不是空白符的字符。同理,还有:
\W - 匹配任意不是字母,数字,下划线,汉字的字符\D - 匹配任意非数字的字符 \B - 匹配不是单词开头或结束的位置
[a] 的反义是 [^a] ,表示除a 以外的任意字符。 [^abcd] 就是除 abcd 以外的任意 字符。
3). 之前我们用过*、+、{} 来表示字符的重复。其他重复的方式还有:
? - 重复零次或一次 {n,} - 重复n 次或更多次 {n,m} - 重复 n 到 m次
正则表达式不只是用来从一大段文字中抓取信息, 很多时候也被用来判断输入的 文本是否符合规范,或进行分类。来点例子看看:^\w{4,12}$ 这个表示一段 4 到 12 位的字符,包括字母或数字或下划线或汉字,可以用来作 为用户注册时检测用户名的规则。(但汉字在python2.x 里面可能会有问题)
\d{15,18} 表示 15 到 18 位的数字,可以用来检测身份证号码
^1\d*[x]? 以 1 开头的一串数字,数字结尾有字母x,也可以没有。有的话就带上 x。
另外再说一下之前提到的转义字符 。如果我们确实要匹配. 或者*字符本身,而 不是要它们所代表的元字符,那就需要用\. 或\* 。 本身也需要用 。 比如"\d+\.\d+"可以匹配出 123.456 这样的结果
一个可以匹配出所有结果的表达式是
\(?0\d{2,3}[) -]?\d{7,8}
解释一下:
\(?
()在正则表达式里也有着特殊的含义,所以要匹配字符 "(",需要用 "\("。?表示这个括号是可有可无的。
0\d{2,3}
区号, 0xx或者 0xxx
[) -]?
在区号之后跟着的可能是 ")"、" "、"-",也可能什么也没有。
\d{7,8}
7 或 8 位的电话号码
可是,这个表达式虽然能匹配出所有正确的数据 (一般情况下,这样已经足够), 但理论上也会匹配到错误的数据。因为()应当是成对出现的,表达式中对于左右 两个括号并没有做关联处理,例如(02188776543 这样的数据也是符合条件的。
我们可以用正则表达式中的 “| ”符号解决这种问题。 “| ” 相当于python 中“or”的作用, 它连接的两个表达式,只要满足其中之一,就会被算作匹配成功。
于是我们可以把 ()的情况单独分离出来:
\(0\d{2,3}\)\d{7,8}
其他情况:
0\d{2,3}[ -]?\d{7,8}
合并:
\(0\d{2,3}\)\d{7,8}|0\d{2,3}[ -]?\d{7,8}
使用“| ”时,要特别提醒注意的是不同条件之间的顺序。匹配时,会按照从左往右 的顺序,一旦匹配成功就停止验证后面的规则。 假设要匹配的电话号码还有可能 是任意长度的数字(如一些特殊的服务号码),你应该把
|\d+
这个条件加在表达式的最后。 如果放在最前面, 某些数据就可能会被优先匹配为 这一条件。你可以写个测试用例体会一下两种结果的不同。
34、随机数
random 模块的作用是产生随机数。之前的小游戏中用到过random 中的 randint :
import random
num = random.randint(1,100)
random.randint(a, b) 可以生成一个 a 到b 间的随机整数,包括 a 和 b。 a、b都必须是整数,且必须 b≥a。当等于的时候,比如:
random.randint(3, 3) 的结果就永远是3
除了 randint,random模块中比较常用的方法还有:
random.random() 生成一个 0 到 1 之间的随机浮点数,包括0 但不包括 1,也就是 [0.0, 1.0)。
random.uniform(a, b) 生成 a、b之间的随机浮点数。不过与randint 不同的是, a、b 无需是整数,也不用考虑大 小。
random.uniform(1.5, 3)
random.uniform(3, 1.5) 这两种参数都是可行的。random.uniform(1.5, 1.5) 永远得到 1.5。
random.choice(seq) 从序列中随机选取一个元素。seq 需要是一个序列,比如 list、元组、字符串。
random.choice([1, 2, 3, 5, 8, 13]) #listrandom.choice('hello') # 字符串 random.choice(['hello', 'world']) # 字符串组成的list random.choice((1, 2, 3)) # 元组 都是可行的用法。
random.randrange(start, stop,step) 生成一个从start 到 stop(不包括 stop),间隔为 step 的一个随机数。 start、stop、step都要 为整数,且start<stop 。 比如:
random.randrange(1, 9, 2) 就是从[1, 3, 5, 7]中随机选取一个。 start 和step 都可以不提供参数,默认是从 0 开始,间隔为1。但如果需要指定 step,则必 须指定 start。
random.randrange(4) #[0, 1, 2, 3]
random.randrange(1, 4) #[1, 2, 3] random.randrange(start,stop, step) 其实在效果上等同于 random.choice(range(start,stop, step))
random.sample(population, k) 从population 序列中,随机获取 k 个元素,生成一个新序列。 sample 不改变原来序列。
random.shuffle(x)
把序列 x 中的元素顺序打乱。shuffle 直接改变原有的序列。
以上是 random 中常见的几个方法。如果你在程序中需要其中某一个方法,也可以这样写:
from random import randint
randint(1, 10)
另外,有些编程基础的同学可能知道,在随机数中有个seed 的概念,需要一个真实的随机 数,比如此刻的时间、鼠标的位置等等,以此为基础产生伪随机数。在python 中,默认用 系统时间作为seed。你也可以手动调用 random.seed(x) 来指定seed。
文献参考:
整理自:
https://wenku.baidu.com/view/001ef117e009581b6ad9eb52.html?re=view