Python_学习记录

源代码编译过程

python => python byte code(python字节码) <= python virtual machine

py => pyc <= pvm

REPL:python控制台:R(read)、E(evaluate)、P(print)、L(loop)

数据类型

数据类型可以粗暴的分为数字类型和非数字类型。

  • 数字类型包括整型、长整型、浮点型和复数型。

  • 非数字型包括字符串、元组、列表和字典。

特点可以归纳为:

  • 非数字类型的共同的:都可以切片、链接(+)、重复(*)、取值(a[0]) 等运算
  • 字符串、列表、元组的截取方式相同:名称[头下标, 尾下标],下标是从0开始算起,可以是正数也可以是负数,下标为空表示取到头或取到尾。开始截取时包含了边界,但不包含结束边界,如name[0,5],取的是0~4不包含5。
  • 非数字类型的不同点:列表可以直接赋值而元组不可以。字典使用dict[key] = value的方式赋值。
  • 元组不能再次赋值,列表可以。

非数字类型

序列

在python中,序列就是一组按顺序排列的值(数据集合)

在python中存在三种内置的序列类型

  1. 字符串
  2. 列表
  3. 元组

优点:

  • 支持索引和切片的操作

特征

  • 第一个正索引为0,指向左端,第一个索引为负数的时候,指向的是右端

列表

特征:

  • 有序
  • 支持增删改查
  • 数据项(数据内容)可变,地址不会改变
  • 用[]表示列表类型,数据项之间用逗号分割,数据项可以是任何类型的数据
  • 支持索引和切片

列表常用方法:

  • listname.append(item) 在列表后面追加元素
  • listname.count(元素) 统计某个元素出现次数
  • listname.extend() 拓展,相当于批量添加
  • listname.index(item) 获取指定元素索引
  • listname.insert(index, item) 在指定位置插入
  • listname.pop([index=-1]) 删除一个元素(默认为最后一个),并返回该元素
  • listname.remove(item) 移除左边找到的第一个元素
  • del listname[下标] 删除列表对应下标的元素
  • listname.reverse() 反转列表
  • listname.sort() 排序;reverse=True 倒序
  • isinstance(listname,list)判断listname是否为列表类型
  • len(listname)数组元素个数
  • listname.clear()清空元素
  • 批量赋值t1,t2,t3,t4 = listnameps:被赋值的变量数量必须和list中的元素数量相当

元组

特征:

  • 不可变序列;创建之后不能修改
  • 不可变
  • () 创建元组类型,数据项用逗号分割
  • 可以是任何类型
  • 元组中只有一个元素时,要加上逗号,否则解释器将会当作整形处理
  • 支持切片

创建:

  • 小括号:tup(item1, item2)
  • 使用构造函数:tup = tuple(item1, item2)
  • 空元组:tup=()tup=tuple()
  • 元组中如果只有一个元素:tup=(item,)

为什么要将元组设计成不可变序列:

  • 多任务环境下,同时操作对象时不需要加锁

注意事项:元组中存储的是对象的引用

  • 元组存储的元素本身是不可变对象如字符串,则不能再改变
  • 但如果存储的是数组,则可以通过数组的方法改变数组内的内容

元组的遍历:

  • for …… in ……
t = tuple(('Python','Hello',90))
for item in t:
	print(item)

修改元组:由于元组不可变,所以不能直接在原有的元组中改变,而是新创建一个元组。如需要拼接两个元组:tup3 = tup1 + tup2

删除元组:元组的元素是不可删除的,但可以用del tup的方式删除整个元组。

字典

特征:

  • 可变
  • 键值对
  • 无序

创建:

  1. {key:value,key2:value2}使用花括号
  2. dict(key=xxx,value=yyyy) :内置函数dict()
  3. 空字典 d={}:字典生成式

获取:

  1. 字典名[key] => 不存在报错
  2. get(key) =>不存在返回none => 可通过 get(key,help) 在不存在指定对应关系时输出help内容

判断:

  1. key in xxx : 判断是否在xxx变量中存在key,存在true,否则false
  2. key not in xxx:判断是否在xxx变量中存在key,存在false,否则true

删除:

  1. del 字典名[key]:删除指定键值对
  2. 字典名.clear():清空指定字典

修改:

  • 字典名[key] = new value :修改值

更新:

  • 字典名.update(另一个字典):将一个字典内容添加到另一个字典中

获取字典视图:

  • keys() :获取字典中所有key
  • values():获取字典中所有的value
  • items():获取所有key.value对

字典元素遍历:

  • for item in xxx

特点:

  • 键值对一一对应,key不允许重复,值可以重复
  • key必须是不可变对象
  • 会占用较大内存
  • 可根据需求动态伸缩

集合

特征:

  • 可变序列
  • python提供的内置数据结构
  • 可以理解为没有value的字典
  • 不能有重复元素(会自动去除)

创建:

  • 使用{}花括号创建
  • set():使用内置函数set()s = set(range(6))
  • 空集合:s = set()

判断:

  • in
  • not in

新增:

  • 集合名.add():一次添加一个
  • 集合名.update():一次添加多个

删除:

  • 集合名.remove():元素不存在则抛出异常
  • 集合名.discard():即使元素不存在也不会抛出异常
  • 集合名.pop():删除任意一个元素(因为集合是无序的)
  • 集合名.clear():清空

集合间的关系:

  • 判断集合之间是否相等 = / !=
  • 判断集合是否是另一个集合的子集 集合A.issubset(集合B) => 是为True
  • 判断集合是否是另一个集合的超集 集合A.issuperset(集合B) => 是为True
  • 判断两个集合是否有交集 集合A.isdisjoint(集合B) => 是为False

集合的数学操作:

# 交集
s1 = {10, 20, 30, 40}
s2 = {20, 30, 40, 50, 60}
print(s1.intersection(s2))  # {20, 30, 40}
print(s1 & s2)  # intersection() 与 & 等价,交集操作

# 并集
s3 = s1.union(s2)  # {10,20,30,40,50,60}
s3_1 = s1 | s2

# 差集
s4 = s1.difference(s2)  # {10}
s4_1 = s1 - s2

# 对称差集
s5 = s1.symmetric_difference(s2)  # {10, 50, 60}
s5_1 = s1^ s2

字符串

字符串特点

特点:

  • 基本数据类型
  • 不可变字符序列
  • 字符串驻留机制:相同的字符串赋值给不同的变量时,不会开辟新的内存空间
字符串驻留机制
  • 字符串的长度为0或1时
  • 符合标识符的字符串(字母数字下划线)
  • 字符串只在编译时进行驻留,而非运行时
  • [-5, 256]
  • sys中的intern方法强制2个字符串指向同一个对象
  • Pycharm对于字符串进行了优化(如使得不符合标识符的字符串也驻留)
a = 'Python'
b = "Python"
c = '''Python'''
print(a,id(a))
print(b,id(b))
print(c,id(c))  # 打印同样的地址

字符串驻留机制的优缺点:

  • 当需要值相同的字符串时,可以直接从字符串池里拿来使用,避免频繁的创建和销毁,提升效率和节约内存,因此拼接字符串和修改字符串是会比较影响性能的
  • 在需要进行字符串拼接时建议使用STR类型的join方法,而非直接使用+,因为join方法是先计算出所有字符串的长度,然后再拷贝,只new一次对象,效率更高
常用方法

字符串常用方法
反向遍历字符串:str[::-1]

查询方法
方法名称作用
index()查找子串substr第一次出现的位置,如果查找的子串不存在则抛出ValueError
rindex()查找子串substr最后一次……
find()查找子串substr第一次出现的位置,不存在返回-1
rfind()……最后一次……
大小写转换
方法名作用
upper()所有字符大写
lower()所有字符小写
swapcase()大变小,小变大
capitalize()首字符大写,其余小写
title()每个单词首字符大写,其余小写

无论是哪种方法都将创建新的字符串对象

对齐
方法名作用
center()居中对齐,第一个参数为指定宽度;第二个为间隔填充符,默认为空格;指定宽度小于实际宽度则返回原字符串
ljust()左对齐……
rjust()右对齐……
zfill()右对齐,左边用0填充,仅接收一个参数:指定宽度,如果指定宽度小于……
拆分
方法名作用
split()从字符串的左边开始拆分,默认的拆分字符是空格字符串,返回的值都是一个列表
通过参数sep指定分割符(分割的依据)
通过参数maxsplit指定拆分字符串时的最大拆分次数,经过最大拆分之后,剩余的子串会单独作为一部分
rsplit()从字符串的右边开始拆分,默认的拆分字符是空格字符串,返回的值都是一个列表
通过参数sep指定分割符
通过maxsplit……
判断
方法名作用
isidentifier()判断是否为合法标识符
isspace()判断是否全部由空白字符组成(回车、换行、水平制表符
isalpha()判断字符串全都由字母组成
isdecimal()判断是否全部由十进制数字组成
isnumeric()判断是否全部由数字组成(包含汉字中的数字和罗马数字)
isalnum()判断是否全部由字母和数字组成
替换、合并
方法名作用
replace()第一个参数:指定被替换的字符串;第二个参数:指定替换的字符串,返回替换后的字符串,替换前的不会变化;第三个参数:指定最大替换次数
join()将列表或元组中的字符串合并成一个字符串(如果参数为字符串而不是列表和元组会将该字符串进行分隔'*'.join('python') => 输出p*y*t*h*o*n
比较

运算符:>、<、==、<=、>=、!=

规则:

  • 首先比较两个字符串中的第一个字符
  • 如果相等则继续比较下一个字符,依次进行,直到两个字符串的字符不相等
  • 比较结果为两个字符串的比较结果
  • 后续字符串中的所有字符将不再被比较

原理:

  • 两个字符进行比较时,比较的是ordinal value(原始值),可通过ord()函数进行比较
  • ord()函数对应chr()函数

==is的区别:
==比较的是内容,is比较的是内存地址

字符串切片

[start:end:step]

s = 'hello,python'
print(s[1:5:1])  # =>out:ello
print(s[::2])  # =>out:hlopto  默认0开始,步长为2,两个元素之间的索引间隔为2
print(s[::-1])  # =>out:nohtyp,olleh  倒序
print(s[-6::1])  # =>out:python  以最后一位作为0,则p为-6
格式化输出

方式一:

  • %s :字符串
  • %i / %d :整数
  • %f :浮点数
name = '张三'
age = 20
print('%s今年%d岁' % (name,age))

方式二:
{}

print('我叫{0},今年{1}'.format(name,age))

方式二plus:推荐

print(f'{name}今年{age}岁')

注意:

  • %10d 10代表宽度,不足则在前方补空格
  • %.3f .3表示精度:保留浮点数的三位小数
  • 宽度和精度可以同时使用
  • 方式二 可以通过print('{0:.3}'.format(3.1415926))实现保留三位数的效果,而不是三位小数,如果仅为了保留三位小数则格式为**{0:.3f}**;同时保有精度和宽度:{:10.3f},0为占位符顺序,可省略
字符串的编码转换
s = '天涯共此时'
# 编码
s.encode(encoding='GBK')  # GBK编码格式中 中文占两个字节
s.encode(encoding='UTF-8')  # UTF-8格式中,中文占三个字节
# 解码
byte = s.encode(encoding='GBK')  # 编码
byte.decode(encoding='GBK')  # 解码

python3种bytes、hex、字符串之间相互转换
  1. 字符串转bytes
"""
eg:
'0123456789ABCDEF0123456789ABCDEF'
b'0123456789ABCDEF0123456789ABCDEF'
"""
def stringTobytes(bs):
    return bytes(bs, encoding='utf8')
  1. bytes转字符串
'''
eg:
b'0123456789ABCDEF0123456789ABCDEF'
'0123456789ABCDEF0123456789ABCDEF'
'''
def bytesToString(bs):
    return bytes.decode(bs, encoding='utf8')
  1. 十六进制字符串转bytes
'''
eg:
'01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF'
b'\x01#Eg\x89\xab\xcd\xef\x01#Eg\x89\xab\xcd\xef'
'''
def hexStringTobytes(bs):
    bsr = bs.replace(" ", "")
    return bytes.fromhex(bsr)
    # return a2b_hex(str)
  1. bytes转十六进制字符串
'''
eg:
b'\x01#Eg\x89\xab\xcd\xef\x01#Eg\x89\xab\xcd\xef'
'01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF'
'''
def bytesToHexString(bs):
    return ''.join(['%02X ' % b for b in bs])

数字类型

具体可以分为以下四种

  1. 整型int
  2. 长整型long integers
  3. 浮点型float
  4. 复数complex:由实数和虚数组成,可以用a + bjcomplex(a, b)表示,复数的实部a和虚部b都是浮点型

数学函数math、cmath

math提供了许多对浮点数的数学运算函数

cmath更多是针对复数的运算

函数描述
abs(x)返回数字的整型绝对值(内置函数)
fabs(x)返回数字的浮点型绝对值(math)
ceil(x)向上取整
cmp(x, y)x<y返回-1,x=y返回0,x>y返回1
exp(x)返回e的x次幂,如math,exp(1)返回2.71828…

Python Number(数字)

数据类型转换

描述函数
int(x)将x转换为整数
long(x)将x转换为长整数
float(x)将x转换为浮点数
complex(real)创建一个复数
str(x)将对象x转换为字符串
repr(x)将对象x转换为表达式字符串,即会在字符串外面再包裹一层引号,这在使用eval()时体现了repr()的特殊效果。
eval(x)计算再字符串中的有效python表达式,并返回一个对象,目前常用于字符串转字典
tuple(s)将序列s转换为一个元组
list(s)将序列s转换为一个列表
set(x)转换为可变集合
dict(d)创建一个字典,d必须是一个序列(key, value)元组
frozenset(s)转换为不可变集合
chr(x)将一个整数转换为一个字符
unichr(x)将一个整数转换为Unicode字符
ord(x)将一个字符转换为它的整数值
hex(x)将一个整数转换为16进制字符串
oct(x)将一个整数转换为一个8进制字符串

运算符

运算符分类

运算符类型运算符
算术运算符①加+;②减-;③乘*;④除/;⑤取余%;⑥幂**;⑦向下取整除//
比较运算符①等于==;②不等于!=;③大于>;④小于<;⑤大于等于>=;⑥小于等于<=
赋值运算符①赋值=;②加法赋值+=;③减法赋值-=;④乘法赋值*=;⑤除法赋值/=;⑥取模赋值%=;⑦幂赋值**=;⑧取整除赋值//=
位运算符①按位与&:参与运算的两个值,如果相应位都是1则该位为1否则为0;②按位或`
逻辑运算符① 布尔与and:左右两边都为真时结果为真,只有左侧的为真才会执行右侧的表达式;②布尔或or:左右两边只要有一个为真时结果为真;③布尔非not:取反
成员运算符①在…之中in:能够在指定的序列当中找到该值为真,否则为假;②不在…之中not in:在指定序列当中找不到该值为真,否则为假
身份运算符①判断两个标识符是不是引用自同一个对象is;②判断两个标识符是不是引用自不同对象is not

优先级

由高到低,同一类型越靠前优先级越高

  1. 指数:**
  2. 按位翻转、一元加号和减号:~+@-@
  3. 乘、除、取模和取整除:*/%//
  4. 加、减:+-
  5. 左移、右移:>><<
  6. 位与:&
  7. 位或:^|
  8. 比较:<=>=<>
  9. 等于:==!=
  10. 赋值:=%= /= //= -= +=*= **=
  11. 身份:isis not
  12. 成员:innot in
  13. 逻辑:notandor
  14. 匿名函数:lambda

注意点

  1. ==is是不同的,前者比较的是两者的值,而后者比较的是两者的地址。在使用它们进行比较时需要慎重。
  2. 赋值列表时有两种方式:①a = b;②a = b[:]。两者结果一致,但区别在于前者是传递引用,仍然是同一个对象;后者是拷贝,创建了新的对象

流程控制

在使用流程控制前,需要提前了解的是:在python中,任何非0和非空(null)的布尔值都为True,与之相反的0和空为False。

条件判断

在使用流程控制时,可以配合逻辑运算符使用:

a = 0
b = 1
# 以下程序不会报错
if a > 0 and b / a > 2:
    print('yes')
else:
    print('no')
# 以下程序会报错
if (b/a > 2):  
    ...

在python中没有switch,但可以手动实现:

def zero():
    return '0'
def one():
    return '1'
...
def num2str(arg):
    # 使用字典映射
    switcher = {
        0: zero,
        1: one,
        2: lambda: "three"
    }
    func = switcher.get(arg, lambda:"nothing")
    return func

num2str(0)

简单的条件判断可以缩写至一行内:

a = [1, 2, 3]
b = a if len(a) != 0 else ''

循环

循环种类:

  • for
  • while
  • 嵌套

循环控制:

  • break:跳出最深层循环
  • continue:跳过本次循环,执行下一次循环
  • pass:空语句,使流程控制的结构完整

while注意点

  1. 循环可以在不满足条件时执行else语句,即循环不是通过break退出时,如:
a = 0
while a < 5:
    a += 1
    print(a)
else:
    print(a)
  1. 类似于if语句,当循环体中只有一条语句可以缩写至一行:
flag = 1
while (flag): print("flag is true")

for注意点

  1. 通过序列索引迭代:
fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
    print(f'下标:{index},值为:{fruits[index]}')
  1. for循环与while循环一样可以使用else语句,同样是在循环正常执行完(非break跳出而中断)的情况下使用,while…else也是。
  2. for循环可以结合enumerate()内置函数使用,该函数会将一个可遍历对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标:如下所示
sequence = [12, 34, 56, 66]
for index, item in enumerate(sequence):
    print(index, item)
# 输出如下
'''
0 12
1 34
2 56
3 66
'''

函数

参数传递

  • 位置实参:根据位置传递
  • 关键字实参:根据形参的名称传递
  • 在函数调用过程中,进行参数的传递:如果是不可变对象,在函数体的修改不会影响实参的值,如字符串;如果是可变对象,在函数体内的修改会影响到实参的值,如列表
  • 如果函数的参数有默认值,在传递参数时新传递的参数会替代默认参数,如不传递则会使用默认参数
  • 如果不确定需要传递参数的个数,则可以使用可变的位置参数可变的关键字参数,分别使用***定义,结果分别为元组字典但它们都只能定义一个,且如果同时使用可变的位置参数和可变的关键字参数,要求个数可变的位置形参放在个数可变的关键字形参之前,它们又称为不定长参数
# 可变的位置参数
def fun(*args):

# 可变的关键字参数
def fun(**args):
  • 调用时将序列中的每个元素都转换为位置实参:使用*
  • 调用时将序列中的每个元素都转换为关键字实参:使用**(如字典)
  • 定义时使用*分隔形参的作用:规定*后面的形参只能使用关键字传参的方式
def fun(a,b,*,c,d):
	print(a,b,c,d)

fun(10,20,30,40)  # 报错:*号之后的形参需要使用关键字参数传递
fun(10,20,c=30,d=40)
fun(a=10,b=20,c=30,d=40)

函数定义时形参的顺序问题

def fun(a,b,*,c,d,**args):
	pass
def fun1(*args,**args2):
	pass
def fun2(a,b=10,*args,**args2):
	pass

返回值

  • 如果没有返回值(函数执行完之后不需要给调用处提供数据):return可以省略不写
  • 函数的返回值,如果是单个,直接返回返回值类型的返回值
  • 函数的返回值如果是多个,返回的结果是元组

变量的作用域

  • 局部变量:函数内定义并使用的变量,仅在函数内部可用,局部变量使用global声明则变为全局变量
  • 全局变量:函数外定义

递归

阶乘

def fac(n):
	if n == 1:
		return 1
	else:
	return n * fac(n-1)

斐波那契数列

def fib(n):
	if n == 1:
		return 1
	elif n == 2:
		return 1
	else:
		return fib(n-1)+fib(n-2)

# 输出这个数列的前六位
for i in range(1,7)
	print(fib(i))
"""
	range() :创建一个整数列表,一般在for循环中使用
	语法:range(start, stop [,step])  
		start 默认为0,为0时可省略
		stop 计数到stop结束,但不包括stop
		step 步长默认为1,为1时可省略
"""

常用内置函数

Python 内置函数 | 菜鸟教程 (runoob.com)

多个值分割转为整形

a,b,c,d = map(int,input('输入4个值,用空格分隔').split())

round()

会像最靠近的偶数取整

print(round(3.5)) # 4
print(round(4.5)) # 4

math.ceil()向上取整

按需导入模块中的函数

  • from 模块 import 函数

导入模块中的所有函数

  • from 模块 import *

python使用cmd指令

  • import os
  • Dir(os)查看os有什么函数
  • help(os.system)查看os.system的具体说明
  • 如:os.system('cls') 清屏

range()

  • range(start, stop[, step])
  • start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
  • stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
  • step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)

判断数据类型

type()

type(obj)输出该变量的数据类型

instance()

instance(x, type),如果x是type类型的话输出True,否则输出False

结论:在判断数据类型时需要使用instance()

因为它可以精确的判断出实例是否是某类或者其子类,而如果类的继承方式不是使用新式类的继承方式,将不能保证正确的输出。而造成这种结果的原因是type是值比较,而instance是地址比较。

魔法方法

  • __开头和结尾的方法称为魔法方法
    __init__(self[,……])ps:相当于其他语言的构造方法

  • __init__方法不能有任何return

  • __new__(cls[,……]):实例化对象时调用的第一个方法,一般不需要去重写它,但当继承不可变类型但却又需要修改时它就显得尤为重要

class CapStr(str):
	def __new__(cls, string):
		string = string.upper()
		return str.__new__(cls, string)
		'''
		将传入的内容转化为大写
		步骤:
		1.传入字符串
		2.调用__new__方法
		3.将传入的string变为大写
		4.将变化后的string交给str基类中的__new__方法处理,生成一个字符串
		'''
  • __del__:不管是手动调用del还是由Python自动回收都会触发__del__方法执行,ps:del引用并不会触发del
魔法方法作用
__add__(self,other)定义加法的行为:+
__sub__(self,other)定义减法的行为:-
__mul__(self,other)定义乘法的行为:*
__truediv__(self,other)定义除法的行为:/
__floordiv__(self,other)定义整数除法的行为://
__mod__(self,other)定义取模算法的行为:%
__divmod__(self,other)定义当被divmod()调用时的行为
__pow__(self,other[,modulo])定义当被power()调用或**运算时的作用
__lshift__(self,other)定义按位左移位的行为:<<
__rshift__(self,other)定义按位右移位的行为:>>
__and__(self,other)定义按位与操作的行为:&
__xor__(self,other)定义按位异或操作的行为:^
__or__(self,other)定义按位或操作的行为:`

简单定制

基本要求:

  • 定制一个计时器的类
  • startstop方法代表启动计时和停止计时
  • 假设计时器对象t1,print(t1)和直接调用t1均显示结果
  • 当计时器未启动或已经停止计时,调用stop方法会给予温馨提示
  • 两个计时器对象可以进行相加:t1+t2
  • 只能使用提供的有限资源完成:
  • (1)使用time模块的localtime方法获取时间
  • (2)time.localtime返回struct_time的时间格式
  • (3)重写__str____repr__实现在print和直接调用时显示结果
import time


class MyTimer:
    def __init__(self):
        self.unit = ['年', '月', '日', '时', '分', '秒']
        self.prompt = '未开始计时'
        self.lasted = []
        self.startTime = 0
        self.stopTime = 0
    def __str__(self):
        return self.prompt
    __repr__ = __str__
    def __add__(self, other):
        prompt = '总共运行了'
        result = []
        for index in range(6):
            result.append(self.lasted[index] + other.lasted[index])
            if result[index]:
                prompt += (str(result[index]) + self.unit[index])
        return prompt
    def start(self):
        self.startTime = time.localtime()
        self.prompt = '提示:请先调用stop() 停止计时'
        print('开始计时')
    def stop(self):
        if not self.startTime:
            self.prompt = '提示:请先调用start() 开始计时'
        else:
            self.stopTime = time.localtime()
            self._calc()
    def _calc(self):
        self.lasted = []
        self.prompt = '共运行了'
        for index in range(6):
            self.lasted.append(self.stopTime[index] - self.startTime[index])
            if self.lasted[index]:
                self.prompt += (str(self.lasted[index]) + self.unit[index])
        self.startTime = 0
        self.stopTime = 0

属性访问

  • __getattr__(self, name):定义当用户试图获取一个不存在的属性时的行为
  • __getattribute__(self, name):定义当该类的属性被访问时的行为
  • __setattr__(self, name, value):定义当一个属性被设置时的行为
  • __delattr__(self, name):定义当一个属性被删除时的行为
# 创建一个矩形类,当设置属性为square时设置长宽相同并计算面积
class Rectangle:
    def __init__(self, w=0, h=0):
        self.w = w
        self.h = h

    def __setattr__(self, name, value):
        if name == 'square':
            self.w = value
            self.h = value
            print('this is a square')
        else:
            super().__setattr__(name, value)
            # self.__dict__[name] = value

    def getArea(self):
        return self.w * self.h

property原理

描述符:将某种特殊类型的类的实例指派给另一个类的属性

  • __get__(self, instance, owner):用于访问属性,返回属性的值
  • __set__(self, instance, value):将在属性分配操作中调用,不返回任何内容
  • __delete__(self, instance):控制删除操作,不返回任何内容
# 案例:摄氏度和华氏度转换
class Celsius:
    def __init__(self, value=26.0):
        self.value = value

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = float(value)


class Fahrenheit:
    def __get__(self, instance, owner):
        return instance.cel * 1.8 + 32
    def __set__(self, instance, value):
        instance.cel = (float(value) - 32) / 1.8


class Temperature:
    cel = Celsius()
    fah = Fahrenheit()


temp = Temperature()
temp.cel = 30  # 赋值摄氏度
print(temp.fah)  # =>86

temp.fah = 100
print(temp.cel)  # =>37.77777777777778

协议

protocols(协议):与其他语言的接口类似,规定哪些方法必须定义。然而在Python中的协议并不是很正式,实际上更像是指南

DuckTyping:当看到一只鸟走起来像鸭子,游泳起来像鸭子,叫也像鸭子,那么这只鸟就可以被称为鸭子

定制类型的协议

  • 如果希望定制的容器是不可变的话,只需要定义__len__()__getitem__()方法
  • 如果希望定制的容器是可变的,除了__len__()__getitem__()方法,还需要定义__setitem__()__delitem__()方法
"""不可变自定义列表,记录列表中每个元素被访问的次数"""


class CountList:
    def __init__(self, *args):
        self.values = [x for x in args]
        self.count = {}.fromkeys(range(len(self.values)), 0)
    def __len__(self):
        return len(self.values)

    def __getitem__(self, item):
        self.count[item] += 1
        return self.values[item]


c1 = CountList(1,2,3,4,5)
c2 = CountList(2,4,5,6,10)
print(c1[1])  # =>2
print(c2[1])  # =>4
print(c1[1] + c2[1])  # =>6
print(c1.count)  # =>{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
print(c1[1])  # =>2
print(c1.count)  # =>{0: 0, 1: 3, 2: 0, 3: 0, 4: 0}

迭代器(iter)

  • for循环
  • iter():创建一个迭代器对象;它自带一个魔法方法:__iter__(),返回它本身
  • next():输出下一个值,如果没有下一个值,则抛出StopIteration异常;它自带一个魔法方法:__next__(),规定了迭代器的规则
string = "hello Python"
it = iter(string)
while True:
	try:
		each = next(it)
	except StopIteration:
		break
	print(each)

# 迭代器魔法方法的使用
class Fibs:
	def __init__(self, n=10):
		self.a = a
		self.b = b
		self.n = n
	def __iter__(self):
		return self
	def __next__(self):
		self.a, self.b = self.b, self.a + self.b
		if self.a > self.n
			raise StopIteration  # 超过10就手动抛异常
		return self.a
fibs = Fibs(100)  # 迭代值为100的斐波那契数列
for each in fibs:
	print(each)  # 输出1~100中的斐波那契数列

生成器(yield)

  • 协同程序:可以运行的独立函数调用,函数可以暂停或者挂起,在需要的时候从程序离开的地方继续或重新开始
  • 是一个特殊的迭代器

BUG

  • SyntaxError 语法错误
  • indexError 索引越界
  • indentationError:缩进错误
  • 思路不清 =》print打印输出的内容确认是否是需要的类型;注释部分代码排查错误

异常处理

出现例外情况

  • 异常处理try……except(相等于Java的try catch)
  • 多个except结构:捕获异常的顺序按照先子类后父类的顺序,为了避免遗漏可能出现的异常,可以在最后增加BaseException
  • try……except……else 如果try块中没有抛出异常,则执行else块,如果抛出异常则执行except块
  • try……except……else……finally finally块无论是否发生异常都会被执行,常用于释放try块中申请的资源

常见的异常类型

异常类型描述
ZeroDivisionError除(或取摸)零(所有数据类型)
IndexError序列中没有此索引
KeyError映射中没有这个键
NameError未声明/初始化对象(没有属性)
SyntaxError语法错误
ValueError传入无效参数
URLErrorurllib库的error模块
HTTPError是URLError的子类;code:返回状态码;reason:返回错误原因;headers:返回请求头
处理http异常的方式

Python 异常处理 | 菜鸟教程 (runoob.com)

手动抛异常

Python raise用法
raise

raise [exceptionName [(reason)]]

其中,用 [] 括起来的为可选参数,其作用是指定抛出的异常名称,以及异常信息的相关描述。如果可选参数全部省略,则 raise 会把当前错误原样抛出;如果仅省略 (reason),则在抛出异常时,将不附带任何的异常描述信息。

也就是说,raise 语句有如下三种常用的用法:

  1. raise:单独一个 raise。该语句引发当前上下文中捕获的异常(比如在 except 块中),或默认引发 RuntimeError 异常。
  2. raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常。
  3. raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息。
  4. 在使用 raise 语句时可以不带参数
try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise ValueError("a 必须是数字")
except ValueError as e:
    print("引发异常:",repr(e))
    raise

程序执行结果为:

输入一个数:a
引发异常: ValueError('a 必须是数字',)
Traceback (most recent call last):
  File "D:\python3.6\1.py", line 4, in <module>
    raise ValueError("a 必须是数字")
ValueError: a 必须是数字

这里重点关注位于 except 块中的 raise,由于在其之前我们已经手动引发了 ValueError 异常,因此这里当再使用 raise 语句时,它会再次引发一次。

当在没有引发过异常的程序使用无参的 raise 语句时,它默认引发的是 RuntimeError 异常。例如:

try:
    a = input("输入一个数:")
    if(not a.isdigit()):
        raise
except RuntimeError as e:
    print("引发异常:",repr(e))

程序执行结果为:

输入一个数:a
引发异常: RuntimeError('No active exception to reraise',)

Trackback模块

import traceback
try:
	print('------------')
	num = 10 / 0
except:
	traceback.print_exc()
	# 会打印出异常的信息,作用是更方便后续存储为log日志

类、对象

class Student:
	native_pace = '福建'  # 成员变量(类属性),被该类的所有对象共享
	def __init__(self, name, age):
		self.name = name  # self.name 为实体属性,将局部变量赋值给实体属性
		self.age = age

	# 实例方法
	def eat(self):
		pass

	# 静态方法 , 使用类名直接访问
	@staticmethod
	def method():
		pass  # 静态方法不需要self,使用staticmethod静态修饰符修饰

	# 类方法 , 使用类名可以直接访问
	@classmethod
	def cm(cls):
		pass  # 类方法需要传递cls参数,使用classmethod修饰符修饰

使用类中的方法:

stu = Student('张三', 20)
stu.eat()  # 对象名.方法名()

Student.eat(stu)  # 与上一行代码功能相同,都是调用了同一个方法
# 不同的是传递的参数形式不同,实际上传入的位置是self
# 类名.方法名(实例对象)

# 类方法和静态方法的使用
Student.cm()
Student.method()

动态绑定属性和方法

类可以创建N个该类的实例对象,每个实例对象的属性不同

stu = Student('张三',20)
stu.sex = '女'  # 动态绑定属性

def show():  # 类外面的函数
	pass
stu.show = show  # 动态绑定方法
stu.show()

面向对象

面向对象编程:OOP

面向过程:注重每一个步骤

面向对象:注重结果

类的组成

  1. 名称
  2. 属性
  3. 方法

类是对象的抽象,对象是类的实例。

类分为:经典类 和 新式类。

类的创建:

class ClassName:
    # 类名后不管加不加括号`()`都会继承元类`type`
    pass

cl1 = ClassName()

类本身也是对象。

对象的属性

查看对象中的所有属性:

对象.dict : cl1.__dict__

对象.属性名 : cl1.att1 = "属性1"

类对象.属性名 : ClassName.att2 = "类对象属性"

del 对象.属性:del cl1.att1

del 类对象.属性: del ClassName.att

非可变类型等同于重新赋值 (内存地址被改变)。

可变类型(如列表)通过列表的方法修改 (内存地址不变)。

类对象同理

通过对象去访问对象的属性: print(cl1.att1)

如果在对象中找到了相应的属性,则优先使用,

如果没有找到相应的属性,则会通过__class__到对象的父类当中去查找;故而如果可以中途改变__class__的指向,改变该对象的父类。

所以想要查找类对象的属性,既可以通过对象去访问父类的方式(前提是对象中没有这个属性,是由父类继承而来),也可以通过 类对象.属性名 print(ClassName.att) 的方式查找。

可以通过id(对象.属性名)的方式验证属性的内存地址的方式验证。

总结

以上通过 对象.属性名的方式去增删改查,实际上都是通过对象的__dict__属性进行操作。

默认情况下类对象的__dict__是只读的,当后续可以通过其他函数进行操作如(setattr)。

对象在正常情况下可以肆无忌惮的添加属性,这就降低了类对象对其的约束,故而可以在类对象中添加__slots__属性约定对象可以添加的属性如__slots__ = ["age"],之后对象如果添加不在约定范围内的属性则会报属性不存在

对象的方法

方法的划分:

  • 实例方法

    默认第一个参数接收一个实例对象

  • 类方法

    默认第一个参数接收一个类对象

  • 静态方法

    没有默认参数

class Person:
    def test1(self):
        # 实例方法
        pass

    @classmethod
    def test2(cls):
        # 类方法
        pass


    @staticmethod
    def test3():
        # 静态方法
        pass

ps:直接通过类名去访问实例方法,且没有传递参数会报错:缺少实例对象。

方法的调用:

  • 实例方法

    标准调用:使用实例去调用实例方法,不需要手动传默认参数

    其他调用:1使用类调用 2找到函数本身调用(因为对象中的方法实际上也是位于__dict__的键值对的值中)

  • 类方法

    标准调用:使用类去调类方法

    其他调用:1.使用实例调用(实例会被忽略,实例对应的类不会被忽略)2.使用子类调用父类的类方法。

封装

  • 提高程序的安全性
  • 如果不希望在类对象外部访问,前面加两个** _**,但仍然可以通过dir()查询到该方法并使用(如在类中定义一个属性__age = 20,通过实例对象.__age无法使用该属性,但通过查询dir(实例对象);可以得知它的属性名被更改为_Student__age,使用实例对象._Student__age依然可以使用)

继承

  • 提高复用性
  • 如果一个类没有继承任何类,则默认继承object
  • python支持多继承
  • 定义子类时,必须在其构造函数中调用父类的构造函数
class Person:  # 默认继承object
	def __init__(self,name,age):
		self.name = name
		self.age = age
	def info(self):
		print(self.name, self.age)

class Student(Person):
	def __init__(self,name,age,stu_no):
		super().__init__(name,age)
		self.stu_no = stu_no

class Teacher(Person):
	def __init__(self,name,age,techOfYear):
		super().__init(name,age)
		self.techOfYear = techOfYear

stu = Student('张三', 20, '1001')
teacher = Teacher('李四', 30, 5)

stu.info()  # out:张三 20
teacher.info()  # out:李四 30
# 该方法都是从Person类继承过来的

方法重写

class Student(Person):
	def __init__(self,name,age,stu_no):
		super().__init__(name,age)
		self.stu_no = stu_no
	# 重写Person类中的info方法
	def info(self):
		super().info()  # 仍然需要父类方法中的内容
		print(self.stu_no)

object类

  • object类是所有类的父类,因此所有类都有object类的属性和方法
  • 内置函数dir() 可以查看指定对象所有的属性
  • object有一个__str__ 方法,用于返回一个对于对象的描述,对应内置函数str()经常用于print()方法,帮助用户查看对象的信息,所以用户经常会将__str__()重写
class Person(object):
	def __init__(self, name, age):
		self.name = name
		self.age = age
	def info(self):
		print('姓名:{0},年龄{1}'.format(self.name,self.age))
	def __str__(self):
	return '姓名:{0},年龄{1}'.format(self.name,self.age)

o = object()
p = Person('jack', 20)
print(dir(o))
print(dir(p))
print(p)  # out:姓名:jacl,年龄20

多态

  • 多态即多种形态
  • 指的是:即使不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用的类型,动态决定调用哪个对象中的方法

静态语言和动态语言关于多态的区别

静态语言实现多态的三个必要条件

  • 继承
  • 方法重写
  • 父类引用指向子类对象

动态语言的多态崇尚鸭子类型当看到一只鸟走起来像鸭子、游泳像鸭子、吃像鸭子,那么这只鸟就可以被称为鸭子。在鸭子类型中,不需要关心对象到底是什么类星星,到底是不是鸭子,只关心对象的行为

特殊属性和特殊方法

名称描述
特殊属性__dict__获得类对象或实例对象所绑定的所有属性和方法的字典
特殊方法__len__()通过重写__len__()方法,让内置函数__len__()的参数可以是自定义类型
__add__()通过重写__add__()方法,可使用自定义对象具有”+“功能
__new__()用于创建对象
__init__()对创建的对象进行初始化
"""
实现两个对象相加的操作
"""
class Student:
	def __init__(self,name):
		self.name = name
	def __add__(self, other):
		return self.name + other.name
	def __len__(self):
		return len(self.name)  # 调用此方法返回name长度

stu1 = Student('张三')
stu2 = Student('李四')
s = stu1 + stu2
print(s)  # out:张三李四

类的赋值与浅拷贝

变量的赋值操作:

  • 只是形成了两个变量,实际上还是指向同一个对象

浅拷贝:

  • python拷贝一般是浅拷贝,拷贝时,对象包含的子对象内容不拷贝,因此,源对象与拷贝对象会引用同一个子对象
class Cpu:
	pass
class Disk:
	pass
class Computer:
	def __init__(self,cpu,disk):
		self.cpu = cpu
		self.disk = disk

"""
1.变量的赋值
"""
cpu1 = Cpu()
cpu2 = cpu1
print(cpu1)
print(cpu2)  # 相等

"""
	2.类的浅拷贝
"""
disk = Disk()  # 创建硬盘类对象
computer = Computer(cpu1, disk)  # 创建一个计算机类的对象

import copy
computer2 = copy.copy(computer)
print(computer, computer.cpu, computer.disk)
print(computer2, computer2.cpu, computer2.disk)  # 输出结果仅computer和computer2不同,其他两项相同,证明在浅拷贝过后,子对象不变

深拷贝:

  • 使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象不相同
computer3 = copy.deepcopy(computer)
print(computer, computer.cpu, computer.disk)
print(computer3, computer3.cpu, computer3.disk)  # 输出结果都不相同

补充

元类 -> type

创建类对象

  1. 通过关键字class
  2. 通过元类:class_name = type("ClassName",(父类),__dict__)

类对象的创建流程及方式:

  1. 检测类中是否有明确的__metaclass__属性
  2. 没有就到父类中查找是否存在__metaclass__属性
  3. 没有就到模块(当前的py文件)中查找是否有__metaclass__属性
  4. 都没有就通过type创建这个类对象

类的描述

class ClassName:
    """
    在此处输入类的描述,作用,属性
    Attributes:
        属性的描述
    """
    def test(self, param1, param2):
      """
      在此处输入方法的描述
      :param param1: 参数的含义, 类型, 是否有默认值
      :param param2: ----
      :return: 返回值的含义, 类型
      """
      print(self, param1, param2)


help(ClassName)  # 通过help可以生成文档

生成项目文档:
使用内置模块:pydoc

私有化属性

python中只有伪私有化,即通过下划线来规定私有属性。

公有属性单下划线私有属性双下划线私有属性
在所有区域都能被访问在类的内部和子类的内部可以被访问,其他区域会警告但仍可被访问只有类内部能访问,其他均不能

注意:私有属性可以通过在被访问的文件中添加__all__,让其他模块访问私有属性且不会警告和报错。

私有属性的实现机制:名字重整(Name Mangling)

应用场景:

  • 数据保护
  • 数据过滤

补充:xxx_这样的变量名是为了与系统变量做区分如id_,__xxx__则是系统内置的属性或方法

只读属性

方案1

  1. 私有化:通过双下划线方式实现
  2. 部分公开: 单独定义一个实例方法用于返回属性
  3. 优化: 通过修饰器property以使用属性的方式使用方法
class Person(object):
  def __init__(self):
    slef.__age = 18
    
  @property
  def age(self):
      return self.__age 


p = Person()
print(p.age)  # 可以得到__age的值
# p.age = xxx  # 不能修改,会报错没有这个属性 
装饰器property

property的两种使用方式

class C(object):
    def getx(self):return self._x
    def setx(self, value):self._x = value
    def delx(self): del self._x
    x = property(getx, setx, delx, f"x属性")
    
    
class D(object):
  @property
  def x(self):
    # "x属性"
    return self._x
  
  @x.setter
  def x(self, value):
    self_x = value
    
  @x.deleter
  def x(self):
    del self._x

补充: 经典类和新式类

  • 经典类:没有继承object
  • 新式类:继承了object

在python2.x中,没有显式的继承object则这个类是经典类,必须显式继承(写在括号里)才是新式类,而到了python3.x中,默认情况下隐式继承object,但仍建议显示继承

经典类中的property与新式类不同,经典类不能使用除property的getter以外的修饰方法

模块

  • Modules
  • 一个 .py 文件就是一个模块
  • 可以包含若干个函数、类、变量
  • 优点:方便其他程序和脚本的导入使用;避免函数名和变量名冲突;提高代码的可维护性;提高代码的可重用性

查看模块内的内容

  • id() 查看内存地址
  • type() 类型
  • dir() 查看模块内都有什么

以主程序形式运行

if __name__ == '__main__':下的代码块
只有通过自身执行时才会输出的内容,如果通过其他文件进行导入使用则不会执行

  • 分层次的目录结构
  • 目的是整合功能相近的模块
  • 作用是使代码规范;避免模块名称冲突
  • 包与目录的区别:包含__init__.py的目录称为包;目录里通常不包含__init.py文件
  • 导入 import 包名只能导入包、模块,使用from……import……能导入包、模块、函数、变量

常用内置模块

常用内置模块

第三方模块的安装使用

  • 在线安装:pip install 模块名
  • 验证安装:import 模块

常用模块的使用

时间模块time和datetime

import timeimport datetime

本地时间:time.localtime(time.time())

格式化时间:time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

反格式化时间:time.strptime(时间字符串, 时间格式)

延迟:time.sleep(秒)

datetime模块相当于对time进行了封装,常用的有:datetime.datetimedatetime.timedalta,具体的方法如下:

  • datetime.year
  • datetime.month
  • datetime.day
  • datetime.hour
  • datetime.minute
  • datetime.second
  • datetime.tzinfo时区
  • datetime.date()返回date对象
  • datetime.time()返回time对象
  • datetime.timetuple返回time.struct_time对象
  • datetime.strftime()datetime.strptime()

datetime类本身也有些方法如:datetime.today()/datetime.now()

文件操作

编码格式

  • 常见的字符编码格式
  1. python的解释器使用的是Unicode(内存)
  2. .py文件在磁盘上使用的是UTF-8(外存)
  • 在开头注释#encoding=gbk的方式可以改变文档的编码格式
  • 不同编码格式的文档大小不同

读取键盘输入

  • raw_input("请输入:"):获取用户输入的任意字符串
  • input("请输入:")

文件的读写原理(IO)

  • 队列:先进先出
  • 内置函数open()创建文件对象。格式:file = open(filename [,mode. encoding])
  • file:被创建的文件对象;open:创建文件对象的函数;filename:要创建或打开的文件名称;mode:打开模式默认为只读'r';encoding:默认文本文件.txt中字符的编写格式为gbk

常用文件打开模式

文件打开模式mode

文件对象的常用方法

文件对象的常用方法

WITH语句(上下文管理器)

with语句可以自动管理上下文资源,不论什么原因跳出with块都可以保证文件正确的关闭以达到释放资源的目的

  • with open('logo.png', 'rb') as src_file
  • 可以将with语句分为两部分:with之后as之前
  • as之前的内容称为上下文表达式,结果为上下文管理器,同时会创建一个运行时上下文
  • 相当于自动实现了__enter__()__exit__()方法
  • 无论语句内是否存在错误都将在执行完之后自动释放资源

目录操作

os模块

  • 是python内置的与操作系统功能和文件系统相关的模块,该模块中的语句的执行结果通常与操作系统有关,在不同的系统上运行,得到的结果可能不同
  • 该模块与os.path模块用于对目录或文件进行操作

os模块操作目录相关函数

os.path模块操作目录相关函数

os.path模块操作目录相关函数

"""
	案例:打印出所有当前目录下的.py文件
"""
import os
path = os.getcwd()
lst = os.listdir(path)
for filename in lst:
	if filename.endswith('.py'):
		print(filename)

"""
	案例2:打印当前目录(包含子目录)下的所有文件
"""
import os
path = os.getcwd()
lst_files = os.walk(path)  #os.walk 可以遍历指定目录下的所有文件及目录,类似递归操作
for dirpath, dirname, filename in lst_files:
	print(dirpath)  # 路径
	print(dirname)  # 文件夹
	print(filename)  # 文件
	for dir in dirname:
		print(os.path.join(dirpath, dir))  # 拼接操作,输出当前目录下所有子路径
	for file in filename:
		print(os.path.join(dirpath, file))  # 输出所有文件的路径

爬虫

python如何访问互联网

  • URL
  • lib
  • URL+lib = URLLIB
import urllib.request
res = urllib.request.urlopen("http://wwww.fishc.com")
html = res.read()
print(html.decode("utf-8"))

案例:爬取有道翻译接口翻译

import urllib.request as ur
import urllib.parse as up
import json
# 方法1:添加访问延迟
import time

while True:
	content = input('输入需要翻译的内容:')
	if content == 'q!':
		break
	url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
	
	# 在此基础上增加上防止被当作频繁访问的非正常用户过滤的头文件
	head = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66 '}
	
	data = {'i': content, 'from': 'AUTO', 'to': 'AUTO', 'smartresult': 'dict', 'client': 'fanyideskweb',
	        'salt': '16100780760685', 'sign': '98955f990c05972ae4ae00da51c4e60e', 'lts': '1610078076068',
	        'bv': 'e352c26cfcd0c5f4e08ab85e750e759a', 'doctype': 'json', 'version': '2.1', 'eyfrom': 'fanyi.web',
	        'action': 'FY_BY_REALTlME'}
	
	data = up.urlencode(data).encode('utf-8')
	
	res = ur.urlopen(url, data)
	html = res.read().decode('utf-8')
	
	target = json.loads(html)
	print('翻译结果:%s' % (target['translateResult'][0][0]['tgt']))
	time.sleep(3)

ps:通过修改头文件使得访问更接近于正常人

  • 通过Requestheaders参数修改
  • 通过Request.add_header()方法修改

ps2:防止被屏蔽

  • 增加延迟
  • 使用代理

代理

步骤:

  1. 参数是一个字典{'类型':'代理ip:端口号'}

proxy_support = urllib.request.ProxyHandler({})

  1. 定制、创建一个opener

opener = urllib.request.build_opener(proxy_support)

  1. 安装opener

urllib.request.install_opener(opener)

  1. 调用opener

opener.open(url)

"""
	案例:使用代理在ip查询网站查询自己的ip
"""
import urllib.request as ur
import random


url = 'http://www.whatismyip.com.tw'
ipList = ['119.6.114.73:81', '183.203.208.166:8118', '111.1.32.28:81']

proxy_support = ur.ProxyHandler({'http':random.choice(ipList)})

opener = ur.build_opener(proxy_support)

ur.install_opener(opener)

res = ur.urlopen(url)
html = res.read().decode('utf-8')

print(html)

正则

re

  • re.search()
import re
re.search(r'Fishc', 'I love Fishc.com')

# 可以用点代表任何除换行之外的字符
re.search(r'.', 'Fishc.com')
# 反斜杠点代表原字符
re.search(r'\.', 'Fishc.com')
# 匹配任何数字
re.search(r'\d', 'fish 123')
# 匹配多个数字
re.search(r'\d\d\d', 'fish 123')
# 匹配符合条件的字母
re.search(r'[aeiou]', 'love I')  # =>o ,大小写有区分
# 匹配范围字母
re.search(r'[a-z]', 'love fishc1234')
# 匹配范围数字
re.search(r'[1-9]', '213123asdas')
# 匹配b字符3次,b超多3个则不返回任何结果
re.search(r'ab{3}c', 'abbbc')
# 匹配3到10次以内的b
re.search(r'ab{3,10}c', 'abbbbbc')
# 匹配范围0-255
re.search(r'[0-2]\d\d|2[0-4]\d|25[0-5]', '188')
# 匹配ip地址,可以用{}优化
res = re.search(r'([0-2]\d\d|2[0-4]\d|25[0-5])\.([0-2]\d\d|2[0-4]\d|25[0-5])\.([1-9]|\d[0-9]|[0-2]\d\d|2[0-4]\d|25[0-5])\.([1-9]|\d[0-9]|[0-2]\d\d|2[0-4]\d|25[0-5])','ip:192.168.1.1')
# 非贪婪模式。默认正则会开启贪婪模式即匹配尽可能多的字符,当?紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的,单独使用则意为匹配前面的子表达式零次或一次
s = '<html><title>test</title></html>'
re.search(r'<.+?>', s)  #=><html>
re.search(r'<.+>', s)  # =>返回整个字符

正则表达式符号表

re.findall()找到匹配的字符并打包为列表返回
re.compile()将正则表达式转化为模式对象,预编译

拓展用法

import re
result = re.search(r' (\w+) (\w+)', 'I love fishc.com')
# \w 匹配包括下划线的任何单词字符
print(result)  # => <re.Match object; span=(1, 12), match=' love fishc'>
print(result.group())  # =>  love fishc
print(result.group(1))  # => love
print(result.start())  # => 1
print(result.end())  # => 12
print(result.span())  # => (1,12)

参考

※ 小甲鱼python

※ 马士兵

求知讲堂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值