函数
常用内置函数
计算函数
abs(-1) # 绝对值
pow(2,5) # 幂: 等效于 2**5
sum([2,3,4]) # 累加和
divmod(92, 10) # 模: 返回为9, 2
round(3.1415926,3) # 精确值: 返回为3.142 (自动四舍五入)
检测函数
max([1,4,5]) # 最大值
min([1,3,4]) # 最小值
all([1,2,39,0]) # 检查是否全为True,返回bool: 这里返回False
any([1,2,4,0]) # 检查是否存在True,返回bool: 这里返回True
进制转换函数
v1 = bin(55) # 十进制 -> 二进制
v2 = int('0b0100110', base = 2) # 二进制(0b) -> 十进制
v1 = oct(55) # 十进制 -> 八进制
v2 = int('0o173', base = 8) # 八进制(0o) -> 十进制
v1 = hex(55) # 十进制 -> 十六进制
v2 = int('0o9a3', base = 16) # 十六进制(0x) -> 十进制
字符进制
v1 = ord('我') # 获得字符 unicode 的十进制表示:字符->数字
v1 = chr(65) # 由 unicode 十进制获取字符:数字->字符
排序
a = [1,3,2]
a.sort() # 将列表排序
b = sorted(a) # 排序但不影响原列表,生成新列表返回
def func1(x):
return int(x[:2])
b = sorted(a, key = func1) # 自定义排序规则,以func1返回值排序
随机函数random
random.randint(1,10) # 随机整数
random.uniform(0,5.5) # 随机小数
random.choice([1,2,3,5]) # 列表中随机值
random.sample([1,2,3,4],2) # 列表中随机取两个数,返回为列表形式
number_list = [1,2,66,8]
random.shuffle(number_list) # 将原列表打散
函数传参:默认值为可变类型格式
def func(a = []):
pass
函数创建的时候则生成了空列表,后续调用如果不传参的时候,都会使用这个空列表,类似于C语言中的static参数。所以默认为可变类型时建议:
def func(a = None):
if not a:
a = []
pass
传参中 * 的用法
乘法运算
收集列表中多余的值
a,b,*c = [1,2,3,4,5]
# a = 1, b = 2, c = [3, 4, 5]
- 函数:以元组形式接受参数 ( *args )
def f(a,*args):
print(args)
f(1, 2, 3, 4, 5, ['a', 'b'])
# a = 1, args = (2, 3, 4, 5, ['a', 'b'])
# 即将其后所有参数放入一个元组中
- 函数:以关键字形式接受参数 ( **args )
def f(**args):
print(args)
f(a = 1, b = 2)
# args为字典,{'a' = 1, 'b' = 2}
生成器函数:yield
def func(): # 生成器函数
print(1)
yield 1
print('next')
yield 'xx'
a = func() # 生成器对象
a.__next__ # 调用生成器对象,并运行至下一个yield,并返回值
# 如果函数代码全部结束会返回None
for item in a:
print item # 可以使用循环遍历生成器对象
适用于大数据量情况下的操作,减少内存占用。range默认使用生成器函数创建
global
关键字
global name
name = 'XXX'
# global 关键字可以在函数直接使用全局变量,并直接修改变量值
闭包(装饰器)
def func(n1):
v1 = 111
def inner():
print(n1 + v1)
return inner # 返回函数名
a = func(2)
b = func(33)
c = func(66) # 先将数据封装在了包(作用域)中
# 执行时再获取封装时的值
a() # 113
b() # 144
c() # 177
多用于线程池
用法: 装饰器
def func1(a1):
def inner():
print('test')
a1()
return inner
@fun1
def func2():
print('inner')
# 相当于执行 func2 = func1(func2)
闭包应用: 装饰器。不改动原函数的情况下,添加功能
多个返回值本质:元组
def func():
return 1,2
a, b = fuc()
# a = 1, b = 2
# 实际返回为(1,2),随后python会对其自动解包,按顺序赋值
邮件
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
# 邮件内容
msg = MIMEText('hello', 'html', 'utf-8') # 邮件内容
msg['Subject'] = 'my主题' # 主题
msg['From'] = formataddr(['ght', 'XXXX@136.com']) # 名字和邮箱
msg['to'] = 'xxx@qq.com' # 目标邮箱
# 发送邮件
server = smtplib.SMTP_SSL('smtp.163.com') # SMTP服务器
server.login('XXXX@136.com', 'XXDDWWGSX') # 账户、授权码
server.sendmail('XXXX@136.com', 'xxx@qq.com',
msg.as_string()) # 自己邮箱、目标邮箱、内容
server.quit()
类
类变量
class TestClass:
# 变量:
city = 'xian' # 类变量
def __init__(self, name):
self.name = name # 实例变量
v1 = TestClass('shanghai')
print(v1.name) # 上海
print(v1.city) # 西安
print(TestClass.city) # 西安
类方法
class TestClass:
def print_str(self): # 绑定方法:需要self参数
pass
@staticmethod # 静态方法:不需要self参数
def static_method():
pass
@classmethode # 类方法:需要cls参数
def class_method(cls, a1):
pass
# 绑定方法需要实例化再调用,静态方法可以直接通过类调用,也可以实例化调用
v1.print_str()
v1.static_method() # 实例化两个都可以调用
TestClass.static_method() # 静态方法直接通过类调用
TestClass.class_method() # 类方法于静态方法类似
类属性
class TestClass:
@property # 将方法伪造为变量,
def d1(self): # 可以用v1.d1直接调用
return self.name + 'add_info' # 不能有self外其他参数
@d1.setter # 将对象伪造为变量,可用=号
def d1(self, val): # 调用v1.d1 = 'wuhan',相当于'wuhan'传入val
self.name = val
@d1.deleter # 调用del v1.d1时运行此方法
def d1(self):
pass
print(v1.d1)
v1.d1 = 'wuhan'
del v1.d1
class TestClass:
x = property(get_x, set_x, del_x) # 快速创建x属性
def get_x(self):
return 123
def set_x(self, val):
pass
def get_x(self):
pass
obj = TestClass()
print(obj.x)
obj.x = 88
del obj.x
特殊成员
__init__
def __init__(self, a1): # 初始化方法
pass
### `__new__`
def __new__(self, *args, **kwargs): # 构造方法(默认执行)
# 创建空对象
obj = object.__new__(self)
return obj
__init__
实际做了两件事:
创建空对象
obj = 对象
。(__new__
创建对象)执行
__init__
方法。(__init__
初始化)
__call__
def __call__(self, *args, **kwargs): # 实例化对象直接调用
pass
obj = EgClass()
,则obj()
意义为调用__call__
__dict__
print(obj.__dict__) # 得到字典形式的对象所有变量
class Foo:
city = 'shanghai'
def __init__(self, name):
self.name = name
self.age = 20
obj = Foo('xiaowang')
print(obj.__dict__)
# {'name':'xiaowang', 'age': 20}
print(Foo.__dict__)
# {拿到类中所有方法和变量的值}
__str__
class Foo:
def __init__(self):
pass
def __str__(self):
return 'qte'
obj = Foo()
print(obj)
# 输出 qte
__getitem__
, __setitem__
, __delitem__
class Foo:
def __init__(self, name):
self.name = name
self.age = 20
def __getitem__(self, item):
return 999
def __setitem__(self, key, val):
pass
def __delitem__(self, key):
pass
obj[22]
:将22
以item
参数,传入__getitem__
obj[0] = 'test'
:将0
以key
参数,'test'
以val
参数,传入__setitem__
del obj[99]
:将99
以key
参数,传入__delitem__
__enter__
, __exit__
class Foo:
def __init__(self, name):
self.name = name
self.age = 20
def __enter__(self):
print('start')
return "return_info"
def __exit__(self):
print('end')
obj = Foo('xiaowang')
with obj as o:
print(123)
# start
# 123
# end
__enter__
,__exit__
需成对使用,with
开始时调用__enter__
, 结束时调用__exit__
。__enter__
中返回的值为with obj as o
中的o
__add__
等
class Foo:
def __init__(self, name):
self.name = name
self.age = 20
def __add__(self, other):
return self.age + other.age
f1 = Foo('root')
f2 = Foo('admin')
data = f1 + f2 # 即:f1.__add__(f2)
类似的加减乘除、大于小于不等于都可以使用类似方法
模块
文件操作
f = open('path', 'w')
content = f.read() # 获取文件所有内容
content = f.read(N) # 按N个字节逐次读取入内存
for i in f: # 按行读取,内存占用小
f.flush() # 将文件的内容直接存储的硬盘
__file__ # 运行脚本的文件路径
os.path.abspath('path.txt') # 获取绝对路径
os.path.join('a', 'b', 'c.txt') # 连接字符为路径:a/b/c.txt
os.path.dirname('path.txt') # 获取文件所在目录
os.path.exists('path.txt') # 判断路径是否存在,返回True/False
os.path.isdir('./path') # 判断是否为文件夹
os.remove('path.txt') # 删除文件(没办法删除文件夹)
os.listdir('dir') # 获取文件夹一级目录中的所有的文件名
os.walk('dir')
'''
获取文件夹中所有文件(包括嵌套)返回元组:
('a', [b], [c])
第一个 'a' 为当前迭代的目录,
第二个 [b] 为文件夹内的目录list,
第三个 [c] 为文件夹内的文件list。
使用for循环时,每次迭代[b]中的目录,直到遍历所有目录,
返回格式同上,即('a', [b], [c])格式
例:
for in_path, folder_list, name_list in os.walk('path')
'''
shutil.rmtree('path') # 删除文件夹以及其内容
shutil.move('a.txt', 'b.txt') # 将文件改名(文件夹也可以)
shutil.copytree('aa', 'bb') # 将文件夹拷贝到目标位置
shutil.copy('aa/bb.txt', 'cc') # 将文件拷贝到目标位置
shutil.make_archive(base_name = 'a', format = 'zip' , root_dir = 'y')
# 压缩文件
shutil.unpack_archive('a.zip', extract_dir = 'xxx', format = 'zip')
# 解除压缩
configparser
import configparser
config = configparser.Configparser() # 初始化
config.read('path.txt', encoding = 'utf-8') # 读取文件
x = config.sections() # 获取节点值['server', 'client']
y = config.items('server') # 获取'server'节点键值对
z = config.get('server', 'v1') # 获取'server'节点,'v1'的值
config.has_section('server') # 是否存在某个节点
config.add_section('test') # 添加节点
config.set('test','name','12') # 为某个节点添加键值,或修改键值
config.remove_section('server') # 删除节点
config.remove_option('server', 'v1') # 删除键值
with open('path.txt','w', encoding = 'utf-8') as f:
config.write(f) # 写入文件
json
json.loads() # 解码json数据,返回字典
json.dumps() # 将字典编码为json格式
json.dumps(XX, indent = 2) # 为字符串添加缩进
xml
<data>
<country name = 'China'>
<rank updata = 'yes'>69</rank>
# tag:rank attrib:updata = 'yes' text:99
</country>
</data>
from xml.etree import ElementTree
root = ElementTree.XML(CONTENT) # 获取内容
node1 = root.find('country') # 找到特定节点内容
node2 = root.findall('country')
for i in node2:
print(i.tag, i.attrib, i.text)
re:正则表达式
\d{11} 数字 {11位}
\w{5,10} 字符 {5-10位}
XX[a,b,d] 固定文本+可变范围[a,b,d]: XXa, XXb, XXd
XX[a-z] or XX[0-9] 固定文本+可变范围[a-z]或[0-9]
. 除了换行符以外的任意字符
[a-zA-Z0-9_-] 可组合多个范围的字符
数量相关(\d为例):
\d? ? 表示为0或1
\d+ + 表示为1或n
\d* * 表示为0或n
{9} 表示为9个
{9,} 表示为9及以上
{1,9} 表示为1到9个
^ 起始符
$ 终止符
默认贪婪匹配
import re
res = re.findall(r'\d{11}', example) # 获取所有和正则表达式匹配的字符串
res = re.findall(r'@(\d{11})', example) # 获取匹配的字符串,返回括号内的内容
res = re.match(r'^\d{11}\w+$', example) # 返回第一个匹配,没有返回None
res = re.search(r'^\d{11}\w+$', example) # 纵观全部字符串,但返回第一个匹配
res = re.split('[,\.]', example) # 通过','和'.'将字符串切割,返回列表
openpyxl:excel
from openpyxl import load_workbook
wb = load_workbook('test.xlsx') # 以路径方式打开excel文件
f = open('test.xlsx')
wb = load_workbook(f) # 以对象方式打开excel文件
all_sheet = wb.worksheets # excel中的每个sheet(对象)
single_cell = all_sheet[0].cell(2,3) # 某个sheet中特定坐标的内特
all_sheet_name = wb.sheetname # 所有sheet名字(list形式)
wb['sheet_name'] # 通过索引方式抓取特定sheet
row1 = sheet[1] # 获取某一行
all_rows = sheet.rows # 获取所有行
for i in sheet.iter_rows(min_row=1, max_row=4) # 循环读取一个区间的行
wb.save('test2.xlsx') # 存储文件
并发编程
进程和线程
GIL锁保证每个进程只占用一个CPU,使用多核需要使用多进程。
线程,IO密集型使用多线程(并发)
IO操作、输入输出等,一般可以直接通过驱动完成的任务。如:网络请求
import threading
def task(a):
pass
for i in range(10): # 创建十个线程
t = threading.Thread(target = task, arg = ('path',))
t.start()
进程,CPU密集型使用多进程(并行)
一个程序可以有多个进程,其中每个进程会有GIL锁,保证每个进程只占用一个CPU。多线程可以充分利用CPU,但是开销更大。
import multiprocessing
def task(a):
pass
for i in range(10): # 创建十个进程
t = multiprocessing.Process(target = task, arg = ('path',))
t.start()
进程池和线程池
防止无限制开进程和线程
线程池
from concurrent.futures import ThreadPoolExecutor
def task(a):
pass
pool = ThreadPoolExecutor(5) # 创建五个线程的线程池
for i in range(9):
pool.submit(task, 'test') # 提交任务
进程池
from concurrent.futures import ProcessPoolExecutor
def task(a):
pass
pool = ProcessPoolExecutor(5) # 创建五个线程的线程池
for i in range(9):
pool.submit(task, 'test') # 提交任务
数据共享
一个进程中的线程共享数据
进程之间共享数据
from multiprocessing import Manager
import multiprocessing
def task(a):
pass
if __name__ == '__main__':
manager = Manager() # 创建共享对象
with manager:
data = manager.list() # 共享的数据
p = multiprocessing.Process(target = task, args = (data,))
t.start()
t.join() # 等到子进程中的代码执行完毕在执行下面的代码
协程
协程本身不存在,由程序员人为创建。本质是让一个线程不停止,切换做多个任务(微线程)
应用场景:IO等待
- 如果开发过程中有IO等待,则适合使用协程。
线程与协程对比
- 并发能力差不多,但是协程资源消耗更
from greenlet import greenlet
def func1():
print(1) # 第2步:输出1
gr2.switch() # 第3步:跳转到func2函数
print(2) # 第6步:输出2
gr2.swithc() # 第7步:跳转到func2函数
def func2():
print(3) # 第4步:输出3
gr1.switch() # 第5步:跳转到func1函数
print(4) # 第8步:输出4
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 第1步:执行协程
import asyncio
async def func1():
print(1)
await asyncio.sleep(2) # IO自动切换到其他任务
print(2)
async def func2():
print(3)
await asyncio.sleep(2)
print(4)
tasks = [ # 添加任务
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_untill_complete(asyncio.wait(tasks))
垃圾回收机制
引用计数:
为每个对象维护一个 ref 的字段用来记录对象被引用的次数,每当对象被创建或者被引用时将该对象的引用次数加一,当对象的引用被销毁时该对象的引用次数减一,当对象的引用次数减到零时说明程序中已经没有任何对象持有该对象的引用,则释放内存。
问题:当二者之间交叉引用,则每个对象的引用计数都不为零,会让占用空间无法释放标记清除:
是一种基于对象可达性分析的回收算法,该算法分为两个步骤,分别是标记和清除。标记阶段,将所有活动对象进行标记。清除阶段将所有未进行标记的对象进行回收即可。
则问题变为了 GC 是如何判定哪些是活动对象。GC 会从根结点出发,与根结点直接相连或者间接相连的对象我们将其标记为活动对象(该对象可达),之后进行回收阶段,将未标记的对象(不可达对象)进行清除。前面所说的根结点可以是全局变量,也可以是调用栈。
问题:必须扫描整个堆内存,即使只有少量的非可达对象需要回收。性能浪费严重分代回收:
在引用计数和标记清楚的基础上,将系统中存活时间不同的对象划分到不同的内存区域,共三代,分别是 0 代,1 代 和 2 代。新生成的对象是 0 代,经过一次垃圾回收之后,还存活的对象将会升级到 1 代,以此类推,2 代中的对象是存活最久的对象。
随着程序的运行,有大量的对象创建和销毁,但是由于交叉引用的存在,创建的对象的数量大于等于销毁的数量,当这两个的数量差大于某个阈值的时候,触发垃圾回收机制。使用标记清除算法将死亡对象进行清除,同时将存活对象移动到 1 代,以此类推。因为程序的一般规律,大部分的对象生存周期都是相当短的,只有少量对象生命周期比较长,甚至会常驻内存。分代回收算法,做到了针对不同的区域采取不同的回收频率,节约了大量的计算从而提高 Python 的性能。
pymysql
连接数据库
import pymysql
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root123', charset='utf8') # 连接数据库
cursor = conn.cursor() # 创建游标
#1.查看数据库
cursor.execute("show databases;")
result = cursor.fetchall()
print(result) # 元组形式返回
# 2.创建数据库
cursor.execute("create database jxday15;")
conn.commit() # 创建数据库必须要commit
# 3.删除数据库
cursor.execute("drop database ixday15;")
conn.commit() # 删除数据库也要commit
# 4.进入数据库
cursor.execute('use mysql')
cursor.execute('show tables')
result = cursor.fetchall()
print(result)
cursor.close()
conn.close()
表操作
# 创建表
cursor.execute('use ixday14');
sql = """
create table tb:(
id int,
name varchar(16),
age int
)default charset=utf8
"""
cursor.execute(sql)
conn.commit() # 创建表后需要commit
# 删除表
cursor.execute('use jxday14')
cursor.execute('drop table tb3')
conn.commit()
删除表
drop table NAME;