# 课程使用python 2.7,IDE使用pycharm
视频教程:牛客网(点击打开链接)
参考教程:菜鸟教程(点击打开链接)
第一节:开发工具和Python语言介绍
主要介绍这个项目需要用到的开发工具,并会帮助简单回顾这个项目所用到的语言-python。
┏━━━━━━━━━━━━━━目录━━━━━━━━━━━━━━┓
1、版本控制系统2、 安装第三方库的方法
【举例】Beautifulsoup——解析Html的库
3、python手册
4、pycharm中的一些快捷键
5、字符串
6、运算操作符 operation
7、内置函数 buildinfunction
8、控制流 controlflow
9、数据结构——列表list、元组tuple、字典dictionary、集合set
10、面向对象——封装、继承、多态
11、异常处理
12、随机数
13、正则表达式
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
1、版本控制系统
(1)Git分布式版本控制系统:GitHub/BitBucket
(2)SVN
【来自百度百科:SVN(Subversion)开放源代码的版本控制系统相较于RCS、CVS,它采用了分支管理系统,它的设计目标就是取代CVS。互联网上很多版本控制服务已从CVS迁移到Subversion。说得简单一点SVN就是用于多个人共同开发同一个项目,共用资源的目的。】
2、 安装第三方库的方法
(1)pip install xxx
(2)在pycharm中安装(settings—project—project interpreter)
【举例】Beautifulsoup——解析Html的库
例:爬取糗百的文本
import requests
from bs4 import BeautifulSoup
content = requests.get("http://www.qiushibaike.com").content # get网页
soup = BeautifulSoup(content, "html.parser") # 网页放入beautifulsoup解析
for div in soup.find_all("div", {"class": "content"}): # 打印content内容
print div.text.strip(), "\n"
3、python手册
在安装python的目录中可以找到。(我安装在了D盘,位置为D:\Python27\Doc\python2713.chm)
4、pycharm中的一些快捷键
(1)Ctrl + / 行注释/取消行注释
(2)Ctrl + Alt + L 代码格式化
(3)Tab + Tab 缩进当前行 / Shift + Tab 不缩进当前行
5、字符串
(1)capitalize() 首字母大写
(2)replace() 替换
stra = 'HELLO world'
print stra.capitalize() # (1)首字母大写
print stra.replace('world','haha') # (2)替换
输出
Hello world
HELLO haha
(3)lstrip() / rstrio() 去除开头/末尾的字符串 (缺省为空格字符)
strb = ' \n\rhello world \r\n'
print 1,strb
print 2,strb.lstrip() # 去除开头的指定字符串(缺省为空格字符)
strb2 = " this is example!!! "
print 3,strb2.lstrip() # 同上
strb3 = "888118this is example!!!8888"
print 4,strb3
print 5,strb3.lstrip('8') # 去除开头的8
print 6,strb3.rstrip('8') # 去除末尾的8
输出:
1
hello world
2 hello world
3 this is example!!!
4 888118this is example!!!8888
5 118this is example!!!8888
6 888118this is example!!!
(4) 其他一些字符串的操作与函数
3)startswith() 判断开头
4)endswith() 判断末尾
5)字符串拼接
6)len()
7)join() 字符串之间以指定字符连接(list→string)
8)split() 字符串通过某字符分开(string→list)
9、10)find() 查找指定字符串片段的位置
stra = 'aaa'
strb = 'bbbb'
strc = 'hello world'
print 3, strc.startswith('hel') # 判断字符串是不是以hel开头,输出True
print 4, strc.endswith('x') # 判断字符串是不是以x结尾,输出False
print 5, stra + strb + strc # 字符串拼接,输出aaabbbbhello world
print 6, len(strc) # 字符串长度,输出11
print 7, '-'.join(['a', 'b', 'c']) # 把字符串之间以-连接,输出a-b-c
print 8, strc.split(' ') # 把字符串通过某字符分开为list,输出['hello', 'world']
print 9, strc.find('hello') # 查找指定字符串位置,输出0(字符串‘hello’从位置0开始)
print 10, strc.find('ello') # 输出1(字符串‘ello’从位置1开始)
输出
3 True
4 False
5 aaabbbbhello world
6 11
7 a-b-c
8 ['hello', 'world']
9 0
6、运算操作符 operation
print 1, 1 + 2, 5 / 2, 5 * 2, 5 - 2
print 2, True, not True # not True 输出 False
print 3, 1 < 2, 5 > 2 # 输出 True True
print 4, 2 << 3 # 移位,输出16
print 5, 5 | 3, 5 & 3, 5 ^ 3 # 或,与,异或(位操作,二进制)输出 7 1 6
输出
1 3 2 10 3
2 True False
3 True True
4 16
5 7 1 6
7、内置函数 buildinfunction
【详见使用手册中的Built-in Functions】
(1)type()
(2)max(),min()
(3)len()
(4)abs()
(5)range()
(6)dir()
(7)chr(), ord()
(8)divmod()
x = 2
y = 3.3
print 1,x, y, type(x), type(y) # 内置函数type()查看变量类型
print 2, max(2, 1), min(5, 3) # 最值
print 3, len('xxx'), len([1, 2, 3]) # 字符串,数组长度
print 4, abs(-2) # (c)fabs,(java)Math.fabs # 绝对值
print 5, range(1, 10, 3) # 1到10, 步长3 输出[1, 4, 7]
print 6, dir(list) # 把list类型下的函数名打印出来
print 7, chr(97), ord('a') # ASCII码97对应字符,字符a对应ASCII码,输出a 97
print 8, divmod(11, 3) # 求余,得3余2,输出(3, 2)
输出 1 2 3.3 <type 'int'> <type 'float'>
2 2 3
3 3 3
4 2
5 [1, 4, 7]
6 ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
7 a 97
8 (3, 2)
(9)eval() / repr()
eval() 将字符串当成有效Python表达式来求值,并返回计算结果
repr() Python的变量和表达式转换为字符串表示
x = 2
print eval('x + 3') # 字符串"x+3",输出5
print repr(x == 1), type(repr(x == 1)) # 输出字符串"False"
print repr(x + 1), type(repr(x + 1)) # 输出字符串3
str_a = "[1,2,3,4]"
print type(str_a) # 字符串str_a
print eval(str_a), type(eval(str_a)) # 转化成list,输出[1, 2, 3, 4] <type 'list'>
输出
5
False <type 'str'>
3 <type 'str'>
<type 'str'>
[1, 2, 3, 4] <type 'list'>
8、控制流 controlflow
(1)if,ellif,else
(2)while循环
score = 65
while score < 100:
print score
score += 10
输出
65
75
85
95
(3)for循环
【例1】输出0~9
(对应c中的:# for (int i = 0; i < 10; ++i) )
for i in range(0, 10):
print i
输出0,1,2,……,9
【例2】输出0~9,步长为2
for i in range(0, 10, 2):
print i
输出0,2,4,6,8
【例3:continue】输出0~9,大于等于5的数
for i in range(0, 10):
if i < 5:
continue # 当i<5时跳过本次循环,执行下一次循环
print i
输出5,6,7,8,9
【例4:break】
for i in range(0, 10):
if i == 5:
break # 当i=5时,跳出整个循环
print i
输出0,1,2,3,4
for i in range(0, 10):
print i # 注意print的位置
if i == 5:
break # 当i=5时,跳出整个循环
输出0,1,2,3,4,5
【例5:pass】
for i in range(0, 10):
if i == 5:
pass # 先不做任何处理,直接跳过,但是如果不写pass,就会语法错误
else:
print i
输出0,1,2,3,4,6,7,8,9(跳过5)
9、数据结构——列表list、元组tuple、字典dictionary、集合set
【具体每种数据结构的方法,见python文档:The Python Tutorial/Data Structures】
【Ⅰ】 列表list(对应于c中的vector,java中的arraylist)
(1、2)列表的元素
(3、4)列表与列表的连接
(5)len()
(6)in :元素是否在list中
(7)insert() 添加元素
(8)pop() 删除指定位置元素,(如果没有指定对象,默认是最后一个值)
(9)reverse() 逆序
(10)索引访问列表的元素
(11、12)sort()列表排序
(13)列表*2
(14)列表初始化
lista = [1, 2, 3]
print 1, lista
listb = ['a', 1, 'c', 1.1] # 列表中的元素可以是不同类型的
print 2, listb
lista.extend(listb) # 列表b【连接】到列表a的后面
print 3, lista # 此时lista输出[1, 2, 3, 'a', 1, 'c', 1.1]
lista = lista + listb # (操作符重载)添加列表b的内容到列表a的后面
print 4, lista # [1, 2, 3, 'a', 1, 'c', 1.1, 'a', 1, 'c', 1.1]
print 5, len(lista) # 列表【长度】(元素个数),11
print 6, 'a' in listb # 元素‘a’是否在listb中,输出True
listb.insert(0, 'www') # 在listb的位置0之前【添加】一个元素‘www’,输出['www', 'a', 1, 'c', 1.1]
print 7, listb
listb.pop(1) # 【弹出】listb位置1的元素("a"),输出['www', 1, 'c', 1.1],缺省默认pop最末尾的元素
print 8, listb
listb.reverse() # 【逆序】,[1.1, 'c', 1, 'www']
print 9, listb
print 10, listb[0], listb[1] # 数组索引访问元素,1.1 c
listb.sort()
print 11, listb # 【排序】 [1, 1.1, 'c', 'www']
listb.sort(reverse=True)
print 12, listb # 逆序排序 ['www', 'c', 1.1, 1]
print 13, listb * 2 # ['www', 'c', 1.1, 1, 'www', 'c', 1.1, 1]
print 14, [0] * 14 # 【初始化】为14个0 ,c语言中memset(src, 0, len)
输出
1 [1, 2, 3]
2 ['a', 1, 'c', 1.1]
3 [1, 2, 3, 'a', 1, 'c', 1.1]
4 [1, 2, 3, 'a', 1, 'c', 1.1, 'a', 1, 'c', 1.1]
5 11
6 True
7 ['www', 'a', 1, 'c', 1.1]
8 ['www', 1, 'c', 1.1]
9 [1.1, 'c', 1, 'www']
10 1.1 c
11 [1, 1.1, 'c', 'www']
12 ['www', 'c', 1.1, 1]
13 ['www', 'c', 1.1, 1, 'www', 'c', 1.1, 1]
14 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
15 [1, 2, 3, 4]
【Ⅱ】元组tuple
tuplea = (1, 2, 3) # 元组是不可变更的list,是只读的
listaa = [1, 2, 3]
listaa.append(4) # 列表具有append()可以添加元素,元组没有该方法
print 15, listaa
输出
15 [1, 2, 3, 4]【Ⅲ】字典dictionary
(2、3)输出指定key对应的value
(4)增加新的键值对
(5)输出key / value的列表
(6)has_key() 判断是否存在指定key
(7、8)pop() del 删除
dicta = {4: 16, 1: 1, 3: 9, 2: 4}
print 1, dicta
print 2, dicta[2] # dicta[2]表示key为2对应的value,输出4
print 3, dicta.get(2) # 通过get()访问value,输出4,同上
dicta['a'] = 'x' # 【增加】新的键值对
print 4, dicta
print 5, dicta.keys(), dicta.values() # 以列表形式【输出】字典的所有key/value
print type(dicta.keys())
print 6, dicta.has_key(1), dicta.has_key('3') # 判断【查找】是否存在指定key(没有has_value)
for k, v in dicta.items():
print 'key-value:', k, v # 【遍历】key value(自动按key的排序输出)
dicta.pop(4) # 【删除】key为4的键值对
print 7, dicta
del dicta[3] # 【删除】key为3的键值对
print 8,dicta
输出
1 {1: 1, 2: 4, 3: 9, 4: 16}2 4
3 4
4 {'a': 'x', 1: 1, 2: 4, 3: 9, 4: 16}
5 ['a', 1, 2, 3, 4] ['x', 1, 4, 9, 16]
<type 'list'>
6 True False
key-value: a x
key-value: 1 1
key-value: 2 4
key-value: 3 9
key-value: 4 16
7 {'a': 'x', 1: 1, 2: 4, 3: 9}
8 {'a': 'x', 1: 1, 2: 4}
(9)字典的value可以是函数
def add(a, b):
return a + b
def sub(a, b):
return a - b
dictb = {'+': add, '-': sub} # 字典的value可以是个函数
print dictb['+'](1, 2) # 通过下标访问vaue
print dictb.get('-')(15, 3) # 通过get()访问value
输出3
12
【Ⅳ】集合set
(1)set是一个无序不重复元素集。作为一个无序的集合,sets不记录元素位置或者插入点。因此,sets不支持 indexing, slicing, 或其它类序列(sequence-like)的操作。
(2)基本功能包括关系测试和消除重复元素.
(3)集合对象还支持union(联合), intersection(交), difference(差)和sysmmetric difference(对称差集)等数学运算.
(4)sets 支持 x in set, len(set),和 for x in set
lista = [1, 2, 3]
seta = set(lista)
setb = set((2, 3, 4))
setc = {3, 4, 5}
print seta,type(seta)
print setb,type(setb)
print setc,type(setc)
print 2, seta & setb,seta.intersection(setb) # 交集
print 3, seta | setb, seta.union(setb) # 并集
print 4, seta - setb # 差
print 5, setb - seta # 差
seta.add('x') # 增加元素
print 6, seta
print len(seta)
print seta.isdisjoint(set((1, 2))) # 没有相同项则返回True
输出
set([1, 2, 3]) <type 'set'>set([2, 3, 4]) <type 'set'>
set([3, 4, 5]) <type 'set'>
2 set([2, 3]) set([2, 3])
3 set([1, 2, 3, 4]) set([1, 2, 3, 4])
4 set([1])
5 set([4])
6 set([1, 2, 3, 'x'])
4
False
10、面向对象——封装、继承、多态
【Ⅰ】封装:把客观事物封装成抽象的类(包括一些属性、方法)
【Ⅱ】继承:以普通的类为基础建立专门的类对象(如果已经有了一个类,又想建立一个非常类似的类,只是添加几个方法。)
【Ⅲ】多态:多态意味着就算不知道变量所引用的对象类是什么,还是能对它进行操作,而它也会根据对象(或类)类型的不同而表现出不同的行为。用户可以对于不知道是什么类(或对象类型)的对象进行方法调用。
【Tip】概念辨析:重载vs重写
(1)方法重载(overloading method):在一个类里面,方法名字相同,而参数不同。返回类型呢?可以相同也可以不同。
函数重载主要是为了解决两个问题:可变参数类型、可变参数个数。Python没有重载。
(2)方法重写(overiding method) :子类不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
class User: # 【封装】User类
type = 'USER' # 静态变量
def __init__(self, name, uid): # 成员函数中的初始化函数
self.name = name
self.uid = uid
def __repr__(self): # 默认输出(reprint)
return 'im ' + self.name + ' ' + str(self.uid)
class Guest(User): # Guest【继承】了User
def __repr__(self):
return 'im guest:' + self.name + ' ' + str(self.uid)
class Admin(User): # Admin【继承】了User
type = 'ADMIN'
def __init__(self, name, uid, group): # Admin多了group
User.__init__(self, name, uid) # 调用基类init
self.group = group # 赋值增加的group
def __repr__(self):
return 'im ' + self.name + ' ' + str(self.uid) + ' ' + self.group # 重写了增加的group——【多态】
def create_user(type):
if type == 'USER':
return User('u1', 1)
elif type == 'ADMIN':
return Admin('a1', 101, 'g1')
else:
return Guest('gu1', 201)
# raise ValueError('error')
user1 = User("u1", 1)
print user1
admin1 = Admin("a1", 101, "g1")
print admin1, "\n"
print create_user("USER")
print create_user("ADMIN")
print create_user("GUEST")
(1) 捕捉异常
try:
print 1
print 2 / 0 # 触发异常后,后面的代码就不会再执行
print 3
except Exception as e: # 捕获异常,把这些异常信息print出来
print 'error:', e
finally: # 不论是否发生异常,都会执行Finally语句后的代码
print 'clean up'
输出
1
error: integer division or modulo by zero
clean up
(2)raise语句用于引发一个异常,可以自定义异常
try:
size = 'L'
if size == 'L':
raise Exception('Raise Error', 'NowCoder') # 可以使用raise语句自己触发异常
except Exception as e:
print 'error:', e
finally:
print 'clean up'
输出
error: ('Raise Error', 'NowCoder')
clean up
(3)捕捉多个异常
try:
print 2/0
except ZeroDivisionError:
print '除数不能为0'
except Exception:
print '其他类型异常'
输出
除数不能为0
12、随机数
* 计算机的随机数都是伪随机。
* 所谓“随机码”,就是无论这个码有多长都不会出现循环的现象,而“伪随机码”在码长达到一定程度时会从其第一位开始循环。
(*)seed() 改变随机数生成器的种子,可以在调用其他随机模块函数之前调用此函数。
(1)random() 获取随机数。不能直接访问的,需要通过 random 静态对象调用该方法。
(4)randint(M,N) 返回[M,N]的整数
(5)choice() 方法返回一个列表,元组或字符串的随机项。
(*)range() 函数可创建一个整数列表。range(10)不包含10。
(6)sample()
(7)shuffle() 方法将序列的所有元素随机排序
import random
random.seed(2) # 指定seed之后,每次随机出来的值被固定
print 1, random.random() # 返回[0,1)之间的浮点数
print 2, random.random() * 100 # [0,100)的浮点数
print 3, int(random.random() * 100) # [0,100)的整数
print 4, random.randint(0, 100) # [0,100]的整数,包含100
print 5, random.choice(range(0, 100, 10)) # [0,100),步长为10,随机抽取1个数
print 6, random.sample(range(0, 100), 4) # 抽样[0,100),随机抽取4个数
a = [1, 2, 3, 4, 5]
random.shuffle(a) # 随机打乱列表
print 7, a
输出
1 0.956034271889
2 94.7827487059
3 5
4 8
5 80
6 [73, 66, 30, 60]
7 [2, 5, 1, 3, 4]
13、正则表达式 Regular Expression
* 可简写为regex、regexp、RE
① \d \D \s \S \w \W
② + * ?
③ | ^
④ 0
⑤ \\ (匹配"."需要转义字符"\.")
【菜鸟教程】下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
模式 | 描述 |
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[...] | 用来表示一组字符,单独列出:[amk]匹配 'a','m'或'k'([ ] 里是“或”的关系) |
[^...] | 不在[]中的字符:[^abc]匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。(至少匹配一次) |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{ n} | |
re{ n,} | 精确匹配n个前面表达式。(指定匹配的长度) |
re{ n, m} | 匹配 n到 m 次由前面的正则表达式定义的片段,贪婪方式 |
a| b | 匹配a或b |
(re) | G匹配括号内的表达式,也表示一个组 |
(?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 | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。C |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b'可以匹配"never"中的 'er',但不能匹配 "verb"中的 'er'。 |
\B | 匹配非单词边界。'er\B'能匹配 "verb" 中的 'er',但不能匹配 "never"中的 'er'。 |
\n, \t, 等. | 匹配一个换行符。匹配一个制表符。等 |
\1...\9 | 匹配第n个分组的内容。 |
\10+241:38 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
(1)re.compile() 根据包含正则表达式的字符串创建模式对象
(2)模式.findall() 以列表的形式返回能匹配的子串
str = 'abc123def12gh15'
p1 = re.compile('[\d]+') # 匹配1个或多个数字。 正则表达式的模式——pattern
p2 = re.compile('\d') # 匹配1个数字
print 1, p1.findall(str)
print 2, p2.findall(str) # 以列表的形式返回匹配的子串
str = 'a@163.com;b@gmail.com;c@qq.com;e0@163.com;z@qq.com'
p3 = re.compile('[\w]+@[163|qq]+\.com') # email的正则表达式
print 3, p3.findall(str)
str = '<html><h>title</h><body>xxx</body></html>'
p4 = re.compile('<h>[^<]+</h>')
print 4, p4.findall(str) # <h>title</h>
p4 = re.compile('<h>([^<]+)</h>') # 加()匹配输出括号内的字符串
print 5, p4.findall(str) # title
p4 = re.compile('<h>([^<]+)</h><body>([^<]+)</body>') # 运用()提取多个
print 6, p4.findall(str) # 'title', 'xxx'
str = 'xx2016-06-11yy'
p5 = re.compile('\d\d\d\d-\d\d-\d\d')
print 7, p5.findall(str)
p5 = re.compile('\d{4}-\d{2}-\d{2}') # 用{}表示次数
print 8, p5.findall(str)
输出
1 ['123', '12', '15']
2 ['1', '2', '3', '1', '2', '1', '5']
3 ['a@163.com', 'c@qq.com', 'e0@163.com', 'z@qq.com']
4 ['<h>title</h>']
5 ['title']
6 [('title', 'xxx')]
7 ['2016-06-11']
8 ['2016-06-11']