Python3.8速通

数据类型

官方文档:https://docs.python.org/zh-cn/3.8/library/stdtypes.html#

数字、二进制(略)

字符串

str对象,即字符串。单引号'xxx'、双引号"xxx"、三重引号"""xxx"""表示。由Unicode码构成的不可变序列,实现了所有一般序列的操作(略)

format()函数

通过format对字符串进行占位操作。或者使用另一种写法f"xxx……",注意使用该写法时{}中应使用变量名,而非index

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
name = "xiaozhou"
age = 18
height = 1.8
print("我的名字是 {} !我 {} 岁了,我 {} 米高~".format(name, age, height))

# 可以通过index来调整传入的值,甚至可以复用
print("我的名字是 {0} !我 {2} 岁了,我 {1} 米高,我就是{0}".format(name, height, age))

# 可以根据key来传值,也可以设置百分比(如下保留2位小数点)
print("我的名字是 {nm} !我 {age} 岁了,我 {ht:.2f} 米高,我就是{nm}".format(nm=name, ht=height, age=age))

# 另一种写法,在字符串前加 f,{}中可以是运算符
print(f"我的名字是 {name} !我 {age} 岁了,我 {height} 米高~")

ROUTEROS
方式 内容
:, 每 3 个 0 就用逗号隔开,比如 1,000
:b 该数字的二进制
:d 整数型
:f 小数模式
:% 百分比模式

字符串修改

方式 意思 例子
strip 去除两端的空白符 “ 我不想要前后的空白,但是 中间\n的可以有\n “.strip()
replace 替换字符,未找到不替换不报错 “帮我替换掉你好”.replace(“你好”, “Hello”)
lower 全部做小写处理 print(“How ABOUT lower CaSe?”.lower())
upper 全部做大写处理 print(“And upper CaSe?”.upper())
title 仅开头的字母大写 print(“do tiTle For me”.title())
split 按要求分割 `print(“你
join 按要求合并 `print(“
startswith 判断是否为某字段开头 print(“我在街头看到你”.startswith(“我在”))
endswith 判断是否为某字段结尾 print(“我在巷尾看到你”.endswith(“看到你”))

一般序列

三种基本序列操作:list、tuple、range。大部分序列均支持以下操作

x in s 如果 s 中的某项等于 x 则结果为 True,否则为 False (1)
x not in s 如果 s 中的某项等于 x 则结果为 False,否则为 True (1)
s + t st 相拼接 (6)(7)
s * nn * s 相当于 s 与自身进行 n 次拼接 (2)(7)
s[i] s 的第 i 项,起始为 0 (3)
s[i:j] sij 的切片 (3)(4)
s[i:j:k] sij 步长为 k 的切片 (3)(5)
len(s) s 的长度
min(s) s 的最小项
max(s) s 的最大项
s.index(x[, i[, j]]) xs 中首次出现项的索引号(索引号在 i 或其后且在 j 之前) (8)
s.count(x) xs 中出现的总次数

列表list

list=[‘1’,’2’,’3’],可存放不同类型元素,支持多维列表

创建

list=[]

list=[1,2,3,4]

lx for x in iterable迭代器生成

list()转换

追加:append()函数

插入:insert(index, n)函数:将n插入index这个位置

按下标删除1:pop(index)函数,无参则删除末尾元素

按下标删除2:del listname[index],del indexname删除整个变量

按元素删除:remove(n)函数: n为list中的元素,并非index

改元素:list[index]=’xxx’

清空元素:clear()函数

合并列表:s.extend(list):将list的内容追加到s后面

反转列表:reverse()函数,反转元素

排序列表:sort()函数,对本函数进行原地排序

查位置:index()函数,元素返回所在下标

查内容:list(index),以下标查询元素内容

字典Dict

dic={“n1”:1, “n2”:”2”, “n3”:[13,4,5]}。键值对形式存在,key是唯一键,value可不同类型、可重复。键值对保留为插入时顺序

创建

  • 空字典:dic={}
  • 字典:dic={“n1”:’”1”, “m”:”2”}
  • 字典推导式:{x: x**2 for x in (2, 4, 6)}
  • dict()转换:dict(spe=123, guido=456,jack=789)

dic[key]=value,直接添加

复制其他dic:copy()函数

删除指定kv:pop(key)函数,key必填,删除前返回value值

删除指定kv:del dic[key]:若key不存在则报错。

清空dic: clear()函数

更新dic的值:update()

修改指定key的值:dic[‘key’]=xxx

查字典长度:len(dic)函数

查是否存在:key in dic 或key not in dic

查所有key:items()函数

查所有value:values()函数

查指定value:get(key)函数

返回value,若没有则个返回默认值:setdefault(key,default)函数

其他

循环方式(1)同时获取键值对:for k, v in knights.items():print(k,v)

循环方式(2)获取指定键值对:for i,v in enumerate(['a', 'b', 'c']):print(i,v)

循环方式(3)多序列循环:

1
2
3
4
5
6
questions = ['name', 'quest', 'favorite color']
answers = ['lancelot', 'the holy grail', 'blue']
for q,a in zip(questions, answers):
print('What is your {0}, it is {1}'.format(q,a))

STYLUS

…………

元组

files = (“file1”, “file2”, “file3”),注意列表用[],元组用(),也可无需使用(),决定元组的是逗号而不是括号。

元组是不可变序列,元素定义初始化后不可更改。

tup=()

tup=2,3,4或tup=(2,3,4):此语法是一样的

tuple()函数转换

  • 元组打包:tup=1,2,3
  • 序列解包:x,y,z = tup,tup可分别赋值给x、y、z

查数量:len()

查位置:index(n)查询n所在下标

查指定元素:tup[index]

set集合

files = {“file1”, “file3”, “file5”} , set中的是无序、不重复的,常用于元素检测、消除重复元素、交集并集等操作。

创建

  • 创建带元素的集合:files = {“file1”, “file3”, “file5”}
  • 创建空集:a=set()
  • 集合推导式:{c for c in 'abracadabra' if c not in 'abc'}
  • set()函数转换

add()函数 新增元素

set.remove(n):删除n元素

update()函数 更新

clear()清空

数学操作

交集:set.intersection(set1) 即&,获取共同存在的元素集合

并集:set.union(set1) 即 | ,获取两者所有元素(不重复)

补集:set.difference(set1) 即 - ,获取set中set1不存在的元素

函数

定义

1
2
3
4
5
def function(parm1,parm2):
……
return xxx

PYTHON

传参

Python的参数传递既不是值传递也不是引用传递,而是赋值传递。参数传递时,Python让新变量与原变量指向了相同的对象。一个对象是可以被多个变量所指向的,也就是说一个参数传入函数后,会有另一个变量指向它

  • 当参数为不可变对象时,所有指向该变量的值总是一样的,不会改变(改变之后是一个新对象)
  • 当参数为可变对象时,在函数中修改时对影响所有指向该对象的变量

注意:

  1. 变量是可以被删除的,但对象无法被删除
  2. 要想在函数中改变外部传进来的参数,要么重新对其赋值,要么将其return

参数类型

  • 必传参数:直接声明
  • 关键字参数:传参时可设置参数名,防止乱序function(parm1=0, parm2=1)
  • 默认参数,调用时可选填:def function(parm1, parm=1)
  • 不定量参数,调用时可传入更多参数:def function(parm1, *parm2)

匿名函数

lambda表达式创建,没有代码块,只有一个表达式sum = lambda parm1, parm2 : parm1 + parm2

冒号前表示输入参数,冒号后表示函数输出;

lambda:None表示没有输入参数,且输出None

创建:

1
2
3
4
5
6
7
8
class Pepole:
def __init__(self):
self.name='xxx'
……
xxx=xxx
……

RUBY

self:在类中获取当前类的功能或属性

__init__():类被实例化时会自动调用__init__()函数,用于初始化设置

继承

1
2
3
4
class Chinese(Pepole):
……

ANGELSCRIPT

Chinese继承了Pepole类,继承了Pepole的函数和属性,在子类中可以复用Pepole的属性和函数,以减少公有属性或功能的开发

函数和属性的私有化

私有程度 介绍
_ 一个下划线开头,如_age 弱隐藏,不想让调用者使用。但若必须调用还是可以用的
__ 两个下划线开头,如__password 强隐藏,不让调用者使用,自己在内部可以用

类的特殊方法
__new__();构造函数,用于创建对象

__init__()类被实例化后自动调用,用于初始化实例对象,可被继承。若子类需要调用,需显式调用,以确保父类正确初始化

__repr__()输出对象的字符串(正式值),返回的字符串准确、无歧义,尽可能表达出如何创建出来的这个对象

__str__()输出对象的字符串(非正式值),返回的字符串可读性更高,使用更方便

__iter__()创建迭代器时被调用,遍历序列时使用

__next__()从容器中返回下一项

……

模块管理

如下多种引用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 引用其他模块(也可以是同路径下.py文件)
import file # file为文件名,不带py
print(file.create_name()) # create_name是file.py中定义的函数

# 引用其他模块中的多个函数
from file import get_name, get_age

# 引用模块下所有函数
from file import *

# 模块重命名,使用 as 关键字
import file as f

APPLESCRIPT

编码风格

  1. 使用4个空格缩进,不使用制表符
  2. 一行代码不超过79字符
  3. 函数和类之间用空行分开
  4. 注释尽量单独放一行
  5. 函数、类明规则命名
  6. …………

目录管理

新增目录:os.mkdir(),多级目录os.makedirs()

复制文件:shutil.copy2()

删除空目录:os.removedirs

删除目录及其所有子目录(需导入) :shutil.rmtree()

查看当前目录:os.getcmd()realpath

查看某文件所在的目录名:os.path.dirname()

查看当前目录下的文件列表os.listdir

查看文件或目录是否存在:os.path.exists()

查看是否是文件/目录:os.path.isfile()/isdir()

其他操作

切分文件全名中的目录和文件:os.path.split()

文件操作

脚本环境下获取当前工作区目录:os.path.split(os.path.realpath(__file__))[0]

命令环境下获取当前工作区目录:os.getcwd()os.path.abspath('.')

如果在只写模式中读取,或在只读模式中写入,会报io.UnsupportedOperation错误

  • w为写入模式,文件不存在则创建,文件已存在则直接会覆盖
  • w+为可读可写模式,不存在则创建,文件已存在则直接会覆盖
  • a为写入模式,文件不存在则创建,已存在则不覆盖,追加在文件末尾
  • a+可读可写,文件不存在则创建,已存在则不覆盖,追加在文件末尾
1
2
3
4
5
6
7
8
9
f=open("new_text.txt", "w"):
f.write("abcdefg")
f.flose()

# 或者使用with写法
with open("new_text.txt", "w") as f:
f.writelines(["abcdefg\n","123456\n"])

LIVECODESERVER

**with:**当使用with时,会自动调用类的__enter__(),然后开始执行with下面的语句,执行结束后会自动调用__exit__()

**writelines:**传入列表格式的数据使用,会分行写入

1
2
3
4
5
6
7
8
import os

if exists("text.txt"):
os.remove()
else:
print("This file does not exist!")

ISBL

查/改

  • r为读取模式,文件不存在时会报FileNotFoundError错误
  • r+为可读可写模式,文件不存在时会报FileNotFoundError错误,写操作会覆盖
1
2
3
4
5
6
7
# 修改
with open("test.txt", "r+") as f:
new_context = f.read()+"\n66666666666"
f.write(new_context)
print("新内容:\n"+new_context)

HAXE

读写二进制

wb&rb为读写二进制数据,r读取文件时,读到文档结束符(EOF)就算是读完了,但字节\x1A(26)转成字符后就是文档结束符,因此使用r可能会出现文档读取不全的现象。

  • 使用r读取,read()返回的是字符串数据
  • 使用rb读取,read()返回的是bytes数据

指定编码

1
2
3
4
with open("test.txt","w", encoding="utf-8")
……

PGSQL

异常处理

使用场景

在不确定某段代码是否能成功执行时,就需要使用异常处理。如文件读取、解析Json文件等,就需要用到FileNotFoundError或者JSONDecodeError等。

注意!

不能滥用异常,在流程控制的逻辑中,一般不用异常处理,如:

1
2
3
4
5
6
7
8
9
10
# 如下是错误用法
d = {'name': 'jason', 'age': 20}
try:
value = d['dob']
...
except KeyError as err:
print('KeyError: {}'.format(err))
# 如下才是合理写法
if 'dob' in d:
value = d[dob]

捕获单个异常

except:捕获异常

1
2
3
4
5
6
7
8
9
10
try: # try下面的代码报的FileNotFoundError错误都能被except捕捉到
with open("no_file.txt", "r") as f:
print(f.read())
except FileNotFoundError as e:
print(e)
with open("no_file.txt", "w") as f:
f.write("I'm no_file.txt") # 进行异常处理
print("new file 'no_file.txt' has been written")

PYTHON

捕获多个异常

注意:一般情况下难以保证程序覆盖所有异常类型,通常在最后一个except捕获一个Exception基类,这样就可以捕获任意非系统异常。或者直接写except捕获所有异常(包括系统异常)

  1. except(Err1, Err2,Err3……)
1
2
3
4
5
6
7
8
9
d = {"name": "f1", "age": 2}
l = [1,2,3]
try:
v = d["gender"]
l[3] = 4
except (KeyError, IndexError) as e:
print("key or index error for:", e)

APACHE
  1. 使用多次except,单独处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
d = {"name": "f1", "age": 2}
l = [1,2,3]
try:
v = d["gender"]
l[3] = 4
except KeyError as e:
print("key error for:", e)
d["gender"] = "x"
except IndexError as e:
print("index error for:", e)
l.append(4)
print(d)
print(l)


STYLUS

异常处理分支

  1. try-except-else:如果没有捕获到异常,则运行其他代码
1
2
3
4
5
6
7
8
9
l = [1,2,3,4]
try:
l[3] = 4
except IndexError as e:
print(e)
else:
print("no error, now in else")

PYTHON
  1. try-except-finally:不论是否捕获到异常,都需执行finnally中的代码
1
2
3
4
5
6
7
8
9
l = [1,2,3]
try:
l[3] = 4
except IndexError as e:
print(e)
finally:
print("reach finally")

PYTHON

自定义异常

自定义异常需要继承Eception基类,并定义初始化函数和str函数

1
2
3
4
5
6
7
8
9
10
11
class MyInputError(Exception):
"""Exception raised when there're errors in input"""
def __init__(self, value): # 自定义异常类型的初始化
self.value = value
def __str__(self): # 自定义异常类型的string表达形式
return ("{} is invalid input".format(repr(self.value)))

try:
raise MyInputError(1) # 抛出MyInputError这个异常
except MyInputError as err:
print('error: {}'.format(err))

手动抛出异常

raise:提示代码中可能出现的异常,供他人调用时debug

1
2
3
4
5
6
7
8
def no_negative(num):
if num < 0:
raise ValueError("I said no negative")
return num

print(no_negative(-1))

ISBL

可被raise的Error如下表:

异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

Json序列化

内置模块pickle实现了Python对象的二进制序列化和反序列化。序列化即将对象及其层次结构转化为字节流的过程。

pickle

序列化对象

pickle.dumps():将对象序列化,并返回该对象的bytes类型数据

1
2
3
4
5
6
7
8
import pickle

data = {"filename": "f1.txt", "create_time": "today", "size": 111}
pickle.dumps(data)

# 结果:b'\x80\x04\x958\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x08filename\x94\x8c\x06f1.txt\x94\x8c\x0bcreate_time\x94\x8c\x05today\x94\x8c\x04size\x94Kou.'

LLVM

保存对象至文件

pickle.dump():将对象序列化并保存至本地

1
2
3
4
5
6
7
8
9
10
11
import os
import pickle
data = {"1": "xiaozhou", "2": "xiaoxue", "3": "xiaoxiaozhou"}

with open("data.txt", "wb") as f:
pickle.dump(data, f)
print(os.listdir())

# 结果:['files', 'data.txt']

KOTLIN

读取文件

pickle.load():将本地文件读取出来

1
2
3
4
5
6
7
8
9
10
import os
import pickle

with open("data.txt", "rb") as f:
data = pickle.load(f)
print(data)

# 结果:{'1': 'xiaozhou', '2': 'xiaoxue', '3': 'xiaoxiaozhou'}

KOTLIN

注意:

  1. Pickle在反序列化类的时候需要有这个类的class,否则会找不到这个类二失败。
  2. 有些对象例如打开的文件、网络链接、线程进程等,如果将这些对象赋给class的属性上,就不能被打包,因为这些需要依赖外部系统状态。

Json

不需要转成二进制,在网络中传输相对安全

json.dumps()json.loads():将对象转化为json格式的字符串 & 将字符串转换为对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json

data = {"filename": "f1.txt", "create_time": "today", "size": 111}
print(type(data))
j = json.dumps(data)
print(j)
print(type(j))

#结果:
<class 'dict'>
{"filename": "f1.txt", "create_time": "today", "size": 111}
<class 'str'>

STYLUS

json.dump()json.load():与上面类似,一般与文件操作一起用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
data = {"filename": "f1.txt", "create_time": "today", "size": 111}
with open("data.json", "w") as f:
json.dump(data, f)

print("直接当纯文本读:")
with open("data.json", "r") as f:
print(f.read())

print("用 json 加载了读:")
with open("data.json", "r") as f:
new_data = json.load(f)
print("字典读取:", new_data)

# 结果
直接当纯文本读:
{"filename": "f1.txt", "create_time": "today", "size": 111}
用 json 加载了读:
字典读取: {'filename': 'f1.txt', 'create_time': 'today', 'size': 111}

PYTHON

注意:json无法序列化class对象

对比 Pickle Json
存储格式 Python 特定的 Bytes 格式 通用 JSON text 格式,可用于常用的网络通讯中
数据种类 类,功能,字典,列表,元组等 基本和 Pickle 一样,但不能存类,功能
保存后可读性 不能直接阅读 能直接阅读
跨语言性 只能用在 Python 可以跨多语言读写
处理时间 长(需编码数据) 短(不需编码)
安全性 不安全(除非你信任数据源) 相对安全

正则

正则常见字符

字符 描述
\d 代表任意数字,就是阿拉伯数字 0-9 这些玩意。
\D 大写的就是和小写的唱反调,\d 你代表的是任意数字是吧?那么我 \D 就代表不是数字的。
\w 代表字母,数字,下划线。也就是 a-z、A-Z、0-9、_。
\W 跟 \w 唱反调,代表不是字母,不是数字,不是下划线的。
\n 代表一个换行。
\r 代表一个回车。
\f 代表换页。
\t 代表一个 Tab 。
\s 代表所有的空白字符,也就是上面这个:\n、\r、\t、\f。
\S 跟 \s 唱反调,代表所有不是空白的字符。
\A 代表字符串的开始。
\Z 代表字符串的结束。
^ 匹配字符串开始的位置。
$ 匹配字符创结束的位置。
. 代表所有的单个字符,除了 \n \r
[...] 代表在 [] 范围内的字符,比如 [a-z] 就代表 a到z的字母
[^...] 跟 […] 唱反调,代表不在 [] 范围内的字符
{n} 匹配在 {n} 前面的东西,比如: o{2} 不能匹配 Bob 中的 o ,但是能匹配 food 中的两个o。
{n,m} 匹配在 {n,m} 前面的东西,比如:o{1,3} 将匹配“fooooood”中的前三个o。
{n,} 匹配在 {n,} 前面的东西,比如:o{2,} 不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。
* 和 {0,} 一个样,匹配 * 前面的 0 次或多次。 比如 zo* 能匹配“z”、“zo”以及“zoo”。
+ 和{1,} 一个样,匹配 + 前面 1 次或多次。 比如 zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。
和{0,1} 一个样,匹配 ?前面 0 次或 1 次。
a|b 匹配 a 或者 b。
() 匹配括号里面的内容。

匹配字符串

例:

1
2
3
4
5
6
7
8
9
import re
ptn = re.compile(r"\w+?@\w+?\.com") # 定义正则

matched = ptn.search("mofan@mofanpy.com") # 使用正则查找字符串,返回第一个匹配的字符串
print(matched)

# 打印结果:<re.Match object; span=(0, 17), match='mofan@mofanpy.com'>

PYTHON

r代表后面的字符串是一个正则

根据上表,\w匹配字母数字下划线,+?代表匹配多次

打印结果中的span=(0, 17)表示找到的字符串在原始字符的位置,match表示找到的具体字符串内容

正则除了search(),还有其他功能:

功能 说明 举例
re.search() 扫描查找整个字符串,找到第一个模式匹配的 re.search(rrun, I run to you) > ‘run’
re.match() 从字符的最开头匹配,找到第一个模式匹配的即使用 re.M 多行匹配,也是从最最开头开始匹配 re.match(rrun, I run to you) > None
re.findall() 返回一个不重复的 pattern 的匹配列表 re.findall(rr[ua]n, I run to you. you ran to him) > [‘run’, ‘ran’]
re.finditer() 和 findall 一样,只是用迭代器的方式使用 for item in re.finditer(rr[ua]n, I run to you. you ran to him):
re.split() 用正则分开字符串 re.split(rr[ua]n, I run to you. you ran to him) > [‘I ‘, ‘ to you. you ‘, ‘ to him’]
re.sub() 用正则替换字符 re.sub(rr[ua]n, jump, I run to you. you ran to him) > ‘I jump to you. you jump to him’
re.subn() 和 sub 一样,额外返回一个替代次数 re.subn(rr[ua]n, jump, I run to you. you ran to him) > (‘I jump to you. you jump to him’, 2)

匹配HTML

1
2
3
re.compile('<li>.*?list_num.*?(\d+).</div>.*?<img src="(.*?)".*?class="name".*?title="(.*?)">.*?class="star">.*?class="tuijian">(.*?)</span>.*?class="publisher_info">.*?target="_blank">(.*?)</a>.*?class="biaosheng">.*?<span>(.*?)</span></div>.*?<p><span\sclass="price_n">&yen;(.*?)</span>.*?</li>', re.S)

GHERKIN
  • .*?list_num.*?这里的 .*? 加在了量词 * 的后面,使得该量词 * 变为非贪婪模式,即匹配尽量少的字符。例如,对 “123abc” 使用 /\d+/ 将会匹配 “123”,而使用 /\d+?/ 则只会匹配到 “1”。

    • 在当前案例中,使用正则来匹配html字符串,大量使用 .*? 来匹配其他字符串。
  • 当前匹配模式为 re.S ,表示跨行匹配。将多行字符串当作一个整体,将换行符 \n 当作一个普通字符加入这个整体中。

  • <span\sclass="price_n" 这里的 \s 代表空白字符,正则中不允许有空格出现

  • 建议在写长正则时,先将单个值的正则写出来,最后再拼起来,这样可以省去很多排错时间

  • 如正则一直无法匹配,尝试查看源码是否存在该值。如下图这种a标签的内容是计算上去的,并非源码中提供。

    img

img

匹配模式

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(locale-aware)匹配
re.M 多行匹配,影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符,跨行匹配
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B.
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。

迭代器,生成器与修饰器

迭代器

某对象实现了__iter__()函数,且该函数返回一个迭代器对象,这个对象就可以成为可迭代对象。可以用for循环遍历的对象均是可迭代对象。

迭代器协议包括:

  1. 实现了__next__()函数
  2. __next__()函数返回了某个数值
  3. __next__()取值完成后,抛出StopIteration异常

生成器

用于在遍历大规模数据时使用的写法,避免内存中数据量过大。生成器调用__next__()函数以惰性方式获取下一个值,遍历结束后无法再次遍历。

优势就在于边迭代边输出,提供了延迟操作。

(哪儿都没说明白,等用上了再说)

装饰器

装饰器的实现前提:函数也是对象,函数可以当做参数传入其他函数。函数也可以当做返回值被return

装饰器的作用就是为一个函数做额外的事情,如写日志、测试、鉴权等。装饰器一般在多个函数中做同样操作时发挥的作用最大,可以较大限度减少代码量

举例说明:

这里的mains函数上方添加了一行@dector,将mains函数作为参数传入了dector中。在dector内部又调用了原函数mains(即参数func),但在调用前后分别执行输出了语句。这就是装饰器dector的作用,在不改变原函数行为的前提下,改变原函数的行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def dector(func):
def tests(*args, **kwargs): # # 如需给原参数传参,这样写可以传任意数量和类型的参数
print("这是触发前的测试")
res = func(*args, **kwargs)
print("这是触发后的操作")
return res
return tests

# 这段代码等价于 mains = dector(mains)
@dector
def mains(name):
print("这是主进程")


mains("小周")

输出:
这是触发前的测试
这是主进程
这是触发后的操作

PYTHON

自定义参数、保留函数元信息

除了原函数所需要的参数,装饰器本身也可以定义参数,例如希望指定装饰器内部函数的执行次数,可以在装饰器这里传入。

需要注意的是,当同一个函数被包装器修饰后,它的名字就已经变成了包装器内部的函数(wrapper),如果需要改成原来的greet,在上面加上一个@functools.wraps(func)就可以了,这会将原函数的元信息拷贝至对应的装饰器函数里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import functools

def repeat(num):
def my_decorator(func):
@functools.wraps(func) #将原函数的元信息拷贝至装饰器函数中
def wrapper(*args, **kwargs):
for i in range(num): # 4被传入进来后,按照这个数字循环调用greet
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator

@repeat(4) # 此处是可以允许传参的
def greet(message):
print(message)
#-------------------------------------#
print(greet.__name__)
输出:wrapper

装饰器的嵌套

允许有多个装饰器,执行顺序是从里到外(有待研究):

1
2
3
4
5
6
7
8
@decorator1
@decorator2
@decorator3
def func():
...

# 等效于:
decorator1(decorator2(decorator3(func)))

类装饰器

myDecorator类的__init__()中定义和调用了aFunction函数,在__init__()执行结束后,aFunction函数已经声明且调用完了。然后输出第三句输出。最后执行aFunction()时,实际上是执行了myDecorator__call__()方法。

因此,被装饰后的函数aFunction(),已经是类myDecorator的对象了,当再次调用aFunction()时,也就是在调用类myDecorator的对象,所以会调到__call__()函数。

使用类装饰器来装饰函数来对函数添加一些额外的属性或功能时,一般会在类的__init__()中传入函数,在__call__()调用修饰的函数或者其他额外处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class myDecorator(object):
def __init__(self, f):
print("inside myDecorator.__init__()")
f()
def __call__(self):
print("inside myDecorator.__call__()")

@myDecorator
def aFunction():
print("inside aFunction()")
print("Finished decorating aFunction()") # 表示aFunction已经调用结束
aFunction()

输出:
inside myDecorator.__init__()
inside aFunction()
Finished decorating aFunction()
inside myDecorator.__call__()

补充:

定义了__call__()方法的类的对象可以像函数一样被调用,此时调用的是对象的__call__()方法。因为按照装饰器语法的涵义,

1
2
3
4
5
6
7
8
9
@myDecorator
def aFunction():
# ……

# 等价于
def aFunction():
# ……
aFunction = myDecorator(aFunction)

进阶用法

lambda表达式

用于创建匿名函数,语法上限为单个表达式,是正常函数定义的语法糖。如下两种写法是一样的:

1
2
3
4
5
6
def add(a, b):
return a + b

add = lambda a,b:a+b

LIVECODESERVER

遍历缩写

如下写法是一样的。

1
2
3
4
5
6
7
8
9
10
l = []
for i in range(10):
l.append(i*2)

l = [i*2 for i in range(10)]

# 使用缩写方式创建字典
d = {"index"+str(i): i*2 fro i in range(10)}

APACHE

分支缩写

对于简单逻辑,允许如下写法:

1
2
3
4
5
6
7
8
9
10
11
12
done = False
if done:
a = 1
else:
a = 2
print(a)

done = False
a = 1 if done else 2
print(a)

STYLUS

遍历简写

在for、if中使用简写

1
2
3
4
5
6
7
8
9
10
# 原始for循环中的if判断
l = []
for i in range(10):
if i % 2 == 0:
l.append(i*2)

# for循环+if判断简写,字典同此写法
l = [i*2 for i in range(10) if i % 2 == 0]

APACHE

带计数器的序列:enumerate()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 这个例子其实逻辑并不算通畅,l[count] = data这行完全可以放到if内,不太能理解为什么要放外面
count = 0
l = [11,22,33,44]
for data in l:
if count == 2:
data += 11
l[count] = data # 当if为Ture时,data的值自增11,并赋给当此循环的下标所在值,
count += 1
print(l)

# enumerate(l)返回了下标和元素两个值,因此在for循环中可以直接使用
# 此处的下标可以自定义初始值,如for count, data in enumerate(l, start=5):
l = [11,22,33,44]
for count, data in enumerate(l):
print(count)
if count == 2:
data += 11
l[count] = data
print(l)

FORTRAN

zip遍历

zip()将序列作为参数将其打包,可同时迭代多个序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 普通方式:执行普通遍历,在每次循环中分别获取两个列表的元素
name = ["a", "b", "c"]
score = [1,2,3]
d = {}
for i in range(3):
d[name[i]] = score[i]
print(d)

# 同时将两个列表遍历,获得的值直接分配给n、s,空字典d 可直接赋值
# 复杂情况下zip()函数的简化程度会更高
name = ["a", "b", "c"]
score = [1,2,3]
d = {}
for n, s in zip(name, score):
d[n]=s
print(d)

MAKEFILE

反转序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
l = [1,2,3]
# 最原始的办法:遍历原序列,从最后追个元素追加至新列表
_l = []
for i in range(len(l)):
_l.append(l[-i-1])
print(_l)

# 短for循环反转
_l = [l[-i-1] for i in range(len(l))]

# 内置的原地反转函数
l.reverse()

# 迭代时反转
for i in reversed(l):
print(i)

# 拷贝后反转
_l = l[::-1]

PYTHON

conda使用

安装(略)

基本操作

创建独立的虚拟环境

1
2
3
conda create --name test python=3.8

APACHE

查看当前虚拟环境列表

1
2
3
conda env list

BASH

切换新建的test环境

1
2
3
conda activate test

APPLESCRIPT

退出当前虚拟环境

1
2

conda deactivate

删除指定虚拟环境

1
conda remove -n envname --all

依赖迁移

在cmd或指定的本地路径下执行,导出依赖列表

1
2
3
pip freeze > requirements.txt

PGSQL

将txt文件放置新项目位置,执行读取

1
2
3
pip install -r requirements.txt

CMAKE

Python3.8速通
https://zhouyinglin.cn/post/python3sutong.html
作者
小周
发布于
2022年11月7日
更新于
2023年7月24日
许可协议