代码高亮: 编程的色彩辅助体系,不是语法要求。
缩进: 一行代码开始前的空白区域,表达程序的格式框架
分类:单层缩进、多层缩进
特点:严格明确:缩进是语法的一部分,缩进不正确程序运行错误
所属关系:表达代码间包含和层次关系的唯一手段。
长度一致:程序内一致即可,一般用四个空格或者一个TAB
注释: 用于提高代码的可读性的辅助文字,不被执行
变量: 程序中用于保存和表示数据的占位符号
命名: 关联标识符的过程
保留字: 被编程语言内部定义并保留使用的标识符
python语言有35个保留字(也叫关键字)
保留字是编程语言的基本单词,大小写敏感
and | elif | import | raise | global |
---|---|---|---|---|
as | else | in | raise | nonlocal |
assert | except | is | return | True |
break | finally | lambda | try | False |
class | for | not | while | None |
continue | from | or | with | async |
def | if | pass | yield | await |
保留字含义
import、from:用于导入模块(第三方库)
in:判断变量是否存在序列中
not:表示“不是”,可用于逻辑判断非操作,表达式运算符
and:表达式运算,逻辑与操作
if、elif、else:分支语句
while:用于循环
def:定义函数或方法
lambda:生成简写函数的lambda表达式
as:名称转换
is:表示“是”,用于表达式操作
or:表示“或”,用于逻辑或和表达式运算
for:用于循环
try、except、finally:用于异常处理
with:用于上下文管理
assert:表示断言,用于判断一个变量或一个表达式的值是否为真
break:表示中断
class:用于定义类
continue:用于执行下一次循环
del:用于删除变量或序列的值
return:用于函数返回结果
yield:用于函数依次返回值
raise:用于抛出异常
nonlocal:用于函数嵌套定义时外层数据在内层的表示
global:表示全局变量
None:表示“空”
True:表示“真”
False:表示"假"
库名引用
inport <库名>
<库名>.<函数名>(函数参数)
from <库名> import <函数名>/from <库名> import *
<函数名>(函数参数)
import <库名> as <库别名>
<库别名>.<函数名>(参数名)
输入函数 input()
输出函数 print()
评估函数 eval()
pass 关键字
pass 无实际意义,只是单纯的用来占位,保证语句的完整性使程序不报错
例如
if age > 18 :
pass #占位,无意义,使程序完整不报错
print("hello")
与数学中整数的概念一致
可正可负,没有取值范围的限制
pow(x,y)函数:计算X^y
四种进制表示形式
十进制:1010、99、-217
二进制:以0b或0B开头:0b010、0B101
八进制:以0o或0O开头:0o123、0O456
十六进制:以0x或0X开头:0x9a、0X89
与数学中概念一致
带有小数点及小数的数字
浮点数取值范围和小数精度都存在限制,但常规计算可忽略
取值范围数量级约 − 1 0 3 07 至 1 0 3 08 -10^307 至 10^308 −10307至10308,精度数量级 1 0 − 16 10^-16 10−16
浮点数间运算符存在不确定尾数,不是bug
round()函数
round(x,d):对x四舍五入,d是小数截取位数,不确定位数发生在 1 0 − 16 10^-16 10−16 左右,round十分有效
浮点数科学计数法表示
使用e或E作为幂的符号,以10位基数,格式如下
e #表示a*$10^b $
与数学中复数的概念一致
定义j= − 1 \sqrt{-1} −1,以此为基础,构建数学体系
a+bj被称为复数,其中,a是实部,b是虚部
例如
z=1.23 e − 4 e^-4 e−4+5.6e+89i
real获得实部,imag获得虚部
数字类型间可进行混合运算,生成结果为“最宽”类型,三种类型存在一种逐渐“扩展”或“变宽”的关系:
整数 ——> 浮点数 ——> 复数 例如:整数 + 浮点数 = 浮点数
一元操作符
二元操作符有对应的增强赋值操作符
x op = y #即 x = x op y ,其中op为二元操作符
例
x += y 等价于 x = x+y
x**=3 等价于 x = x**3
abs(x) #绝对值,x的绝对值
divmod(x,y) #商余,(x//y,x%y),同时输出商和余数
pow(x,y[,z]) #幂余,(x**y)%z,[····]表示参数z可省略
round(x[,d]) #四舍五入,d是保留小数位数,默认值为0
max( x 1 x_1 x1, x 2 x_2 x2,···, x n x_n xn) #最大值,返回 x 1 x_1 x1, x 2 x_2 x2,···, x n x_n xn中最大值,n不限
min( x 1 x_1 x1, x 2 x_2 x2,···, x n x_n xn) #最小值,返回 x 1 x_1 x1, x 2 x_2 x2,···, x n x_n xn中最小值,n不限
int(x) #将x别为整数舍去小数部分
float(x) #将x变为浮点数,增加小数部分
complex(x) #将x变成复数,增加虚数部分
由0个或多个字符组成的有序字符类型
字符串序号
<----------- 反向递减序号
-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1
请 输 入 带 有 符 号 的 温 度 值
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
----------> 正向递增序号
字符串的使用
索引:返回字符串中单个字符 <字符串>[M]
,其中M表序号
切片:返回字符串一段字符子串 <字符串>[M:N]
,左开右闭
字符串切片的高级用法:
<字符串>[M,N]
,M缺失表示至开头,N缺失表示至结尾
<字符串>[M:N:K]
,根据步长K对字符串切片
字符串的特殊字符
转义符 \
转义字符表达特定字符的本意
例如:"双引号(\")" 结果为 双引号(")
转义符形成一些组合,表达一些不可打印的含义
"\b" 回退 "\n" 换行,光标移动到下行首 "\r" 回车,光标移动到本行首
r 方法原样输出
输入: str=""" ab 输出: ab
cd cd
ef ef
"""
x + y #连接两个字符串x和y
n*X 或 x*n #复制n次字符串x
x in s #如果x是s的子串,返回True,否则返回False
注意:not in 与 in 相反
len(x) #长度,返回字符串x的长度
str(x) #任意类型所对应的字符串形式
hex(x)或oct(x) #整数x的十六进制或八进制小写形式字符串
chr(x) #x为Unicode编码,返回其对应的字符
ord(x) #x为字符,返回其对应的Unicode编码
unicode编码
str.lower() 或 str.upper() #返回字符串的副本,全部字符小写/大写
str.split(sep=None) #返回一个列表,由str根据sep被分隔的部分组成
例:"A,B,C",split(",")=>['A','B','C']
str.count(sub) #返回子串sub在str中出现的次数
str.replace(old,new) #返回字符串str副本,所有old子串被替代为new
例:"python".replace("n","n123.io")=>"python123.io"
str.center(width[,fillchar]) #字符串str根据宽度width居中,fillchar可选
例:"python".center(20,'=') 结果为:
"==========python=========="
str.strip(char) #从str中去掉在其左侧和右侧char中列出的字符
例:"=python=".strip("=") => "python"
str.join(iter) #在iter变量除最后元素表外每一个元素后增加一个str
例:",".join("12345") => "1,2,3,4,5"
补充:
字符串zfill()方法,在字符串前面补0
例如:str(<需要转化为字符串的文本>).zfill(4) #补4个0
用法:<模板字符串>.format(<逗号分隔的参数>)
例如:
"{}":计算机{}的cpu占用率为{}%".format("2018-10-10","c",10)
序号: 0 1 2 0 1 2
"{1}":计算机{0}的cpu占用率为{2}%".format("2018-10-10","c",10)
#字符串槽里{}序号可自定义,匹配format()默认序号。例如:{1}为"c"
槽内部格式化的配置方法(可用于print()输出)
{<参数序号>:<格式控制标记>}
: | <填充> | <对齐> | <宽度> | <,> | <.精度> | <类型> |
---|---|---|---|---|---|---|
引导符号 | 用于填充 | < 左对齐 | 槽设定的 | 数字的4 | 浮点数小数 | 整数类型 |
的单个字符 | > 右对齐 | 输出宽度 | 位分隔符 | 精度或字符 | b,c,d,o,x,X | |
^ 居中对齐 | 串最大输出长度 | 浮点数类型 | ||||
e,E,f,% |
例如:
>>>"{0:=^20}".format("PYTHON")
'==========PYTHON=========='
>>>"{0:*>20}".format("BIT")
'****20个***BIT'
>>>"{:10}".format("BIT")
'BIT 10个空格 '
>>>"{0:,.2f}".format(12345.6789)
'12,345.68'
>>>"{0:b},{0:c},{0:d},{0:o},{);x},{0:X}".format(425)
'110101001,∑,425,651,1ag,1A9'
>>>"{0:e},{0:E},{0:f},{0:%}".format(3.14)
'3.140000e+00,3.140000E+00,3.140000,314.000000%'
补充:字符串格式化
示例:
name="小明"
print("%c"%name 同学) ===> 小明同学
if <条件>:
<语句块>
一般形式
if <条件>:
<语句块1>
else:
<语句块2>
紧凑形式:适用于简单表达式的一分支结构
<表达式1> if <条件> else <表达式2>
注意:条件正确执行表达式1,错误执行表达式2
if <条件1>:
<语句块1>
elif <条件2>: #注意:多条之间的包含关系
<语句块2> 变量取值范围的覆盖
········
else:
<语句块n>
含义:遍历某个结构形成的循环运动方式
for <循环变量> in <遍历结构>:
<语句块>
注意:
从遍历结构中遍历逐一提取元素,放在循环变量中
由保留字 for 和 in 组成,完整遍历所有元素后结束
每次循环,所获得元素放入循环变量,并执行一次语句块
计数循环
1、循环N次
for i in range(N): #遍历由range()函数产生的数字序列,产生循环
<语句块>
注意:
循环N次,变量i从0到N-1
2、循环特定次
for i in range(M,N,K): #range()产生从M到N-1的数列,以k为步长
<语句块>
字符串遍历循环
for c in s: #s是字符串,遍历字符串每一个字符,产生循环
<语句块>
列表遍历循环
for item in ls: #ls是一个列表,遍历其每个元素,产生循环
<语句块>
文件遍历循环
for line in fi: #fi是一个文件标识符,遍历其每行,产生循环
<语句块>
含义:由条件控制的循环运行方式
while <条件>: #反复执行语句块,直到条件不满足时为止
<语句块>
注意:
当条件设置不当,陷入死循环时。CTRL+C退出执行
循环与else
for <变量> in <遍历结构>: while <条件>:
<语句块1> <语句块1>
else: else:
<语句块2> <语句块2>
注意:
< #小于
<= #小于等于
>= #大于等于
> #大于
== #等于。注意:程序中“=”为赋值符号
!= #不等于
and #逻辑与
or #逻辑或
not #逻辑非
try:
<语句块1> #若语句块1异常则执行语句块2,避免出现异常提示
except:
<语句块2>
try:
<语句块1> #标注异常处理后,仅响应此类异常。异常类型名字等同于变量
except<异常类型>:
<语句块2>
try:
<语句块1>
except:
<语句块2> #finally 对应的语句块4一定执行,else对应语句块3在不发生异常时执行
else:
<语句块3>
finally:
<语句块4>
使用raise关键字可以抛出一个异常
格式:raise <异常类型> #异常类型为系统内置异常类型。后面可加具体错误与括号中
基于面向对象编程自定义
例: class <异常类型(自定义名)>(Exception):
def __init__(self,····):
pass
def __str__(self):
pass
函数是一段具有特定功能的、可重用的语句组。函数是一段代码的表示
函数是一种功能的抽象、一般函数表达特定功能
两个作用:降低编程难度和代码复用
格式:
def <函数名>(<参数,0个或多个>):
<函数体>
return <返回值>
注意:
函数定义时,所指定的参数是一种占位符
函数定义后,如果不经过调用,不会被执行
函数定义时,参数是输入,函数体是处理,结果是输出。(ipo)
函数的调用
调用过程
例:
def fact(a): #定义函数fact,返回值为变量s
s=1
····
renturn s
a=fact(10) #调用函数fact(),给定参数10.并把函数返回值s的值赋给a
print(a)
参数个数
函数可以有参数也可以没有,但必须保留括号
可选参数传递
函数定义时可以为某些参数指定默认值,构成可选参数
格式:
def <函数名>(<非可选参数>,<可选参数>):
<函数体>
return <返回值>
例:计算n!//m
def fact(n,m=1):
s=1
for i in range(1,n+1):
s*=i
return s//m
注意:m为可选参数,但调用fact()函数而不给m参数传值时,默认m=1
可变参数传递
函数定义时可以设计可变数量参数,即不规定参数总数量
格式:
def <函数名>(<参数>,*b):
<函数体>
return <返回值>
例:计算n!
def fact(n,*b):
······
return s
调用:
fact(10,3)
fact(10,3,5,8)
列表、字典作为参数传递,巧用*号
参数前面加上*
号 ,意味着参数的个数不止一个,另外带一个星号*
参数的函数传入的参数存储为一个元组(tuple
),带两个*
号则是表示字典(dict
)
def t1(param1, *param2): def t2(param1, **param2):
print(param1) print param1
print(param2) print param2
t1(1,2,3,4) t2(1,a=2,b=3)
输出: 输出:
# 1 # 1
# (2,3,4) # {a:2, b:3}
此外,一个*号还可以解压参数列表: 同时使用*和**
def t3(p1, p2): def t4(a, b=10, *args, **kwargs):
print(p1, p2) print(a)
args = [1, 2] print(b)
t3(*args) print(args)
输出 print(kwargs)
# 1 2 t4(1, 2, 3, 4, e=5, f=6, g=7)
输出:
# 1
# 2
# 3 4
# {'e': 5, 'g': 7, 'f': 6}
参数传递的方法
参数传递方法有两种,位置传递和名称传递。
例:
def fact(n,m=1):
······
return s//m
调用:
fact(10,5) #位置传递
fact(m=5,n=10) #名称传递
含义:局部变量是指仅在程序局部(例如一个函数内部)起作用,全局变量变量是指在整个程序任何地方都起作用即可以影响全局
<语句块1> #定义在语句块1、2中的全局变量可以被函数内部调用
def <函数名>(<参数>): #定义在函数体内的局部变量只能被函数内部调用
<函数体>
return <返回值>
<语句块2>
注意:
局部变量是函数内部的占位符,与全局变量可能重名但不同
函数运算结束后,局部变量被释放
可以使用global 保留字在函数内部使用全局变量
规则1:局部变量和全局变量是不同变量
例
n,s=10,100
def fact(n):
s=1 #fact()函数中s是局部变量与全局变量s不同
for i in range(1,n+1):
s*=i
return s #局部变量s
print(fact(n),s) #全局变量s
n,s=10,100
def fact(n):
global s #fact()函数中使用global保留字声明此处是全局变量S
······
return s #此处s指全局变量
print(fact(n),s) #此处全局变量被函数修改
规则2:局部变量为组合数据类型且未创建,等同于全局变量
例
ls=["F","f"] #真实创建全局变量列表
def func(a):
ls.append(a) #此处ls是列表类型且未真实创建(指在函数内部未真实创建),等同于全局变量
return
func("c")
print(ls) #输出结果:["F","f","c"]
ls=["F","f"] #真实创建全局变量ls
def func(a):
ls=[]
ls.append(a) #此处ls为真实创建的列表类型,局部变量
return
func("c")
print(ls) #运行结果:["F","f"]
注意:lambda函数返回函数名作为结果
格式
<函数名>=lambda<参数>:<表达式>
等价于
def <函数名>(<参数>):
<函数体>
return <返回值>
例
f=lambda x,y:x+y
f(10,15) #结果为25
f=lambda : "lambda函数"
print(f()) #结果为:lambda函数
注意:
lambda函数有一些固定的使用方法,建议逐步掌握
lambda函数主要用作一些特定函数的或方法
一般情况下,建议用def定义普通函数
pyhon2内置类,python3改为内置函类
作用:对可迭代对象进行过滤,得到一个filter对象(可迭代)
用法:filter可以给定两个参数,第一个参数是函数,第二个参数是可迭代对象
例:
age=[12,23,30,17,16,22,19]
x=filter(lambda ele:ele>18,ages)
print(x) ==> <filter object at 0x000002670373E908>
for a in x:
print(a) ==> 23 30 22 19
adult=list(x)
print(adult) ==> [23,30,22,19]
内置类
作用:对可迭代对象中的每个元素,进行函数(参数)操作。与filter类似
例:
ages=[12,23,30,17,16,22,19]
m=map(lambda ele:ele+2,agee)
print(list(m)) ==> [14,25,32,19,18,24,21] #m为可迭代对象
内置函数,from functools import reduce
例:
def foo(x,y): #对列表中的数进行累加
return x+y #第一次:x=100.y=89
scores=[1000,89,76,87] #第二次:x=189,y=76,依照此规律依次累加
print(reduce(foo,scores)) ==> 352(第四次:265+87)
students=[
{'name':'zhangsan','age':'18':'score':'98'},
{'name':'lisi','age':'21':'score':'97'},
{'name':'jack','age':'22':'score':'100'}
]
def bar(x,y):
return X+y['age']
print(reduce(bar,students,0)) #0为x初始值
sort方法排序
例:
nums=[4,8,2,1,7,6]
nums.sort() #列表的sort方法,直接对列表进行排序
print(nums) ===> [1,2,4,6,8]
sorted,内置函数,不改变原有数据,而生成一个新的有序的列表
ints=(5,9,2,3,1,3,8,7,4)
x=sorted(ints)
print(ints) ===> (5,9,2,1,3,8,7,4)
print(x) ====> [1,2,3,4,5,6,7,8,9]
注意
例:
students=[{'name':'zhangsan','age':18,'score':98},
{'name':'lisi','age':21,'score':97},
{'name':'jack','age':22,'score':100},
{'name':'tony','age':20,'score':90}
]
def foo(ele): #foo函数可无参数,但调用时,在sorta()内部传递了一个参数给foo
return ele['age']
students.sort(key=ele) #在sort内部实现时,调用foo方法,传入一个参数,参数为列表元素
#利用匿名函数,简化上述函数
students.sort(key=lambda ele:ele['age'])
高阶函数有三种形式
一个函数作为另一个函数的参数。例:lambda函数的使用
把一个函数当作另一个函数的返回值
例:
def test(): def demo(): def bar():
print('我是test函数') print('我是demo函数') print('我是bar函数')
retuen 'hello' return test return test()
x=test;print(x) ==> 我是test函数 hello
y=demo() #y是test函数 print(a=bar()) ==> hello
z=y();print(z) ==> hello
在一个函数中定义另一个函数(即函数的嵌套)
def outer(x):
print('我是outer函数')
def inner(): #inner函数是定义在函数内部的函数
print('我是inner函数')
if x>18:
inner()
return 'hello'
print(12) ==> 我是outer函数
print(21) ==> 我是outer函数
我是inner函数
概念:由函数及其相关的引用环境组合而成的实体(闭包=函数块+引用环境)
构成条件:函数嵌套,外部函数返回内部函数。
如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就认为是闭包
例
def outer():
x=10
def inner():
nonlocal x #nonlocal关键字调用外部函数变量
y=x+1
print('inner里的y=',y)
x=20 #若无nonlocal调用,此处则为创建一个新变量X
return inner
print(outer()()) ==> 11
定义:利用闭包实现功能,使用@(语法糖)符号
例:计算程序耗时
import time
def cal_time(fn):
def inner(): #可加参数 inner(x)
start=time.time()
fn() #s=fn(x)
end=time.time()
print('代码耗时',end - start)
return inner #return x
@cal_time #调用cal_time,并把被修饰的函数传递给fn
def demo(): #x传给demo(),即demo(x)。还可写多个参数
x=0 #再次调用demo()函数时,此时demo()函数不再是原来的demo()
· #而是cal_time中内部函数inner,cal_time中fn()为demo()函数
·
·
装饰器的高级使用
开发中:开放封闭原则,利用装饰器,在不改变功能模块源码的前提下,扩展功能。
例:
def can_play(fn):
def inner(x,y,*args,**kwargs):
if args[0]<=22:
f(n)(x,y)
else:
print('太晚了,赶紧睡')
return inner
@can_play
def play_game(name,game):
print('{}正在玩{}'.format(name,game))
play_game('张三','王者荣耀',18)
改进:
clock=kwargs['clock']
if clock<=22:
·
·
play_gane('李四','绝地求生',clock=18) #参数(clock=18)在kwargs保存为键值对
#若无clock参数会报错,解决方案如下:
clock=kwargs.get('clock',23) #若无clock为空值,使用默认值(23)
代码复用——把代码当成资源进行抽象
代码资源化:程序代码是一种用来表达计算的“资源”
代码抽象化:使用函数等方法对代码赋予更高级的定义
代码复用:同一份代码在需要时可以被重复使用
函数和对象是代码复用的两种主要形式
函数:将代码命名在代码层建立了初步抽象
对象:属性和方法.和()在函数之上再次组织进行抽象
抽象级别:对象大于函数
模块化设计——分而治之
通过函数或对象封装将程序划分为模块及模块间的表达
具体包括:主程序、子程序和子程序间的关系
分而治之:一种分而治之、分层抽象,体系化的设计思想
紧耦合:两个部分之间交流很多,无法独立存在
松耦合:两个部分之间交流较少,可以独立存在 #模块内部紧耦合,模块间松耦合
递归的定义——函数定义中调用函数自身的方式
两个关键的特征
链条:计算过程存在递归链条
基例:存在一个或多个不需要再次递归的基例
类似数学归纳法
数学归纳法
证明当n取第一个值 n 0 n_0 n0时命题也成立
假设当 n k n_k nk时命题成立,证明n=nk+1时命题也成立
递归是数学归纳法思想的编程体现
函数递归的调用过程
例:
n ! = { 1 , n = 0 n ( n − 1 ) ! , o t h e r w i s e n!=\begin{cases} 1,n=0 \\ n(n-1)!, otherwise\end{cases} n!={1,n=0n(n−1)!,otherwise
def fact(n):
if n==0: #基例
return 1
else:
return n*fact(n-1) #递归链条
递归的实现——函数+分支语句
注意:递归本身是一个函数,需要函数定义方式描述
函数的内部,采用分支语句对输入参数进行判断
基例和链条,分别编写对应代码
过程:
fact(5) ==>fact(4) ==>fact(3) ==>fact(2) ==>fact(1) ==fact(0)
120 <== 24 <== 6 <== 2 <== 1 <== 1
递归实例
例:字符串反转输出
def rvs(s):
if s=="":
return s
else:
return rvs(s[1:])+s[0]
斐波那契数列——F(n)=F(n+1)+F(n-2)
def f(n):
if n==1 or n==2:
return 1
else:
return f(n-1)+f(n-2)
hashlib
两个重要算法:md5和sha加密
方法:单向加密:只有加密过程,不能解密 md5/sha
对称加密
非对称加密:rsa
md5加密 #需要将要加密内容转化为二进制
例:
x=hashlib.md5() #生成一个md5对象
x.update('abc'.encode('utf8')) #括号内将'abc'转化为二进制,utf-8编码
print(x.hexdigest()) #x为md5对象,其后面的方法将其转化为十六进制数字
sha加密
例:
h1=hashlib.sha1('123456'.encode())
h2=hashlib.sha224('123456'.encode()) #sha后面的数字表示加密长度,安全性高于md5
print(h2.hexdigest()) #生成的十六进制数共56位,一位十六进制占224中的4位,
#224/56=4,相当于4位二进制
hmac
特点:hmac加密可以指定秘钥
例:
h=hmac.new('h'.encode(),'你好'.encode()) #'h'为秘钥
result=h.hexdigest()
print(result) #获得加密的结果
概述
模块本质是一个py文件
模块命名规则:由数字、字母下划线组成,不能以数字开头
导入一个模块就能使用这个模块的变量和函数
注意
使用:from <模块名> import* 本质上读取模块里的_ all_属性
例:
_all_=['m','test']
m='yes'
n=100
以一个下划线开始的变量,建议只在本模块里使用,不导入其他模块。强制性禁止使用变量
例:
def _bar():
pass
del bar #删除bar
del (bar,···,···,) #可删元组
_name _
当直接运行这个py文件(模块)的时候,值是_ main_
如果这个py文件作为一个模块导入的时候,值是文件名
例:
if _name_=='_main_':
程序 #只有直接运行这个py文件时才会执行程序
概述
包(多个模块集合)是一个可将多个具有相似或都有关联的多个模块放到一个文件夹,这个文件夹即为包
注意
python包里会有一个_init _.py文件
例:
<包>
_init_.py
x.py ==> _init_.py中 ==> import <包>
p.py from . import X 可直接调用x模块
直接调用类里的方法,需要自定义方法别名
class <类名>: 例:
def <方法1>: def eat(): #在p类里定义eat方法
····
def <方法2>: eat=p.eat #在类里为eat方法取别名eat
直接调用:
_p=<类名> #创建对象,_表示对象私有化
<方法1别名>=_p.<方法1> #给方法1起别名
可迭代对象例如:list/tuple/dict/set/str/range/filter/map
for ····· in循环的本质是调用了可迭代对象的 _ _ iter _ _ 方法,获取到这个方法得到返回值。这个返回值是一个对象,然后再调用这个对象 _ _ next _ _ 方法
例:
class Foo(object):
def __next__(self): #__next__可与iter方法写在同一个类里
return 1
class Demo(object):
def __init__(self,x):
self.x=x
def __iter__(self):
f=Foo()
return f
d=Demo(100)
for i in d:
print(x) #调用next方法,打印1
优化例子:
class Demo(object):
def __init__(self):
self.x=x
self.count=0
def __iter__(self,x):
return self
def __next__(self):
self.count+=1
if self.count<=self.x:
return 'hello'
else:
raise stopIteration #迭代器停止
修改例子
return 'hello' 改为 return self.count-1
for i in Demo(10):
print(i)
注意:
d=Demo(10)
#运行过程
i=d.__iter__()
i.__next__()
i=iter(d) #内置函数iter可以获取到一个可迭代对象的迭代器
第一个 print(next(i))=0,第二个为1
定义:一个实现了iter方法和next方法的对象,就是迭代器
demo
例:斐波那契数列的迭代器实现
class Fibonacci(object):
def __init__(self,n):
seelf.n=n
self.num1=self.num2=1
self.count=0
def __iter__(self):
return self
def __next__(self):
self.count+=1
if self.count<=self.n:
x=self.num1
self.num1,self.num2=self.m2,self.num1+self.num2
return x
else:
raise stopcteration
生成器本质上是一个特殊的迭代器
例:
nums=[i for i in range(10)] #列表生成式(推导式)/字典推导式·····
print(nums) ===> [0,1,2,3,4,5,6,7,8,9]
g=(i for i in range(10)) #g为生成器
for i in g:
print(i) #依次打印结果:===> 0 2 3 4 5 6 7 8 9
是一个对象,定义class。生成器在写法上像一个函数。
例:
def my_gen(n):
i=0
while i < n:
yield i #yield关键字将函数变成生成器
i+=1 #执行yeild i 后,执行这一步
G=my_gen(10)
for i in G:
集合类型与数学中的集合概念一致
集合元素之间无序,每个元素唯一,不存在相同元素
集合元素不可更改,不能是可变数据类型
集合用大括号{}表示,元素间用逗号分隔
建立集合类型用{}或set()
建立空集合类型,必须使用set()
>>>A={"python",123,("python",123)}
{123,"python",("python",123)}
>>>B=set("pypy123")
{'1','p','2','3','y'}
s|t #并,返回一个新集合,包括在集合s和t中的所有元素
s-t #差返回一个新集合,包括在集合s但不在集合t中的元素
s&t #交,返回一个新集合,包括同时在集合s和t中的元素
s^t #补,返回一个新集合,包括集合s和集合t中的非相同元素
s<=t或s
s>=t或s>t #返回True/False,判断s和t的包含关系
4个增强操作符
s|=t #并,更新集合s,包括在集合s和t中的所有元素
s-=t #差,更新集合s,包括在集合s但不在t中的元素
s&=t #交,更新集合s,包括在集合s但不在t中的元素
s^=t #补,更新集合s,包括集合s和t中的非相同元素
s.add(x) #如果x不在集合s中,将x增加到s
s.discard(x) #移除s中元素x,如果x不在集合s中,不报错
s.remove(x) #移除s中元素x,如果x不在集合s中,产生keyError
s.clear() #移除s中所有元素
s.pop() #随机返回s的一个元素,更新s,若s为空产生keyError异常
s.copy() #返回集合s的一个副本
len(s) #返回s的元素个数
x in s #判断s中元素x,x在集合s中,返回True,否则返回False
x not in s #判断s中的元素x,x不在集合s中,返回True,否则返回False
set(x) #将其他类型变量转变为集合类型
序列类型:字符串类型,元组类型,列表类型
序列的定义
-5 -4 -3 -2 -1 #反向递减序号
"BIT" 3.1415 1024 (2,3) ["中国",9]
0 1 2 3 4 #正向递增序号
通用操作符
x in s #如果x是序列s的元素,返回True,否则返回False
x not in s #如果是序列s的元素,返回False,否则返回True
s+t #链接两个序列s和t
s*n或n*s #将序列s复制n次
s[i] #索引,返回s中第i个元素,i是序列的序号
s[i:j]或s[i:j:k] #切片,返回序列s中第i列,以k为步长的元素子序列
5个函数和方法
len(s) #返回序列s的长度,即元素个数
min(s) #返回序列s的最小元素,s中元素需要可比较
max(s) #返回序列s的最大元素,s中元素需要可比较
s.index(x)或s.index(x,i,j) #返回序列s从i开始到位置中第一次出现元素x的位置
s.count(x) #返回序列s中出现k的总次数
元组是一种序列类型,一旦创建就不能被修改,是序列类型的一种拓展
使用小括号()或tuple()创建,元素间用逗号分隔
可以使用小括号或不使用小括号
例:
>>>creature='cat','dog','tiger','human'
>>>creature
('cat','dog','tiger','human')
ls[i]=x #替换列表ls第i元素为x
ls[i:j:k]=lt #用列表lt替换ls切片后所对应元素子列表
del ls[i] #删除列表ls中第i元素
del [i:j:k] #删除列表ls中第i到第j以k为步长的元素
ls+=lt #更新列表ls,将列表lt元素增加到列表ls中
ls*=n #更新列表ls,其元素重复n次
len(ls) #列表长度
ls.append(x) #在列表ls最后增加一个元素x
ls.clear #删除列表ls中所有元素
ls.copy() #生成一个新列表,赋值ls中所有元素
ls.insert(i,x) #在列表ls的第i位置增加元素x
ls.pop(i) #将列表第i为位元素取出并删除该元素
ls.remove(x) #将列表ls中出现的第一个元素x删除
ls.reverse() #将列表ls中的元素反转
ls.count() #统计列表ls中出现同一元素出现次数
ls.sort() #对列表排序
ls.index() #从列表中找到第一个匹配项索引位置
list(seq) #强制转换元组seq为列表类型
max()/main() #返回最大值/最小值
cmp(list1,list2)#python2中比较两个列表得到元素
调用copy方法(列表自带),可以复制一个列表内容,但新列表与原列表指向不同内存空间
例:
x=[100,200,300]
y=x #等号是内存地址的赋值。x、y指向同一个内存空间,会相互影响
z=x.copy()
x[0]-=1
print(y) ===> [99,200,300]
print(z) ===> [100,200,300]
使用copy模块
例:
import copy
a=copy.copy(x) #等价于 a=x.copy()
例:
words=['hello','good',[100,200,300],'yes','NO']
words1=words.copy() #1、浅拷贝,可以认为只拷贝了一层(一维)
words=[2][0]=1
print(words1) ==> ['hello','good',[1,200,300],'yes','NO']
word2=copy.deepcopy(words)
words=[2][0]=1
print(word2) ==> ['hello','good',[100,200,300],'yes','NO']
for item in ls: for item in tp:
<语句块> <语句块>
如果不希望数据被程序改变,转换成元组类型
例:
>>>ls=['a','b','c']
>>>lt=tuple(ls)
>>>lt
('a','b','c')
映射是一种键(索引)和值(数据)的对应
例:内部颜色为蓝色,外部颜色为红色
映射关系: (键) ( 值)
内部颜色:蓝色
外部颜色:红色
序列类型由0···n整数作为数据的默认索引
映射类型则由用户为数据定义索引
字典是“映射”的体现:
例:
{<键1>:<值1>,<键2>:<值2>,<键3>:<值3>,········,<键n>:<值n>}
在字典变量中,通过键获得值
例:
<字典变量>={<键1>:<值1>,<键2>:<值2>,·····,<键n>:<值n>}
<值>=<字典变量>[<键>] <字典变量>[<键>]=<值>
#[]用来向字典变量中索引或增加元素
例:
>>>d={'中国':'北京','美国':'华盛顿'}
>>>d['中国']
'北京'
>>>de={};type(de) #type(x),返回x的类型
<class 'dict'>
del d[k] #删除字典d中键k对应的数据值
k in d #判断键k是否在字典d中,如果在返回True,否则返回False
d.keys() #返回字典d中所有的键信息
d.values() #返回字典d中所有的值信息
d.items() #返回字典中所有的键值对信息
例:
>>>d={'中国':'北京','美国':'华盛顿'}
>>>'中国' in d
True
>>>d.values()
dict_values ['北京','华盛顿']
d.get(k,<default>) #键k存在,则返回相应值,不存在则返回值
d.pop(k,<default>) #键k存在,则取出相应值,不存在则返回值
d.popitem() #随机从字典中取出一个键值对,以元组形式返回
len(d) #返回字典d中元素的个数
d.clear() #删除所有的键值对
例:
>>>d={'中国':'北京','美国','华盛顿'}
>>>d.get('中国','伊斯兰堡')
'北京'
>>>d.get('巴基斯坦','伊斯兰堡')
'伊斯兰堡'
>>>d.popitem()
('中国','北京')
映射无处不在,键值对无处不在
例如:统计数据出现的次数,数据是键,次数是值
最主要的作用:表达键值对数据,进而操作他们
例:
for k in d:
<语句块>
文本文件—文件是数据的抽象和集合
由单一特定编码组成的文件,如utf-8编码
由于存在编码,也被看成是存储着的长字符串
适用于例如:.txt文件、.py文件等
二进制文件
文本文件与二进制文件区别
例: f.txt 文件保存:"中国是伟大的国家!"
#文本的形式打开文件
tf=open("f.txt","rt")
print(tf.readline())
tf.close()
输出:中国是伟大的国家
#二进制形式打开文件
bf=open("f.txt","rb")
print(bf.readline())
tf.close()
输出:b'\xd6\xd0\xb9\xfa\xca\xc7\xb8·····
文件的处理步骤:打开=>操作=>关闭
文件的存储状态----(a=open())---->文件占用状态----(a.close())—>文件储存状态
<变量名>=open(<文件名>,<打开模式>)
<变量名> #文件句柄
<文件名> #文件路径和名称(源文件同目录可省路径)
<打开模式> #读or写, 文本or二进制
例:文件路径
"D:/PYE/f.txt" "./PYE/f.txt"
"D:\\PYE\\f.txt" "f.txt"
'r' #只读模式,默认值,如果文件不存在,返回FileNotFoundError
'w' #覆盖写模式,文件不存在则创建,存在则完全覆盖
'x' #创建写模式,文件不存在则创建,存在返回FileExistsError
'a' #追加写模式,文件不存在则创建,存在则在文件最后追加内容
'b' #二进制文件模式
't' #文本文件,默认值
'+' #与r/w/x/a一同使用,在原功能基础上增加同时读写功能
例:
f=open("f.txt") #文件形式,只读模式、默认值
f=open("f.txt","rt") #文件形式,只读模式、同默认值
f=open("f.txt","a+") #文件形式,追加模式+读文件
f=open("f.txt","b") #二进制形式,只读模式
f=open("f.txt","wb") #二进制形式,覆盖写模式
<变量名>.close() #<变量名>为文件句柄
file.seek(0,0) #重置指针,回到开头
<文件名>.rpartition('.') #rartition中'r'表示从右边第一个点往右切分
例:
sss.txt.rpartition('.') ==> ('sss','.','txt')
<f>.read(size=-1) #读取全部内容,如果给出参数,读入前size长度
例: >>>s=f.read(2)
中国
<f>.readline(size=-1) #读入一行内容,如果给出参数,读入该行前size长度
例:
>>>s=f.readline()
['中国是一个伟大的国家']
#一次读入,统一处理
fname=input("请输入要打开的文件名称:")
fo=open(fname,"r")
txt=fo.read()
f.close()
#按数量读入,逐步处理
fname=input("请输入要打开的文件名称:")
fo=open(fname,"r")
text=fo.read(2) #对txt进行处理
while txt !=" ": #对txt进行处理(改进)
txt=fo.read(2)
fo.close
#一次读入,分行处理
fname=input("请输入要打开的文件名称:")
fo=open(fname,"r")
for line in fo.reaadlines():
print(line)
fo.close()
#分行读入,逐行处理
fname=input("请输入要打开的文件名称:")
fo=open(fname,'r')
for line in fo:
print(line)
fo.close()
<f>.write(s) #向文件写入一个字符串或字节流
<f>.writelines(lines) #将一个元素全为字符串的列表写入文件
例:
>>>ls=['中国','法国','美国']
>>>f.writelines(ls)
中国法国美国
<f>.seek(offset) #改变当前文件操作指针的位置
#offset含义如下:
0-文件开头
1-当前位置
2-文件结尾
例:
>>>f.seek(0) #回到文件头
注意:初始状态,文件指针一般在文件文件结尾
with关键字称为上下文管理器,很多需要手动关闭的连接,比如文件连接、socket连接、数据库连接,都可以使用with关键字自动关闭
with关键字后面对象,需要实现_ _ enter _ _ 和 _ _ exit _ _魔法方法
当进入with代码块时,会调用 _ _ enter _ _ 方法,当with代码块执行完后,会自动调用 _ _ exit _ _方法,完成需求
例:
with open(文件名,'r') as file:
file.read()
数据的操作周期:存储<=>表示<=>操作
数据存储(存储格式)<----->数据表示(数据类型)<---->数据操作(操作方式)
存储方式一:空格分隔
使用一个或多个空格分隔进行存储,不换行
缺点:数据中不能存在空格
例: 中国 美国 日本 德国 法国
存储方式二:逗号分隔
存储方式三:其他方式
存储(表示)
一维数据的读入处理
从空格分隔的文件读入数据(示例)
例: 中国 美国 日本 德国 法国
txt=open(fname).read()
ls=txt.split() #若用特殊符号分隔括号内特殊符号
f.close()
>>>ls
['中国','美国','日本','德国']
一维数据的写入处理
采用空格分隔方式将数据写入文件
ls=['中国','美国','日本']
f=open(fname,'w')
f.write(''.join(ls)) #若采用特殊符号分隔,例:f.write('$'.jinn(ls))
f.close()
使用列表类型
列表类型可以表达二维数据
使用二维列表
例: [[3.14,3.16,3.18]
[3.15,3.17,3.19]]
使用两层for循环遍历每一个元素
外层列表元素可对应一行也可对应一列
CSV:comma-separated values
国际通用的一二维数据存储格式,一般.CSV拓展名
每行一个一维数据,采用逗号分隔,无空行
Excel和一般编辑软件都可以读入或另存为CSV文件
例:
表格数据: 城市······· CSV存储数据: 城市,环比, 同比
北京······· 北京,101.5,120.7
· 上海 ,101.2,127.3
·
注意:
如果某个元素缺失,逗号仍要保留
二维数据的表示可以作为数据存储,也可以另行存储
逗号为英文半角逗号,逗号与数据之间无额外空格
二维数据的读入处理
从CSV格式文件中读入处理
例:
fo=open(fname)
ls=[]
for line in fo:
line=line.replace('\n',' ')
ls.append(line.split(','))
f.close()
二维数据的写入处理
将数据写入CSV格式的文件
ls=[[ ],[ ],[ ]] #三维列表
f.open(fname,'w')
for item in ls:
f.write(','.join(item)+'\n')
f.close()
二维数据的逐一处理
采用二层循环
ls=[[1,2],[3,4],[5.6]] #二维列表
for row in ls:
for column in row:
print(column)
CSV文件读写
写:
import ssv #系统内置模块
file=opennn(文件名,'w',encoding='utf8',newline=' ') #打开一个文件
w=csv.writer(file)
w.writerow([列表数据]) #写入数据,列表可以是多维的
读:
file=open·····
r=csv.reader(file)
for data in r:
逐行读取····
将数据写入内存:
使用StringIO、BytesIO两个数学模块
from io import StringIO/BytesIO
dumps:将数据转化成为json字符串,不会将数据保存到文件里
dump:将数据转换为json字符串的同时写入指定文件
例:json.dump(字符串,文件名)
Loads:将json字符串加载为python里的数据。例:json.Loads(字符串)
Load:读取文件,把读取的内容加载为python里的数据
例:
file=open(文件名,'r',encoding='utf8')
json.Load(file)
序列化:dumps、dump,将python数据转化为二进制
反序列化:loods、lood
例:
pickle.dumps(需要转化为字符串的数据) #方法与json方法类似
类是对一群具有相同特征或行为的事务的一个统称,是抽象的,不能直接使用
由类创建出来的一个具体的存在,可以直接使用。由哪一个类创建出来的对象,就拥有在哪一个类中定义的属性和方法
**注意:**每次创建对象都会调用_ _init _ _ 方法和 _ _new _ _方法
定义类:使用Class
格式:class <类名>: #类名一般需要遵守驼峰命名法,内一个单词首字母大写
class <类名>(object):
例:小明今年18岁,身高1.75,每天早上跑完步,会去吃东西
小美今年17岁,身高1.65,小美不跑步,小美喜欢吃东西
class Student(object): #关注这个类有哪些属性和行为
def __init__(self,name,age,height): #在__init__方法里,以参数形式定义属性
self.name=name
self.age=age
self.height=height
#行为定义另一个函数(方法)
def run(self):
print('正在跑步')
def eat(self):
print('正在吃东西')
#student() 会自动调用__init__方法
s1=Student('小明','18','1.75') #使用Student类创建了两个实例对象s1、s2
s2= Student('小美','17','1.65')
#根据业务逻辑,让不同的对象执行不同的行为
s1.run() s1.eat() s2.eat()
例:
class Student(object):
def __init__(self,x,y):
self.name=x
self.age=y
s1=Student('张三','18') #s1.name ==> 张三
执行流程:
1、调用__new__方法,申请一段内存空间
2、调用__init__方法,让self指向申请好的那段内存空间
3、让s1也指向创建好的这段内存空间
#可使用"="直接为属性赋值,若这个属性不存在会给对象添加一个新的属性
例: s1.city='上海' #动态属性
__slots__=() #这个属性直接定义在类里,为一个元组,用来规定对象可以存在的属性
定义
类里的一些特殊的方法
特点
种类
__init__ #在创建对象时,会自动调用
__del__ #当对象被报销时,会自动调用这个方法
__repr__ #当打印一个对象的时候,会自动调用这个对象的__ str__ 或者 __repr__方法
__str__ #当两个方法都存在时,__str__优先。打印列表,调用__repr__方法
__eq__ #运算符相关魔法方法
注意: #str()将对象转换为字符串,会自动调用__str__方法
#str(p1)/print(p1),转换成为字符串,默认会转化类型+内存地址
例:
class Parson(object):
def __init__(self,name,age):
self.name=name
self.age=age
#p1、p2是不同对象,指向内存不同
p1=Person('张三','18')
p2=Person('张三','18')
print('p1 is p2',p1 is p2) #False,is运算符,可判断两个对象是否为同一对象
print('p1==p2',p1==p2) #False,'=='本质调用__eq__方法,获取这个方法的返回值
#注意:如果__eq__不重写,默认比较内存地址
注意
例:
class Person():
·
·
def __call__(self,**args,**kwargs):
print('args={},kwargs={}'.format(args,kwargs))
fn=kwargs['fn']
return fn(args[0],args[1])
p=Person(····)
print(reprcp) #调用内置函数repr会触发对象的__repr__方法
print(p.__repr__) #手动调用,魔法方法一般不手动调用
n=p(1,2,fn=lambda x,y;x+y) #对象名()<=>调用这个对象的<对象名>.__call__()方法
print(n) ==>3
算术运算符相关魔法方法
__ne__ #not eq,取反
__gt__ #greater than,使用>运算符自动调用
__ge__ #使用>=运算符自动调用
__lt__ #less than p1
__le__ #<=
__add__ ##
__sub__ #-
__null__ #*
例:
def __<运算符>__(self.other):
········
p1<运算>2 #return self.name<运算符>other.name
p1<运算>p2 #return self.name<运算>other.name
重写__eq__方法:
def __eq__(self,other):
#if self.name==other.name and self.age==other.age:
# return True
#return False
return self.name==other.name and self.age==other.age
p1=Person('张三',18) ==> print(p1 is p2) #False
p2=Person('张三',18) ==> #True,重写,获取返回值
print(p1 != p2) #False,本质上调用重写的__eq__方法,或__ne__取反
print(dir(p)) #p为一个对象,打印所有属性和方法
__class__ #属于那个类
__dict__ #把对象属性和值换为一个字典
__dir__ #等价于dir(p)
__doc__ #用来查看文档注释,格式: 方法(对象名/类名).__doc__
__module__ #打印 ==> __main__ 模块名
__slots__ #需要自己定义,规定对象所含属性
__dict__ #将对象转换为字典(属性转换为字典),但不能直接把对象当字典用。<>.__dict__
__setitem__ #[]语法会调用对象的__setitem__方法
__getitem__ #[]语法自动调用,使对象可通过字典操作
例:
class Person(object):
def __init__(self,name,age,city):
self.name=name
self.age=age
self.city=city
(1) p=Person('张三',18,'襄阳')
print(p.__dict__) #{'name':'张三','age':·····}
def __setitem__(self,key,value):
p.__dict__[key]=value
(2) p['age']=20 #[]调用__setitem__方法,修改对象age为20
def __getitem__(self,item):
return self.__dict__[item]
(3) print(p['name']) #张三
对象p1、p2是通过Person类创建的实例对象
p1=Person('张三',18) #类person、对象p1、p2分别有单独不同的储存空间
p2=Person('李四',19) #name、age是对象属性,是每一个实例对象都会单独保留一份属性,
#每个实例对象互不影响
注意:对象属性,在__init__方法里,以参数形式定义
类属性(定义在类里、函数之外)
类属性直接在类里定义(不在 __init _ _ 及其他方法里定义)
class Person(object):
type='人类':
类属性可以通过类和实例对象获取
print(Person.type) ==> 人类
print(P1.type) ==> 人类 #p1(实例对象)无type属性,但可从类内存中找到类属性,
#但不可修改类属性
类属性只能通过类和实例修改
p1.type='human' #仅在p1内存中新建type='human'属性,不修改其属性
Person.type='monkey' #修改了类属性
定义:以两个下划线开始的变量是私有变量
例:
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
self.__money=100 #__开头,私有变量
注意:可在类里调用私有变量,调用函数获得私量
def test(self): #类里定义函数/方法
self.__money+=10 #此外私有变量可直接获取
获取私有变量
print(p.__money) #不能直接获取
print(p._Person__money) #使用"对象._类名__私有变量名"获取
定义get和set方法来获取(私有变量在类内容可调用)
(1)在类内部定义
def get_money(self):
return self.__money
print(p.get_money())
(2)修改私有变量,在类内部定义
def set_money(self,qian):
self.__money=qian
p.set_money #修改变量
私有函数(方法)
例:在Person类中(同前面Person方法),定义方法
def eat(self,food): #存储在类内存中
print(self,name+'正在吃'+food)
p1=Person('张三',18)
p1.eat('红烧牛肉面') #实例对象在调用方法时,不需要给形参self传参,
#会自动把实例对象传递给self,直接使用实例对象调用方法
#1、eat对象方法,可直接使用"<实例对象>.方法名(参数)"调用,使用此方法
#不需要传递self,会自动将对象名传递给self
#2、还可用<类名>.(方法名),这种方式,不会自动给self传参,需要手动的指定self
例:
Person.eat(p1,'西红柿鸡蛋盖饭') #将p1传给了self
注意:
如果一个方法里没有用到实例对象的私有属性,可将这个方法定义成static
例:
@static method
def demo(): #定义在类内部
pass
静态方法(即用不到实例对象,也用不到类)
例:
class calculator(object):
@static method
def add(a,b):
return a+b
calculator.add(1,4) #或者c=calculator,c.add(1,4)
#本质上可认为把一些函数方法,打包放到类中,
#用面向对象的方法来调用(但这些函数,方法不使用对象的任何属性)
类方法
可以使用实例对象和类对象调用
例:在类Person中
@classmethod
def test(cls): #如果这个函数只用到了类属性,我们可以定义成类方法
pass #cls指类(类对象),类方法会有一个参数cls,会自动传参
例:
class Sigleton(object):
instance=None #类属性,也可定义为私有属性
__is_first=Ture #s私有属性
@classmethod
def __new__(cls,*args,**kwargs):
if cls.instance is None:
#申请内存,构建一个对象,并把对象的类型设置为cls
cls.instance=object.__new__(cls)
return cls.instance
def __init__(self,a,b):
if self.__is_first:
self.a=a
self.b=b
self.__is_frist=False
s1=Singleton('呵呵','嘿嘿嘿')
#调用__new__方法,会调用object的__new__方法,object的__new__方法会申请内存,
#如果重写了__new__方法,需要手动申请内存
s2=Singleton('哈哈','嘻嘻嘻')
#s2不会重新申请内存,而是与s1共用一个内存,
#若__init__方法无if语句,s2中'哈哈','嘻嘻嘻'会覆盖s1中的'呵呵','嘿嘿嘿'
is
身份运算符,用以比较是否为同一对象,实质上是获取两个对象内存地址(id(对象1)==id(对象2))进行比较
type(对象名(实际)) #获取类,type(对象名)==类名,判断该对象是否由类创建
isinstance
内置函数(方法),用来判断一个对象是否由指定的类(或父类)实例化出来的。
格式:
isinstance(对象名,类名) #返回值为True/False,isinstance(对象名,类1,类2,······)
issubclass
内置函数(方法),用来判断一个类是否为另一个类的子类
格式:
insubclass(类名,可能父类) #返回值True/False,issubclass(类名,(可能父类1,可能父类2,·····))
面向对象编程有三大特征:封装、继承、多态
封装:函数是对语句的封装;类是对函数和变量的封装
继承:类和类之间可以认为手动的建立关系,父类的属性和方法,子类可以使用
多态:是一种技巧,提高代码的灵活度
例:
class Animal(object): #父类,基类
def __init__(self,name,age):
self.name=name
self.age=age
def sleep(self):
print(self.name+'正在睡觉')
class Dog(Animal): #子类,派生类。继承父类的__init__和sleep方法
def bark(self):
print(self.name+'正在叫')
d1=Dog() #Dog()调用__new__方法,再调用__init__方法。Dog中重写__new__方法,
#会查找父类。直到找到object
d1=Dog('大黄',3) #调用__init__(如new方法一样)
d1.name ==>大黄
d1.sleep() ==> 大黄正在睡觉
#父类里定义的属性,子类可以直接使用,父类的方法子类实例对象可以直接调用
格式:
class 子类名(父类1名称,父类2名称): #父类个数不限
pass
注意:
如果多个父类有相同的方法(属性),排在子类括号中靠前的父类得到继承
例: class 子类名(父类A,父类B)若AB存在相同属性子类将继承父类A中的····
不同父类函数同名的情况下,可用一个类属性查看方法的调用顺序。_ _ mro_ _
格式: 子类名._ _ mro_ _ 例:print(子类名._ _ mro_ _)
深度大于广度,不同父类函数同名,优先级高的父类的深度深
新式类和经典类的继承
#手动的指定student类继承自object
class Student(object):
pass
#未指定Dog父类,python3默认继承object
class Dog():
ps=pass
新式类:继承自object的类
经典类:不继承自object的类 (注意:在python2中不手动指定,即默认为经典类)
#继承特点:如果一个类A继承自类B,由类A创建出来的实例对象都能直接使用类B里定义的方法
子类的实现和父类的实现完全不一样。子类可以选择重写父类
子类在父类的基础上又有更多的实现
例:
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def Sleep(self):
print(self.name+'正在睡觉')
class Student(person):
def __init__(self,name,age,school):
Person.__init__(self,name,age) #第一种方法
#子类在父类实现的基础上,又添加了自己新的功能,调用父类的两种方法:
# 1、父类名.方法名(self,参数,列表)
# 2、使用surper直接调用父类方法,推荐使用第二种方法
surper(Student,self).__init__(name,age) #第二种方法
self.school=school
def Sleep(self):
print(self.name+'正在课间休息时间睡觉')
概念:基于继承,通过子类重写父类的方法,达到不同的子类对象调用相同的父类方法,得到不同的结果,提高代码的灵活度。
例:
class Dog(object):
def work(self):
print('狗正在工作')
class PoliceDog(Dog):
def work(self):
print('警犬正在攻击敌人')
class BlidDog(Dog):
def work(self):
print('缉毒犬正在搜毒')
class Person(object):
def __init__(self,name):
self.name=name
self.dog=None
def work_with_dog(self):
if self.dog is not None and isinstance(self,dog,Dog):
self.dog.wrk
p=Person('张三')
1、pd=policeDog()
p.dog=pd
p.work_with_dog()
2、bd=BlindDog()
p.dog=bd
p.work_with_dog()
3、dd=DruDog()
p.dog=dd
p.work_with_dog()
像一个房子的门,是进出这间房子的必经之路,如果一个程序需要收发网络数据,那么就需要有这样的端口。(在linux系统中,端口可以有65535即2的16次方个)
用以标记端口,端口号只有整数,范围是0到65535,端口号按照一定的规定进行分配
知名端口号
知名端口号是众所周知的端口号,范围从0到1023.可以理解为,一些常见的号码是估计的,好比电话号码110、10086····,一般情况下,如果一个程序需要使用知名端口号需要有root权限
动态端口号
范围:从1024到65535
之所以称为动态端口,是因为他一般不固定分配某种服务,而是动态分配动态分配是指当一个系统或程序需要网络通信时它向主机申请一个端口,主机从可用端口中分配一个供它使用,当程序关闭,同时也释放了所占用的端口号
端口号作用
同一电脑用pid区分不同程序(或进程)
ip + 协议 + 端口 ==> 标记网络进程
socket(套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多数都是基于socket来完成通信的。例如我们每天浏览网页、QQ聊天以及法email等等
在python中使用socket模块的函数socket就可以完成:
import socket
socket.socket(Adderss Family,Type)
说明:
函数socket.socket创建一个socket,该函数带有两个参数:
创建一个tcp.socket(tcp套接字)
import socket #创建tcp的套接字
s=socket.socket(socket.AF_INET,socket.STREAM)
·············· #使用套接字的功能,省略
s.close #不用的时候关闭套接字
创建一个udp.socket(udp套接字)
import socket
#创建udp套接字
s=socket.socket(socket.AF_INET,socket.DGRAM)
·········· 省略功能
s.close
注意:调试代码使用工具:网络调试助手(NetAssist)
udp是User Datagram Protocol的简称,中文名称是用户数据报协议,在通信开始之前不需要建立相关的链接,只要发送数据即可,类似于生活中“写信”
socket可以在不同的电脑间通信,还可以在同一电脑的不同程序之间通信
例:
import socket
s=socket.socket(socket.AF_INET,socket.SCK_DGRAM)
#1、创建socket,并链接
#AF_INET:表示这个socket是用来进行网络链接的
#SOCK_DGRAM:表示这是一个udp链接
s.sendto('你好'.encode('utf8'),('192.168.31.199',9090))
#2、发送数据,s.sendto(data,address)
#data:要发送的数据,他是二进制的数据
#address:发送给谁,参数是一个元组,元组内含2个参数,第0个表示目标哦IP地址,第一个表示程序端口号
#3、关闭socket
s.close
注意:2、3之间接收数据:
data,address=s.recvfrem(1024)
print(·······)
注意:通信时最好绑定端口号
例:
import socket
#创建基于udp的网络socket链接
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#绑定端口号和IP地址
s.bind('192.168.31.199',9090)
#recvfrom 接收数据
data,addr=s.recvfrom(1024)
#接收到的数据是一个元组,元组里有两个元素:data,address。
#第0个元素是接收到的数据,第1个元素是发送方的ip和端口号
print('从地址:{}端口号{}接收到了消息,内容是:{}'.format(addr[0],addr[1],data))
#data需做utf8编码,防止传输过程中文乱码,上一行写不下省略:data.decode('utf8')
#关闭
s.close()
UDP:没有严格的客户端和服务器的区别
TCP:有客户端和服务器,面向连接的协议
例:
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#基于TCP协议的socket连接,在发送数据前,需先与服务器建立连接
s.connect(('192.168.31.199',9090)) #调用connect方法连接到服务器
s.send('hello'.encode('utf8'))
s.close()
例:
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('192.168.31.199',9090))
#把socket变成一个被动监听的socket
s.listen(128) #注意:128位队列数,即超过服务器极限数目的最多排队数
#s.accept接收数据,一个元组,内含两个元素,第0个客户端socket连接,第一个是客户端ip和端口号
client_socket,client_addr=s.accept() #拆包
data,addr=client_socket.recv(1024) #tcp用recv获取数据,udp用recvfrom
print('客户端{}端口号{}内容{}'.format(addr[0],addr[1],data.decode(utf8)))
http协议:Hyper Text Transfer Protocol 超文本传输协议
HTML:超文本标记语言
架构
http服务器都是基于tcp的socket链接
B/S架构中。http请求头:request headers,http响应头:response headers
返回内容前,需要先设置http响应头
例:
client_socket.set('HTTP/1.1 200 OK\n'.encode('utf8'))
client_socket.send('content-type:text/html\n'.encode('utf8'))
http请求头
IP地址的绑定
127.0.0.1 和 0.0.0.0 都表示本机,0.0.0.0表示所有可用的地址
例:
server_socket.bind(('0.0.0.0',<端口号>))
server_socket.listen(128) #监听队列数
状态码
根据不同请求返回不同内容
#创建好socket链接并绑定端口后
#根据不同请求作出不同响应
while True:
client_socket,client_addr=serve_socket.accept()
data=client_socket.recv(1024).decode('utf8')
path='/'
if data: #浏览器发送过来的数据有可能是空的
path=data.splitlines()[0].split(' ')[1]
print('请求路径是{}'。format(path))
response_body='返回内容'
if path=='请求路径>':
response_body='返回内容'
······· #各种请求对应不同响应(返回内容)
·······
响应:
'conten-type:text/html;charset=utf8\n' #用utf8打开
404页面未找到:'HTTP/1.1 404 page not found'
成功访问:'HTTP/1.1 200 OK\n'
import socket
class myserver(object):
def __init__(self,ip,port):
self.socket.socket(socket.AF_INET·····)
self.bind(ip,port)
self.socket.listen(128)
def run_server(self): #服务器代码主体
········
server=myserver('0.0.0.0',9090)
server.run_server()
类似于模块、框架
实例:
import json
from wsgiref.simple_server import make_server
def load_file(file_name,**kwargs):
try:
with open('pages(文件名)'+file_name,'r',encoding='utf8') as file:
cotent=file.read()
if kwargs: #一个字典,需要填入'html'里的内容
content(content.format(**kwargs)) #拆包,填入对应的位置
return content
except FileNotFoundError:
print('文件未找到')
def index():
····
def show():
return load_file(xxx.txt)
def show_info():
return load_file('info.html',username='zhangsan',age=19,gedder='male')
url={
'/':inndex,
'/show':show,
·····
}
def demo_app(environ,start_response):
#demo_app需两个参数
#第0个参数,表示环境(电脑环境:请求路径相关环境)
#第一个参数,是一个函数,用来返回响应头
#这个函数需要一个返回值,返回值是一个列表
#列表里只有一个元素,是一个二进制,表示返回给浏览器的数据
path=environ['PATH_INFO']
#environ是一个字典,保存了很多数据,其中重要的一个是PATH_INFO能获得到用户的访问路径
statas_code='200 ok'
method=url.get(path)
if method:
response=method()
else:
statas_code='404 not found'
response='页面走丢了'
start_response(statas_code,[('Contenn-Type','text/html;charset=utf8')])
return [response.encode('utf8')]
if __name__=='__main__':
httpd=make_server(' ',8090,demo_app)
sa=httpd.socket.getsocketname()
print('serving HTTP on',sa[0],'port',sa[1],'····')
httpd.serve_forever() #服务器一直运行
#httpd.headle_request() #只处理一次请求
#一般放在处理请求前
import webbrowser
webbrowser.open('http://locahost:8000/xyz?abc')
#相当于打开电脑浏览器并输入'http://······'
import threading
t1=threadingn.Thread(target=<函数/方法>) #线程1
t2=threadingn.Thread(target=<函数/方法>) #线程2
#注意:target需要一个函数,用来指定需执行的任务
#启动线程
t1.start() #两个线程并非同时运行,而是交替运行
t2.start() #python多线程特性,多个线程交替运行,称为伪多线程
补充:
threading.carrent_thread().name #方法,得到线程名字
t1=threading.Tread(target=<函数/方法>,name=<线程名>)
多线程
多个线程可以同时操作一个全局变量,即多线程共享全局变量
同步
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。同步就是协同步调,按预定的先后顺序进行运行。线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
互斥锁
互斥锁为资源引入一个状态:锁定/非锁定
某个线程需要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改。直到该线程释放资源,将资源的状态变成“非锁定”,其他线程才能两次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性
threading模块中定义了Lock类,可以方便的处理锁定
#创建一把“锁”
lock=threading.Lock()
#加载同步锁
lock.acquire()
#释放“锁”
lock.release()
概念
线程之间有时需要通信,操作系统提供了很多机制来实现线程间的通信,其中我们使用最多的就是队列Queue
Queue的原理
Queue是一个先进先出(first in first out)的队列,主进程中创建一个Queue对象,并作为参数传入子进程,两者之间通过put()放入数据,通过get()取出数据,执行了get函数之后队列中的数据会被同时删除,可以使用multiprocessing 模块的Queue实现多线程之间的数据传递
#创建一个队列q
q=queue.Queue()
#往队列q中添加数据(元素)
q.put()
#从队列中取出数据(元素)
q.get()
补充:
stack 栈结构
先进先出,后进后出
程序:例如 xxx.py是一个程序,是一个静态的
进程
一个程序运行起来后,代码+用到的资源称之为进程,它是操作系统分配资源的基本单位
注意:不仅可以通过线程完成多任务,进程也是可以的
进程的状态
工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另一些任务在等待cpu进行执行,因此导致了有了不同的状态
multiprocessing 模块是跨平台版本的多进程模块,提供了一个process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情
示例:创建子进程,只需要传入一个执行函数和函数的参数创建一个process实例,用start()方法启动
import multiprocessing
·······
if __name__ == '__main__': #注:在windows系统中,须当执行整个.py文件时,才不会报错
p1=multiprocessing.process(target=<方法/函数(不带括号)>)
p2=multiprocessing.process(target=<方法/函数(前面已定义)>)
启动:
p1.start()
p2.start()
注意:
#如果函数/方法有参数,使用"args"
target=<函数>,args=<参数>
#进程pid:
import os
os.getpid() #放于方法/函数下(代码行下)
方法说明
process(target[,name[,args[,kwargs]]])
#target:如果传递了函数的引用,可以任务这个子进程就执行这里的代码
#args:给target指定的函数传递的参数,以元组的方式传递
#kwargs:给target指定的函数传递命名参数
#name:给进程设定一个名字,可以不设定
process创建实例对象的方法:
start() #启动子进程实例(创建子进程)
is_alive() #判断子进程是否存活
join(timeout) #是否等待子进程结束,或等待多少秒
teminate() #不论任务是否完成,立即终止子进程
注意:常用属性
name:进程别名,默认process-N,N从1递增
pid:进程号(进程pid)
功能区别
进程:能够完成多任务。比如在一台电脑上同时运行多个QQ
线程:能够完成多任务。比如一个QQ中多个聊天窗口
定义不同
区别总结
注:进程间通信与线程一样,使用队列Queue,但这个队列是multiprocessing中的模块,即multiprocessing.Queue。队列中先进先出,用法与前面线程间通信Queue一致
种类
用法
示例:以multiprocess.Queue为例
#创建队列时,可以指定最大长度,默认是0,表示无限制。超过限制造成堵塞,进程等待
q=multiprocessing.Queue(5)
#查看判断进程队列Queue是否满了(达到限制),返回布朗值,True表示满了
print(q.full())
#block:put参数,表示阻塞
q.put('how',block=True) #若队列满了就等待
#timeout:put参数,超时,等待xx时间后,程序报错,单位秒
#若不使用block、timeout则会一直等待,不报错,一般两者配合使用
q.put('how',block=True,timeout=1) #等待1秒后报错
#不阻塞,满了不等待,直接报错
q.put_nowait('how') #等价于:q.put('how',block=False)
注意:
get()与put()一样,都会阻塞,都可配置timeout
概述
当进程(所需)不多时,可直接用multiprocessing中process动态生成多个进程。但当需要进程非常多时,可用multiproocessing 中pool方法
初始化pool时,可以指定一个最大进程数,当有新的请求提交到pool时,若池未满,那就创建一个新的进程来执行该请求。反之,请求会等待,直至池中有进程结束,才会用之前进程执行新的任务
实例
from multiprocessing import pool
import os,time,random
def worker(msg):
t_start=time.time()
print("%s开始执行,进程号为%d"%(msg,os.getpid()))
time.sleep(random.random()*2) #random 随机生成0~1之间浮点数
t_stop=time.time()
print(msg,"执行完毕,耗时%0.2f"%(t_stop-t_start))
po=pool(3) #定义一个进程池,最大进程数3
for i in range(0,10):
#pool().apply_async(需要调用的目标,(传递给目标的参数元组,))
#每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,))
print('-----start------')
po.close() #关闭进程池,关闭后po不再接收新的请求
po.join() #等待po中所有子进程执行完毕,必须放在close语句之后
print("------end-------")
进程和线程中都有join方法,join方法的作用是让主进程(或线程)等待子进程(或线程)
import time
x=10
def test(a,b):
time.sleep(1)
global x
x=a+b
t=threading.Thread(target=test,args=(1,1))
t.start()
#t.join(),使用join方法后,主线程将等待子线程运行完成,打印结果为2
print(x) #结果为10,主线程快于子线程,主线程先打印结果,子线程还在计算
requests.request() #构造一个请求,支持以下各种方法的基础方法
requests.get() #获取HTML网页的主要方法,对应于HTTP的GET方法
requests.head() #获取HTML网页头信息的方法,对应于HTTP的HEAD
requests.post() #向HTML网页提交POST请求方法,对应于HTTP的POST
requests.Put() #向HTML网页提交PUT请求的方法,对应于HTTP中PUT
requests.patch() #向HTML网页提交PATCH请求的方法,对应于HTTP中PATCH
requests.delete() #向HTML页面提交删除请求,对应于HTTP的DELETE
含义
r=requests.get(url)
#构造一个向服务器请求资源的request对象,url为请求路径
#返回一个包含服务器资源的response对象,并将对象赋给变量r
格式构成
requests.get(url,params=None,**kwargs)
#url:拟获取页面url链接
#params:url中的额外参数,字典或字节流格式,可选
#**kwargs:12个控制访问的参数
response对象的属性
r.status_code #HTTP请求的返回状态,200表示连接成功,404表失效
r.text #HTTP响应内容的字符串形式,即url对应的页面内容
r.encodeing #从HTTP header中猜测的响应内容编码方式
r.content #HTTP响应内容的二进制形式
r.apparent_encoding #从内容中分析出响应内容编码方式(备选编码方式)
理解response的编码
r.encoding:如果header中不存在charset,则认为编码为ISO-8859-1
r.text根据r.encoding显示网页内容
r.apparent_encoding:根据网页内容分析出的编码方式,可以看做r.encoding备选
异常种类
requests.connectionError #网络连接错误异常,如果DNS查询失败,拒绝连接等
requests.HTTPError #HTTP错误异常
requests.URLRequired #URL缺失异常
requests.ToomanyRedirects #超过最大重定向次数,产生重定向异常
requests.ConnecTimeout #连接远程服务器超时异常
requests.Timeout #请求url超时,产生超时异常
异常处理(爬虫通框架)
r.raise_for_status() #在方法内部判断 r.status_code 是否等于200,不需要增加额外的if
#语句,该语句便于利用try-except 进行异常处理
框架
import requests
def gethtmltext(url):
try:
r=requests.get()
r.raise_for_status() #若状态码不是200,引发HTTPError报错
r.encoding=r.apparent_encoding
return r.text
except:
return "异常"
定义
HTTP,Hypertext Transfer Protocol 超文本传输协议。HTTP是一个基于“请求与响应”模式的、无状态的应用层协议。HTTP协议采用URL作为定位网络资源的标识,URL格式如下:http:// host [:port] [patch]
名词解释
HTTP协议对资源的操作
PATCH和PUT的区别
假设URL位置有一组数据UserInfo,包括UserTD、UserName等20个字段
需求:用户修改UserName、其他不变
requests.request(method,url,**kwargs)
**kwargs访问控制参数(13个)
params:字典或字节序列,作为参数增加到url中
>>>kv={'key1':'value1','key2':'value2'}
>>>r=requests.request('GET','http://python123.io/ws',params=kv)
>>>print(r.url)
http://python123.io/ws?key1=value1&key2=value2
data:字典、字节序列或文件对象,作为request对象的内容
>>>kv={'key1':'value1','key2':'value2'}
>>>body='主体内容'
>>>r=requests.request('GET','http://python123.io/ws',params=kv,data=body)
json:JSON格式的数据,作为request的内容(与data类似)
headers:字典,HTTP定制头,request请求头(比如UA、host等信息)
>>>hd={'User-Agent':'chrome/10'}
>>>r=requests.request('POST','http://python123.io/ws',headers=hd)
Cookies:字典或cookieJar,request中的cookie
auth:元组,支持HTTP认证功能
files:字典类型,传输文件
>>>fs={'file':open('data.xls','rb')}
>>>r=requests.request('POST','http://python123.io/ws',files=fs)
timeout:设定超时时间,秒为单位
>>>r=requests.request('POST','http://python123.io/ws',timeout=3)
proxies:字典类型,设定访问代理服务器,可以增加登录认证
>>>pxs={'http':'http://user:[email protected]:1234','https':'https://10.10.10.1:44321'}
>>>r=requests.request('GET','http://python123.io/ws',proxies=pxs)
allow_redirects: True/False,默认为True,重定向开关
stream: True/False,默认为True,获取内容立即下载开关
Verify: True/False,默认为True,认证SSL证书开关
cert:本地SSL证书路径
格式:requests.get(url,params=None,**kwargs)
#url:拟获取页面url链接
#params:url中的额外参数,字典或字节流格式,可选
#**kwargs:12个控制访问参数。与request方法一致,除params。
#requests库其他6个方法由request封装而来,故他们参数与request一致
requests库其他6个方法由request封装而来,故他们参数与request一致
requests.head(url,**kwargs) #**kwargs 12个可选
requests.post(url,data=None,json=None,**kwargs)
requests.put(url,data=None,**kwargs)
requests.patch(url,data=None,**kwargs)
requests.delete(url,data=None,**kwargs)
try:
r=requests.get(url,timeout=30)
r.raise_for_status()
r.encodeing=r.apparent_encoding
return r.text
except:
return '产生异常'
来源审查:判断User-Agent进行限制,检查来访HTTP协议头的User-Agent域,只响应浏览器或友好爬虫的访问
发布公告:robots协议,告知所有爬虫,网站的爬取策略,要求爬虫遵守(非强制性)
Robots Exclusion Standard,网络爬虫排除标准
别名:beautiful soup 4,bs4
<html>
<body>
<p class="title">
······· <====> HTML 标签树
p>
body>
html>
Beautiful Soup 库是解析、遍历、维护“标签树”的功能库
<p>····p>:标签Tag
<p class="title">·····p> #p:标签名称name,成对出现。class:属性Attributes,0个或多个
主要是用bs4库中的BeautifulSoup类
from bs4 import BeautifulSoup
import bs4
HTML <———> 标签树 <———> BeautifulSoup
BeautifulSoup 对应一个HTML/XML 文档的全部内容
例:soup=BeautifulSoup('data','html.parser')
bs4的HTML解析器(需安装bs4库):BeautifulSoup(mk,'html.parser')
lxml的HTML解析器(需安装lxml库):BeautifulSoup(mk,'lxml')
lxml的xml解析器(需安装lxml库):BeautifulSoup(mk,'lxml')
html5lib的解析器(需安装html5lib库):BeautifulSoup(mk,'html5lib')
Tag:标签,最基本的信息组织单元,分别用<>和>标明开头和结尾
Name:标签的名字,<>····>的名字是'p',格式:<tag>.name
Attributes:标签的属性,字典形式组织,格式:<tag>.attrs
Navigablestring:标签内非属性字符串,<>···>中字符串,格式:<tag>.string
comment:标签内非属性字符串的注释部分,一种特殊的comment类型
元素详解:
Tag
#任何存在html语法中的标签都可以用soup.<tag>访问获得。当HTML文档存在多个相同<tag>对应内容时,
#soup.<tag>返回第一个
Tag的name(名字):每个<tag>都有自己的名字,通过<tag>.name获取字符串类型
Tag的attrs(属性):一个<tag>标签可以有多个属性,字典类型。
Tag的Navigablestring:Navigablestring可以跨越多个层次。
Tag的comment:comment是一种特殊类型
注意:以下示例的soup为BeautifulSoup类解析的网页内容
<html>
<head>
<title>This is a python demo pagetitle>
head>
<body>
<p class="title">
p>
<p class="course">python is ··········
is demo········
a>
<a>is demo·····
a>
p>
body>
html> //<>···>构成了所属关系
| <html> <————|b到html为上行遍历
| > | <body>
| <p> | <--------> <p>
| <title> <b> | <a> <--> <a>
html到title为下行遍历 p到p,a到a是平行遍历
标签树的下行遍历
例:
for child in soup.body.children:
print(child) #遍历儿子节点
for child in soup.body.descendants:
print(child) #遍历子孙节点
标签树的上行遍历
.parent #节点的父亲标签
.parents #节点先辈标签的迭代类型,用于循环遍历先辈节点
#注意:遍历先辈节点,包括soup本身,所以要区别判断
标签树的平行遍历
.next_sibling #返回按照HTML文本顺序的下一个平行节点标签
.previous_sibling #返回按照HTML文本顺序的上一个平行节点标签
.next_siblings #迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
.previous_siblings #迭代类型,返回按照HTML文本顺序的前续所有平行节点标签
注意:平行遍历发生在同一父亲节点下的个节点之间
例:
for sibling in soup.a.next_strings:
print(sibling) #遍历后续节点
for sibling in soup.a.previous_siblings:
print(sibling) #遍历前续节点
bs4库的prettify()方法
bs4库的编码
bs4库将任何HTML输入都变成utf-8编码;python 3.x 默认支持编码是utf-8,解析无障碍
HTML通过预定义的<>····>标签形式组织不同类型的信息
信息标记的三种形式
XML(extensible Markup language) #可拓展性好,但繁琐
例:
<img src="chain.jpg" size="10"/>
完元素的缩写形式
<! --This is a comment,very useful-->
注释书写形式
格式:
<name>·····name>
<name/>
JSON(JavaScript Object Notation) #有类型的键值对,适合程序处理js,较xml简洁
有类型的键值对 key:value
示例:"name":"北京大学" #name:类型,键key。北京大学:值value
例:
"name":["北京大学","延安自然学院"] #多值用[,]组织
"name":{
"newName":"北京大学",
"oldName":"延安自然学院" #键值对嵌套用{,}
}
键与值得三种形式:
"key":"value"
"key":["value1","value2"]
"key":["subkey":"subvalue"]
YAML(YAML Aint Markup Language) #信息无类型,文本信息比例高,可读性好
1、无类型键值对 key:value
name:北京理工大学 #name:键key,仅字符串。北京大学:值value
2、缩进表示所属关系
name:
newName:北京理工大学
oldName:延安自然科学院
3、-表达并列关系
name:
-北京理工大学
-延安自然科学院
4、|表达整块数据,#表示注释
text:| #学校介绍
······················
······················
方法一:完整解析信息的标记形式,再提取关键信息。(xml、json、yaml)需要标记解析器,例如:bs4库的标签树遍历
方法二:无视标记形式,直接搜索关键信息。(搜索)对信息文本查找函数即可
融合方法:结合形式解析与搜索方法,提取关键信息。(xml、json、yaml、搜索)需要标记解析器及文本查找函数
基于bs4库
find_all()方法
<>.find_all(name,attrs,recursive,string,**kwargs)
#返回一个列表类型,存储查找结果,<>表示经beautifulsoup对象解析后的内容,下面以前文soup表示
name:按标签名称检索字符串
>>>fof tag in soup.find_all(True): #True表示所有标签
print(tag.name) #输出所有标签名
>>>import re
>>>for tag in soup.find_all(re.compile('b')):
print(tag.name) #输出所有b标签
attrs:对标签属性的检索字符串,可标注属性检索
>>>soup.find_all(id='link') #括号内仅一个参数直接写属性,为多个参数时为attrs(id='link')
>>>import re
>>>soup.find_all(id=re.compile('link'))
recursive:是否对子孙节点全部检索,默认True
>>>soup.find_all('a',recursive=False)
string:<>······>中字符串区域的检索字符串
注意:
注意:
<tag>(····) #等价于.find_all(···)
soup(···) #等价于 soup.find_all(···)
<>.find() #搜索且只返回一个结果,用find_all()参数
<>.find_parents() #在先辈节点中搜索,返回列表类型,同find()参数
<>.find_parent() #在先辈节点中返回一个结果,同find()参数
<>.find_next_siblings() #在后续平行节点中搜搜,返回列表类型,同find_all()参数
<>.find_next_sibling() #在后续平行节点中返回一个结果,同find()参数
<>.find_previous_sibling() #在前序平行节点中搜索,返回列表类型,同find_all()参数
<>.find_previous_sibling() #在前方平行节点中返回一个结果,同find()参数
re:regular expression ,别名:regex、RE
正则表达式是用来简洁表达一组字符串的表达式
例:
'pn'
'pyn' 正则表达式:
'pytn' <====> p(y/yt/yth/ytho)?n
'pythn'
'python'
'py' 'pyy' 'pyyy' 'pyyyy' ······'pyyy····(无穷个)'
正则表达式:py+
'py'开头,后续存在不多于10个字符,后续字符不能是'p'或'y'(例:pyabc)
正则表达式: py[^py]{0,10}
正则表达式是一种通用的字符串表达框架,可以用来判断字符串中的特征归属
正则表达式在文本处理中十分常用:
编译:将符合正则表达式语法的字符串转换成正则表达式特征
例:
正则表达式:p(y/yt/yth/ytho)?n
regex='p(y/yt/yth/ytho)?n' ===编译==> p=re.compile(regex) #特征p
正则表达式由字符和操作符构成
正则表达式常用操作符
. #表示任何单个字符
[] #字符集,对单个字符给出取值范围。 [abc]表示a、b、c,[a~z]表示a到z单个字符
[^] #非字符集,对单个字符给出排除范围。 [^abc]表示非a或b或c的单个字符
* #前一个字符0次或无限次拓展。 abc*表示ab、abc、abcc、abccc等
+ #前一个字符1次或无限次拓展。 abc+表示abc、abcc、abccc等
? #前一个字符0次或1次拓展。 abc?表示ab、abc
/ #左右表达式任意一个。 abc/def表示abc、def
{m} #拓展前一个字符m次。 ab{2}c表示abbc
{m,n} #拓展前一个字符m至n次(含n)。 ab{1,2}c表示abc、abbc
^ #匹配字符串开头。 ^abc表示abc且在一个字符串开头
$ #匹配字符串结尾。 abc$表示abc且在一个字符串结尾
() #分组标记,内部只能使用|操作符。 (abc)表示abc,(abc|def)表示abc、def
\d #数字、等价于[0~9] \D非数字的等价于[^0~9]
\w #单词字符、等价于[A~Za~z0~9] (匹配非标点符号) \W与\w相反
\s #非打印字符(空格、换行、制表符) \S打印字符
注意:
匹配标点符号需加\。例:匹配点\.
[]表示可选项范围,结果为单个字符。|表示或者
示例
^[A~Za~z]+$ #由26个字母组成的字符串
^[A~Za~z0~9]+$ #由26个字母和数字组成的字符串
^_?\d+$ #整数形成的字符串
^[0~9]*[1~9][0~9]*$ #正整数形式的字符串
[1~9]\d{5} #中国境内邮政编码,6位
[\u4eoo-\ugfa5] #匹配中文字符
\d{3}-\d{8}|\d{4}-\d{7} #国内电话号码:010-68913536
匹配IP地址正则表达式(IP地址分段,每段0-255):
\d+.\d+.\d+.\d+ 或 \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}
精确算法:
0~99:[1~9]?\d
100~199:1\d{2}
200~249:2[0-4]\d
250~255:25[0-5]
即:(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])
调用:import re
正则表达式的表示类型
raw string类型(原生字符串类型)<=> 注意:不包含对转义符再次转义的字符串。
re库用raw string类型表示正则表达式,表示为:r’text’
例如:r’[1-9]\d{5}’
re库也可以采用string类型表示正则表达式,但更繁琐。
例如:‘[1-9]\d{5}’
建议:当正则表达式包含转义字符时,使用raw string
re库的功能函数
re.search() #在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match() #从一个字符串的开始位置起匹配正则表达式,返回match对象,无结果返回None
re.findall() #搜索字符串,以列表类型返回全部能匹配的字串。
re.split() #将一个字符串以正则表达式匹配结果进行分隔,返回列表类型
re.finditer() #搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
re.sub() #在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
re功能函数详解
re.search(pattern,string,flags=0)
re.search(pattern,string,flags=0)
#pattern:正则表达式的字符串或原生字符串
#string:待匹配字符串
#flags:正则表达式使用时的控制标记
注意:常用标识
re.I re.IGNORECASE #忽略正则表达式的大写,[A-Z]能够匹配小写字符
re.M re.MUL TLL IME #正则表达式中的^操作符能够将给定字符串的每行当作匹配的开始
re.S re.DTALL #正则表达式中的.操作符能够匹配所有字符,默认匹配除换行外所有字符
re.match(pattern,string,flags=0)
re.findall(pattern,string,flags=0) #以上两个函数参数同re.search()
re.split(pattern,string,maxsplit=0,flags=0)
re.split(pattern,string,maxsplit=0,flags=0)
#pattern,string,flags参数同上
#maxsplit:最大分割数,剩余部分作为最后一个元素输出
例:
>>>re.split(r'[1-9]\d{5}','BLT10081 TSU10084')
['BLT','TSU','']
>>>re.split(r'[1-9]\d{5}','BLT10081 TSU10084',maxsplit=1)
['BLT','TSU10084']
re.finditer(pattern,string,flags=0))
re.sub(pattern,repl,string,count=0,flags=0)
re.sub(pattern,repl,string,count=0,flags=0)
#reple:替换匹配字符串的字符串,正则替换
#count:匹配的最大替换次数
#其他参数同上
注意:
1、repl可以是函数,例:
def test(x):
y=int(x.group(0))
Y*=2
return str(y)
2、sub内部调用text方法时,会把匹配的数据以re.match格式传参
print.sub(r'\d+',test,待匹配字符 )
re.compile(pattern,flags=0)
regxe=re.compile(pattern,flags=0) #将正则表达式的字符串形式编译成正则表达式对象
例:
>>>rst=re.search(r'[1-9]\d{5}','BLT 10081') #函数式用法,一次性操作
>>>rst=pat.search('BLT 10081') #面向对象用法:编译后的名次操作
定义:match对象是一次匹配结果,包含匹配的很多信息
>>>match=re.search(r'[1-9]\d{5}','BLT 10081')
match对象的属性
.string #待匹配文本
.re #匹配时使用的patter对象(正则表达式)
.pos #正则表达式搜索文本的开始位置
.endpos #正则表达式搜索文本的结束位置
.group(0) #获得匹配后的字符串,括号内参数为分组序数。分组相关解释放在末尾
.start() #匹配字符串在原始字符串的开始位置
.end() #匹配字符串在原始字符串的结束位置
.span() #返回(.start(),.end())
补充:
分组:在正则表达式中,加括号分组
例:(?p<分组名>正则表达式) #给分组取名,{分组名:匹配值}
groupdict(分组名)/groupdict() #获得分组组成的字典,{分组名:匹配值}
示例:
>>>import re
>>>m=re.search(r'[1-9]\d{5}','BLT10081 TSU10084')
>>>m.string/m.endpos·······
贪婪匹配
同时匹配长短不同的多项,re库默认采用贪婪匹配,即输出匹配最长的子串
最小匹配
最小匹配操作符:
*? #前一个字符0次或无限次拓展,最小匹配
+? #前一个字符1次或无限次拓展,最小匹配
?? #前一个字符0次或1次拓展,最小拓展
{m,n}? #拓展前一个字符m至n次(含n),最小匹配
注意:只要长度输出可能的,都可以通过在操作符后增加?变成最小匹配
一个快速功能强大的网络爬虫框架(网站级)
爬虫框架是实现爬虫功能的一个软件结构和功能组件集合,是一个半成品,能够帮助用户实现专业网络爬虫
scrapy爬虫框架结构(“5+2”结构)
数据流的三个路径:
爬虫框架结构解析
scraoy命令行(scrapy -h)
scrapy专业爬取框架,提供操作的scrapy命令行。windows下,启动cmd控制台
格式:scrapy
常用scrapy命令
startproject #创建一个新工程 scrapy startproject [dir]
genspider #创建一个爬虫 scrapy genspider [options]
settings #获得爬虫的配置信息 scrapy settings [options]
crawl #运行一个爬虫 scrapy crawl
list #列出工程中的所有爬虫 scrapy list
shell #启动url调试命令行 scrapy shell [url]
例:1、演示html页面地址:http://python123.io/ws/demo.html
文件名称:demo.html
产生步骤1:应用scrapy爬虫框架主要是编写配置代码
步骤1:建立一个scrapy爬虫工程
选取一个目录(例D:\python\),然后执行如下命令:
(命令行下)D:\python>scrapy startproject python123demo
生成的工程目录
结构: python123demo/ #外层目录
scrapy.cfg #部署scrapy爬虫的配置文件
python123demo/ #scrapy框架的用户自定义python代码
_init_py #初始化脚本
items.py #Items代码模块(继承类)
middlewares.py #MiddleWares 代码模块(继承类)
pipelines.py #pipelines代码模块(继承类)
setting.py #scrapy爬虫的配置文件
spiders/ #spiders代码模块目录(继承类)
_pycache_ #缓存目录,无需修改
内层目录: spiders/ #spiders代码模块目录(继承类)
_init_.py #初始化文件,无需修改
_pycache_/ #缓存目录,无需修改
注意:用户自定义的spiders代码增加在此处
产生步骤2:
步骤2:在工程中产生一个scrapy爬虫
进入工程目录(D:\python\python123demo),然后执行如下命令:
D:\python\python123demo>scrapy genspider demo python123.io
#该命令作用:仅用于生成demo.py爬虫文件,该文件可以手工生成
1、生成一个名称为demo的spiser
2、在spider目录下增加代码文件demo.py
3、注意:爬虫文件中
def parse(self,response)
#parse()用于处理响应,解析内容形成字典,发现新的url爬取请求
产生步骤3:
步骤3:配置产生的spider爬虫
1、初始化url地址
2、获取页面的解析方式
产生步骤4:
步骤4:运行爬虫,获取网页
在命令行下,执行如下命令:
D:\python\python123demo>scrapy crawl demo
#爬虫被执行,捕获页面存储在demo.html
概述:
包含yield语句的函数是一个生成器,生成器每次处理一个值(yield语句)。函数被冻结,被唤醒后再产生一个值,生成器是一个不断产生值的函数,每调用一次在yield位置产生一个值,直到函数执行结束。
优势
生成器更节省空间,响应更加迅速,使用更加灵活。
例:demo.py
import scrapy
class Demospider(scrapy.spider):
name='demo'
def atart_request(self):
urls=['http:·····']
for url in urls:
yield scrapy.Request(url=url,callback=self.parse)
步骤:
scrapy爬虫数据类型(Request、Response、Item三大类)
Request类
格式: class Scrapy.http.Request()
#Request对象表示一个http请求,由spider生成,由Downloader执行
属性方法:
.url #Request对应的请求url地址
.method #对应的请求方法,'GET''POST'等
.header #字典类型风格的请求头
.body #请求内容主体,字符串类型
.meta #用户添加的拓展信息,在scrapy内部模块间传递信息使用
.copy #复制该请求
Rsponse类
格式: class Scrapy.http.Request()
#Response对象表示一个http响应,由Downloader上生成,由spider处理
属性和方法:
.url #Response对应的url地址
.status #http状态码,默认是200
.headers #Response对应的头部信息
.body #Response对应的内容信息,字符串类型
.flags #一组标记
.request #产生Response类型对应的Request对象
.copy() #复制该响应
Item类
格式: class Scrapy.item.Item()
#Item对象表示一个从HTML页面提取的信息内容。由spider生成,由Item pipeline处理
#Item类似于字典类型,可以按照字典类型操作
scrapy爬虫提取信息的方法
scrapy爬虫支持多种html信息提取方法:
Beautiful Soup、lxml、re、xpath selector、css selector
css selector的基本使用
<HTML>.css('a::attr(herf)').extract()
windows、linux系统自带工具,命令行启动。
基本使用:
curl -A #指定请求表示,设置user_agent.格式:curl -A "chrome" 网址url
-X #用指定方法请求。格式:curl -X POST url
-I #只返回请求头信息。格式: curl -I url
-d #以post方法请求url,并发送相应参数。格式:curl -d <要传参数> url
-O #下载文件并以远程文件名保存。格式:curl -O url
-o #下载文件且自定义文件名。格式:curl -o <自定义文件名> url
-L #跟随重定向请求。格式: curl -IL url
-H #设置头信息。格式: curl -H <头信息>
-k #允许发起不安全的ssl请求(有的网站未认证)
-b #设置cookie。格式: curl -b <自定义cookie> url
-S #不显示其他无关信息
-v #显示连接过程中所有信息
注意:
-d可以传文件,可传多个参数:
-d a=1 -d b=2 -d c=3
-d*a=1&b=2&c=3
-d @文件名
例:curl -o image.webp -H 'accept:image/webp' url
#image.webp:定义文件名
#accept:image/webp 定义文件格式
示例:linux系统中
curl url |grep -E "\dt"
#-E:正则表达式
#-v:取反
linux系统自带工具
基本使用:
-O #以指定文件名保存下载文件。格式:wget -O <自定义文件名> url
--limit #以指定速度下载目标文件。格式:wget --limit,例:--limit-rate=200k 以200k/s速度下载
-c #断点续传
-b #后台下载
--mirror #镜像某目标网站
-p #下载页面所有相关资源
-r #递归下载所有网页中所有的链接
-log #日志(显示下载进度)
-u #指定user-agent
例:
镜像下载整个网站保存到本地
wget -c --mirror -u "mozilla" -p --convert-links url
HTTPie
linux系统中使用的爬虫工具,使用:http -参数
postman
接口类爬虫工具
charles、fiddler
抓包工具
基本语法,详情:https://www.w3school.com.cn/xpath/index.asp
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:
路径表达式 | 结果 |
---|---|
bookstore | 选取 bookstore 元素的所有子节点。 |
/bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang | 选取名为 lang 的所有属性。 |
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()❤️] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang=‘eng’] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
node() | 匹配任何类型的节点。 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/* | 选取 bookstore 元素的所有子元素。 |
//* | 选取文档中的所有元素。 |
//title[@*] | 选取所有带有属性的 title 元素。 |
通过在路径表达式中使用“|”运算符,您可以选取若干个路径。
实例
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
//book/title | //book/price | 选取 book 元素的所有 title 和 price 元素。 |
//title | //price | 选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |
轴名称 | 结果 |
---|---|
ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
attribute | 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
namespace | 选取当前节点的所有命名空间节点。 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
绝对路径起始于正斜杠( / ),而相对路径不会这样。在两种情况中,位置路径均包括一个或多个步,每个步均被 斜杠分割:
/step/step/...
step/step/...
相关概念
轴(axis)
定义所选节点与当前节点之间的树关系
节点测试(node-test)
识别某个轴内部的节点
零个或者更多谓语(predicate)
更深入地提炼所选的节点集
轴名称::节点测试[谓语]
例子 | 结果 |
---|---|
child::book | 选取所有属于当前节点的子元素的 book 节点。 |
attribute::lang | 选取当前节点的 lang 属性。 |
child: | 选取当前节点的所有子元素。 |
attribute: | 选取当前节点的所有属性。 |
child::text() | 选取当前节点的所有文本子节点。 |
child::node() | 选取当前节点的所有子节点。 |
descendant::book | 选取当前节点的所有 book 后代。 |
ancestor::book | 选择当前节点的所有 book 先辈。 |
ancestor-or-self::book | 选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点) |
child:/child::price | 选取当前节点的所有 price 孙节点。 |
Matplotlib:高质量的二维数据可视化功能库
seaborn:统计类数据可视化功能库
Mayavi:三维数据可视化功能库(3D效果)
https://pypi.org
使用pip安装工具(命令行工具)
pip install <第三方库名> #安装指定第三方库
pip install -u <第三方库名> #更新已安装第三方库
pip uninstall <第三方库名> #卸载指定第三方库
pip download <第三方库名> #下载但不安装指定第三方库
pip show <第三方库名> #列出某个指定第三方库的详细信息
pip search <关键词> #根据关键词在名称和介绍中搜索第三方库
pip list #列出当前系统已安装得到第三方库,等价于:pip free2e
集成安装
结合特定的python开发工具的批量安装
Anaconda,支持近800个第三方库,包含多个主流工具,适合数据计算领域开发
文件安装
某些第三方库pip下载后,需要编译后在安装
如果操作系统没有编译环境,则只能下载不能安装
解决方案:搜索第三方库名,下载对应版本文件,使用pip install <文件名>安装
路径操作:os.path子库,处理文件路径及信息
进程管理:启动系统中其他程序
环境参数:获得系统软硬件信息等环境参数
路径操作
os.path子库以path为入口,用于操作和处理文本路径
import os.path 或 import os.path as op
操作函数
os.path.abspath(path) #返回path在当前系统中的绝对路径
例:>>>os.path.abspath('file.txt')
'C:\\users\python\file.txt'
os.path..normpath(path) #归一化path的表现形式,统一用\\分隔路径
例:>>>os.path.normpath('D://PYE//file.txt')
'D:\\PYE\\file.txt'
os.path.relpath(path) #返回当前程序与文件的相对路径(relative path)
例:>>>os.path.relpath('C://PYE//file.txt')
'····\\····\\····\\····\\PYE\\file.txt'
os.path.dimame(path) #返回path中的目录名称
例:>>>os.path.dirname('D://PYE//file.txt')
'D:PYE'
os.path.basename(path) #返回path中最后的文件名称
例:>>>os.path.basename('D://PYE//file.txt')
'filee.txt'
os.path.join(path,*paths) #组合path与paths,返回一个路径字符串
例:>>>os.path.join('D:/','PYE/fiel.txt')
'D:/PYEE/file.txt'
os.path.exists(path) #判断path对应文件目录是否存在,返回True或False
os.path.isfile(path) #判断path对应是否已存在的文件,返回True或False
os.oath.isdir(path) #判断path所对应的是否为已存在的目录,返回True或False
os.path.getmtime(path) #返回path对应文件或目录最近一次修改时间
os.path.getatime(path) #返回path对应文件或目录上一次访问时间
os.path.getctime(path) #返回path对应文件或目录的创建时间
os.path.getsize(path) #返回path对应文件的大小,以字节为单位
进程操作
os.system(command) #执行程序或命令command,在windows中返回值为cmd的调用返回信息
例:
import os
os.system('C:\\windows\\system32\\calc.exe')
>>>
0
环境参数
os.chdir(path) #修改当前程序操作的路径
os.getcwd() #返回程序的当前路径
os.getlogin() #获得当前系统登录用户名称
os.cpu_count() #获得当前系统的cpu数量
os.urandom() #获得n个字节长度的随机字符串,通常用于加密运算
将.py源代码转换成无需源代码的可执行环境
.py文件 ——> pyinstaller ——> windows(exe文件)
cmd命令行下:pip install pyinstaller
命令行下: pyinstaller -F <文件名.py> #将py文件转化为exe文件
-h #查看帮助
--clear #清理打包过程中的临时文件
-D,--onedir #默认值,生成dist文件夹
-F,--onefile #在dist文件夹中只生成独立的打包文件
-i <图标文件名.ico> #指定打包程序使用的图标(ico)文件
例:pyinstaller -i <文件名>.ico -F <文件名>.py
随机数种子
随机数种子 ——> 梅森旋转算法——> 随机序列
基本随机数函数
seed(a=None) #初始化给定的随机数种子,默认为系统时间
random() #生成一个[0.0,1.0]之间的随机小数
例:
>>>random.seed(10) #产生种子10对应序列
>>>random.random() #0.5714025946899135
random(a,b) #生成一个[a,b]之间的整数
randrange(m,n[,k]) #生成[m,n]之间以k为步长的随机整数
getrandbits(k) #生成一个k比特长的随机整数
uniform(a,b) #生成[a,b]之间的随机小数
choice(seq) #从序列seq中随机选择一个元素
shuffle(seq) #将序列seq中元素随机排列,返回打乱后的序列
例:
random.random(10,100) ==>64
random,randrange(10,100,10) ===>80
random。getrandbits(16) ===>37885
random.uniform(10,100) ===>13.096321648808136
random.choice([1,2,3,4,5]) ===>2
s=[1,2,3,4,5];random.shuffle(s);print(s) ==> [3,5,1,4,2]
calendar 日历库
time() #获取当前时间戳,即计算机内部时间值,浮点数(time.time())
ctime() #获取当前时间并以易读的方式表示,返回字符串
gmtime() #获取当前时间,表示为计算机可处理的时间格式
localtime() #类似于gmtime(),但它将秒数转换为本地时间
例
>>>time.time() ==> 1658653428.881543
>>>time.ctime() ==> Sun Jul 24 17:04:51 2022
>>>time.gmtime() ==>
time.struct_time(tm_year=2022, tm_mon=7, tm_mday=24, tm_hour=9, tm_min=5, tm_sec=51, tm_wday=6, tm_yday=205, tm_isdst=0)
>>>time.localtime() ==>如果加参数结果与gmtime()不同
time.struct_time(tm_year=2022, tm_mon=7, tm_mday=24, tm_hour=17, tm_min=7, tm_sec=52, tm_wday=6, tm_yday=205, tm_isdst=0)
格式化函数
time.ASCtime() #格式化为可读格式
strftime(tpl,ts) #tpl是格式化模板字符串,用来定义输出效果。ts是计算机内部时间类型变量
strptime(str,tpl) #str是字符串形式的时间值,tpl是格式化模板字符串,用来定义输入效果
例:
>>>t=time.gmtime()
>>>time.strftime('%Y-%m-%d %H:%M:%S',t)
'2022-07-24 09:15:48'
>>>timestr='2022-07-24 09:15:48'
>>>time.strptime(timestr,'%Y-%m-%d %H:%M:%S')
time.struct_time(tm_year=2022, tm_mon=7, tm_mday=24, tm_hour=9, tm_min=15, tm_sec=48, tm_wday=6, tm_yday=205, tm_isdst=-1)
格式化控制符
%Y | 年份 | 0000~9999 例:1900 |
---|---|---|
%m | 月份 | 01~12 例:10 |
%B | 月份名称 | January~December 例:April |
%b | 月份名称缩写 | Jan~Dec 例:Apr |
%d | 日期 | 01~31 例:25 |
%A | 星期 | Monday~sunday 例:wednesday |
%a | 星期缩写 | Mon~Sun 例:Wed |
%H | 小时(24h制) | 00~23 例:12 |
%I | 小时(12h制) | 01~12 例:7 |
%P | 上/下午 | AM,PM 例:PM |
%M | 分 | 00~59 例:36 |
%S | 秒 | 00~59 例:26 |
perf_counter() #返回一个cpu级别的精确时间计数值,单位为秒。
#由于这个计数值起点不确定,连续调用差值才有意义
sleep(s) #s拟休眠时间,单位是秒,可以是浮点数
例:
>>>start=time.perf_counter() ==> 194087.2030045
>>>end=time.perf_counter() ==> 194108.093826
>>>end-start ==>20.89082149998285
>>>def wait():
time.sleep(3.3)
>>>wait() #程序将等待3.3秒后再退出
turtle.setup(width,height,startx,starty) #画布的宽度、高度,窗体位置坐标(以屏幕左上参考)
注意:setup()不是必须的
画笔运动命令
forward() #简写fd(),向当前方向前进
backward() #bk(),后退
right() #rt(),右转多少度
left() #lt(),左转多少度
goto(x,y) #画笔移动到坐标x,y位置
penup() #up(),提起画笔
pendown() #down(),放下画笔
circle() #画圆,半径为正,圆心在画笔左侧,反之右侧
speed() #画笔速度[0,10]整数
画笔控制命令
pensize() #画笔宽度
pencolor() #画笔颜色
fillcolor() #填充颜色
color(color1,color2) #pencolor=color1,fillcolor=color2
filling() #返回当前是否填充
begin_fill() #开始填充
end_fill() #填充完成
hideturtle() #隐藏画笔
showturtle() #显示画笔
bgcolor() #背景颜色
bgpic('1.gif') #背景图片
clear() #清空窗口,turtle位置不变
resec() #清空窗口,turtle起始状态
undo() #撤销一个turtle动作
isvisible() #返回当前turtle是否可见
stamp() #复制当前图形
write() #写文本
dot() #以参数为直径画点
setpos(x,y) #设置笔坐标
position() #笔当前坐标
jieba库分词的三种模式
jieba库常用函数
jieba.lcut(s) #精确模式,返回一个列表类型的分词结果
jieba.lcut(s,cut_all=True) #全模式,返回一个列表类型的分词结果,存在冗余
jieba.lcut_for_search(s) #搜索引擎模式,返回一个列表类型的分词结果,存在冗余
jieba.add_word(w) #向分词词典增加新词w
例:
>>>jieba.lcut('中国是一个伟大的国家')
['中国','是','一个','伟大','的','国家']
>>>jieba.lcut('中国是一个伟大的国家',cut_all=True)
['中国','国是','一个','伟大','的','国家']
>>>jieba.lcut_for_search('中华人民共和国是伟大的')
['中华','华人','人民','共和','共和国','中华人民共和国','是','伟大','的']
词云以词语为基本单位,更加直观和艺术地展示文本
WordCloud对象
w=wordcloud.WordCloud() #以WordCloud对象为基础,配置参数,加载文本,输出文件
w.generate(txt) #向wrdcloud对象W中加载文本txt
w.to_file(filename) #将词云输出为图像文件,png或jpg格式
例:
import wordcloud
c=wordcloud.WordCloud() #步骤1:配置对象参数
c.generate('wordcloud by python') #步骤2:加载词云文本
c.to_file(pywordcloud.png) #步骤3:输出词云文件
配置对象参数
width #指定词云对象生成图片的宽度,默认400像素
height #指定词云对象生成图片的高度,默认200像素
min_font_size #指定词云中字体的最小字号,默认4号
max_font_size #指定词云中字体的最大字号,根据高度自动调节
font_step #指定词云中字体字号的步进间隔,默认为1
font_path #指定字体文件的路径,默认为None
max_words #指定词云显示的的最大单词数量,默认200
step_words #指定词云的排除词列表,即不显示的单词列表
background_color#指定词云的背景颜色,默认为黑色
mask #指定词云形状,默认为长方形,需要引用imread()函数
注意:mask的使用
>>>from scipy.misc import imread
>>>mk=imread('pic.png') #图片形状即为词云形状
>>>w=wordcloud.WordCloud(mask=mk)
例:
w=wordcloud.WordCloud(width=600,min_font_size=7,backgroud_color='white')
demo 1
import wordcloud
txt='life is short,you need python'
w=wordcloud.WordCloud(background_color='white')
w.generate(txt)
w.to_file('pywordcloud.png')
demo2
import jieba
import wordcloud
txt="程序··········"
w=wordcloud.WordCloud(width=1000,font_path="msyh.ttc",hight=700)
w.generate(" ".join(jieba.lcut(w.generate(txt)))) #用空格分隔词
w.to_file('pywordcloud.png')