nump使用

nump使用

import numpy as np

arr1 = np.array([1, 2, 3, 4])
print(arr1)
arr2 = np.array([[1, 2, 3, 1], [4, 5, 6, 3], [4, 8, 9, 10]])
print(arr2)
np_linspace = np.linspace(0, 1, 12)
print(np_linspace)

#矩阵的生成
np_zeros = np.zeros((2, 3))
print(np_zeros)
np_eye = np.eye(3)
print(np_eye)
np_diag = np.diag([1, 2, 3, 4])
print(np_diag)

# 数组的属性
print(arr2.shape)
print(arr2.ndim)
print(arr2.size)
print(arr2.dtype)
print(arr2.itemsize)

#类型转换
print(np.float(32))
print(np.int8(34))
print(bool(0))
print(np.float(True))
print(np.float(False))

#数组下标查找
print(arr2[2][:2])
print(arr2[0, 0:3])

#数组形状
arr2.shape = 4, 3
print(arr2)
print(arr1.reshape(2,2))
arr_1 = np.arange(24).reshape(4,6)
print(arr_1)
print(arr_1.ravel())
print(arr_1.flatten()) # 横向
print(arr_1.flatten(‘F’)) # 纵向

#改变数组
arr3 = np.array([5,6,7,8])
print(np.hstack((arr1,arr3)))
print(np.vstack((arr1,arr3)))
print(np.concatenate((arr1,arr3),axis=0))

#数组切割
print(np.hsplit(arr3,2))
print(np.vsplit(arr2,2))
print(np.split(arr2,2,axis=0))

#随机生成数字
print(np.random.random(100))
print(np.random.rand(10,5))
print(np.random.randn(10,5))
print(np.random.randint(2,10,size=[2,5]))

#矩阵生成与运算
maty1 = np.mat(‘1,2,3;4,5,6;7,8,9’)
print(maty1)
maty2 = np.matrix([[1,2,3],[4,5,6],[7,8,9]])
print(maty2)
print(maty2*3)
print(maty2+maty1)
print(maty2*maty1)
print(np.dot(maty2,maty1))
print(maty1.T)
print(maty1.H)
print(maty1.I)

 

python群发邮件

python群发邮件

1. 前言
1.1 应朋友要求,写一个群发邮件的脚本,用来实现往每个人的邮箱里边发送自己的工资条

2. 数据格式,*后一列是邮箱地址%title插图%num

3. 脚本实现的功能
3.1 自定义邮件标题

3.2 记录发送成功或失败的个数,防止发送失败

4. 代码实现

# -*- coding: utf-8 -*-
# @Time : 2021/3/26 10:11
# @Author : liyf–95/02/02
# @File : send_email.py
# @Software: PyCharm

import xlrd
import time
import re
from email.mime.text import MIMEText
from smtplib import SMTP_SSL

from loguru import logger

# qq邮箱smtp服务器
host_server = ‘smtp.qq.com’
# sender_qq为发件人的qq号码
sender_qq = ‘123456@qq.com’
# 第三方客户端登录时需要的授权码,不是qq密码
pwd = ‘xxxxxxxxxxxxx’
# 发件人的邮箱
sender_qq_mail = ‘123456@qq.com’
# 获取当前月份
batch = time.strftime(“%Y-%m”, time.localtime())

suffix = time.strftime(“%Y%m”, time.localtime())

def get_success_error_counts():
“””
用来读取日志文件中的数据,并转成列表形式,方便调用该函数处理列表中的数据,用来做去重处理
:return: 列表
“””
success_email_list = []

try:
with open(f’success_log_{suffix}.txt’, ‘r’, encoding=’utf8′) as f:
results = f.readlines()
for res in results:
success_email_list.append(res.strip())
except Exception:
logger.error(f’success_log_{suffix}.txt 文件不存在,初始化列表为0!’)
success_email_list = success_email_list

error_list = []
try:
with open(f’error_log_{suffix}.txt’, ‘r’, encoding=’utf8′) as f:
results = f.readlines()
for res in results:
restr = res.strip()
email = re.findall(re.compile(r”email’: ‘(.*?)’, ‘”, re.S), restr)[0]
error_list.append(email)
except Exception:
error_list = error_list

return success_email_list, error_list

def read_excel(subject):
“””
读取excel数据
:param subject: 自定义的邮件标题
:return:
“””
workbook = xlrd.open_workbook(‘工资条2.xlsx’)

worksheet = workbook.sheet_by_index(0)

nrows = worksheet.nrows
# 定义一个空列表,用来存放每一个员工的数据,包括表头
total_list = []
for i in range(nrows):
data_list = worksheet.row_values(i)
if data_list[0] == ”:
pass
else:
total_list.append(data_list)
logger.info(f’数据读取完毕,共有 {len(total_list) – 1} 位同事’)
logger.info(‘————————————————————‘)
time.sleep(2)
for k, v in enumerate(total_list[1:]):
msg_content = ”
for i, j in enumerate(v):
if total_list[0][i] == ‘邮箱’:
pass
else:
# 有一些列的数据为空,处理数据
val = ‘无’ if str(v[i]).strip() == ” else v[i]
msg = f’# {total_list[0][i]}:{val}\n’
msg_content += msg
name = v[0]
email_addr = v[-1]
success, error = get_success_error_counts()
logger.info(f’正在向第 {k + 1}/{len(total_list) – 1} 位同事 {name} 发送邮件,请稍等…’)
if len(success) == 0:
# 说明日志中没有数据,即还没有发送成功的例子
# 开始发送数据
email_content = f’尊敬的 {name} 同事,您好,您的 {batch} 月份工资单信息如下:\n{msg_content}# 发送时间:{time.strftime(“%Y-%m-%d %H:%M:%S”, time.localtime())}’
send_email_to_member(email_addr, email_content, name, subject)
logger.info(f’已发送至邮箱:{email_addr},接收人:{name}’)
else:
# 已经有发送成功的例子,并已存入success_log.txt文件中
email_list = [] # 用来存放success_log.txt文件中的邮箱地址,用来去重
for data in success:
email_list.append(str(data).split(‘—->’)[-1])
if email_addr in email_list:
# 如果需要发送邮件的邮箱地址在success_log.txt文件中,则说明该邮箱已经发送过,无需重复发送
logger.warning(f'{name} 同事:{email_addr} 已经发送过了,无需重复发送邮件!!’)
pass
else:
# 正常发送邮件
email_content = f’尊敬的 {name} 同事,你好,您的 {batch} 月份工资单信息如下:\n{msg_content}# 发送时间:{time.strftime(“%Y-%m-%d %H:%M:%S”, time.localtime())}’
send_email_to_member(email_addr, email_content, name, subject)
logger.info(f’已发送至邮箱:{email_addr},接收人:{name}’)
logger.info(‘————————————————————‘)
logger.info(f’脚本运行结束!等待5分钟后自动关闭窗口(或者手动点击窗口右上角关闭)!!!’)
logger.info(‘运行结果:’)
logger.info(f'{len(total_list) – 1} 位同事已全部发送完毕’)
success, error = get_success_error_counts()
logger.info(f’Successd:{len(success)},Failed:{len(error)}’)
time.sleep(300)

def send_email_to_member(email_addr, email_content, name, subject):
“””
发送邮件
:param email_addr: 收件人邮箱地址
:param email_content: 需要发送的正文内容
:param name: 收件人姓名
:return:
“””
# ssl登录
smtp = SMTP_SSL(host_server)
# set_debuglevel()是用来调试的。参数值为1表示开启调试模式,参数值为0关闭调试模式,
smtp.set_debuglevel(0)
smtp.ehlo(host_server)
smtp.login(sender_qq, pwd)

msg = MIMEText(email_content, “plain”, ‘utf-8′)
msg[“Subject”] = subject # 邮件标题
msg[“From”] = sender_qq_mail # 发件人
msg[“To”] = email_addr # 收件人邮箱
try:
smtp.sendmail(sender_qq_mail, email_addr, msg.as_string())
smtp.quit()
msg = f'{name} 发送成功,时间: {time.strftime(“%Y-%m-%d %H:%M:%S”, time.localtime())}—->{email_addr}’
with open(f’success_log_{suffix}.txt’, ‘a’, encoding=’utf8′) as f:
f.write(msg)
f.write(‘\n’)
f.close()
time.sleep(0.5)
except Exception as e:
logger.error(f’发送失败—>{name}\n原因:{e}’)
item = {}
item[‘name’] = name
item[’email’] = email_addr
item[‘error_reason’] = e
item[‘date’] = time.strftime(“%Y-%m-%d %H:%M:%S”, time.localtime())
with open(f’error_log_{suffix}.txt’, ‘a’, encoding=’utf8′) as f:
f.write(str(item))
f.write(‘\n’)
f.close()

if __name__ == ‘__main__’:
subject = input(‘请输入自定义邮件标题:’)
logger.info(f’自定义邮件标题为:{subject}’)
read_excel(subject)
5. 逻辑梳理
5.1 该脚本的使用qq邮箱发送,其中获取授权码可以 点击这里参考博客

5.2 注意事项

5.2.1 excel名称必须为 `工资条2.xlsx`

5.2.2 `邮箱` 列必须为*后一列,`姓名` 列必须在*列,因为代码中 `name=v[0], email_addr=v[-1]` 是固定的。可以自己做适当修改

5.2.3 表头名称可以随意改动,列数也可以随意增减,但要保证 `邮箱` 和 `姓名` 列存在

6. success_log_202103.txt 和 error_log_202103.txt 的作用
6.1 success_log_202103.txt

6.1.1 用来记录发送成功的数据

6.1.2 发送邮件之前,会先读取该txt文件,并判断要发送的email地址是否在txt里边,如果存在,则不发送,防止重复发送

6.2 error_log_202103.txt

6.2.1 一般情况下,没有这个文件,但是由于一些不可控因素,比如邮箱地址不存在或者断网等,会导致发送邮件失败

6.2.2 发送失败之后会把当前发送的数据记录下来,就会生成这个文件

6.2.3 如果该文件有数据,则首先检查是否是邮箱不正确导致的,如果不是,重新运行exe文件

7. 测试
7.1 使用 `pyinstaller -F send_email.py` 打包 py 文件为 exe 可执行文件

7.2 运行截图

%title插图%num

7.3 邮件内容

%title插图%num

Python系列11-Python文件操作

Python系列11-Python文件操作

文章目录
一.从文件中读取数据
1.1 读取整个文件
1.2 逐行读取
1.3 创建一个包含文件各行内容的列表
1.4 使用文件的内容
二. 写入文件
2.1 写入空文件
2.2 写入多行
2.3 附加到文件
三.存储数据
3.1 使用json.dump() 和json.load()
3.2 保存和读取用户生成的数据
3.3 重构
参考:
一.从文件中读取数据
文本文件可存储的数据量多得难以置信:天气数据、交通数据、社会经济数据、文学作品等。每当需要分析或修改存储在文件中的信息时,读取文件都很有用,对数据分析应用
程序来说尤其如此。例如,你可以编写一个这样的程序:读取一个文本文件的内容,重新设置这些数据的格式并将其写入文件,让浏览器能够显示这些内容。
要使用文本文件中的信息,首先需要将信息读取到内存中。为此,你可以一次性读取文件的全部内容,也可以以每次一行的方式逐步读取。

1.1 读取整个文件
要读取文件,需要一个包含几行文本的文件。
下面首先来创建一个文件,它包含关系型数据库的名称以及排名。

Oracle 1
MySQL 2
SQL Server 3
PostgreSQL 4

代码:
文件路径给一定要是’/’,’’会报错

with open(‘E:/python/file_test/db.txt’) as file_object:
contents = file_object.read()
print(contents)

测试记录:

Oracle 1
MySQL 2
SQL Server 3
PostgreSQL 4

1.2 逐行读取
读取文件时,常常需要检查其中的每一行:你可能要在文件中查找特定的信息,或者要以某种方式修改文件中的文本。

要以每次一行的方式检查文件,可对文件对象使用for 循环。

代码:

filename = ‘E:/python/file_test/db.txt’

with open(filename) as file_object:
for line in file_object:
print(line)

测试记录:

E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/file_test1.py
Oracle 1

MySQL 2

SQL Server 3

PostgreSQL 4

Process finished with exit code 0

我们打印每一行时,发现空白行更多了
为何会出现这些空白行呢?因为在这个文件中,每行的末尾都有一个看不见的换行符,而print 语句也会加上一个换行符,因此每行末尾都有两个换行符:一个来自文件,另一
个来自print 语句。要消除这些多余的空白行,可在print 语句中使用rstrip().

代码:

filename = ‘E:/python/file_test/db.txt’

with open(filename) as file_object:
for line in file_object:
print(line.rstrip())

测试记录:

E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/file_test1.py
Oracle 1
MySQL 2
SQL Server 3
PostgreSQL 4

Process finished with exit code 0

1.3 创建一个包含文件各行内容的列表
使用关键字with 时,open() 返回的文件对象只在with 代码块内可用。如果要在with 代码块外访问文件的内容,可在with 代码块内将文件的各行存储在一个列表中,并在with 代码块外使用该列表:你可以立即处理文件的各个部分,也可推迟到程序后面再处理。

代码:

filename = ‘E:/python/file_test/db.txt’

with open(filename) as file_object:
lines = file_object.readlines()

for line in lines:
print(line.rstrip())

测试记录:

E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/file_test1.py
Oracle 1
MySQL 2
SQL Server 3
PostgreSQL 4

Process finished with exit code 0

1.4 使用文件的内容
将文件读取到内存中后,就可以以任何方式使用这些数据了。下面以简单的方式使用圆周率的值。首先,我们将创建一个字符串,它包含文件中存储的所有数字,且没有任何空格。

文件信息:

3.1415926535
8979323846
2643383279

代码:

filename = ‘E:/python/file_test/pi.txt’

with open(filename) as file_object:
lines = file_object.readlines()

pi_string = ”
for line in lines:
line_format = line.rstrip()
line_format = line_format.lstrip()
pi_string += line_format

print(pi_string)
print(len(pi_string))

测试记录:

E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/file_test2.py
3.141592653589793238462643383279
32

Process finished with exit code 0

二. 写入文件
保存数据的*简单的方式之一是将其写入到文件中。通过将输出写入文件,即便关闭包含程序输出的终端窗口,这些输出也依然存在:你可以在程序结束运行后查看这些输出,可与别人分享输出文件,还可编写程序来将这些输出读取到内存中并进行处理。

2.1 写入空文件
要将文本写入文件,你在调用open() 时需要提供另一个实参,告诉Python你要写入打开的文件。为明白其中的工作原理,我们来将一条简单的消息存储到文件中,而不是将其打印到屏幕上。

代码:

filename = ‘E:/python/file_test/programming.txt’

with open(filename, ‘w’) as file_object:
file_object.write(“I love programming.”)

测试记录:

C:\>more E:\python\file_test\programming.txt
I love programming.

C:\>

2.2 写入多行
函数write() 不会在你写入的文本末尾添加换行符,因此如果你写入多行时没有指定换行符,文件看起来可能不是你希望的那样.

代码:

filename = ‘E:/python/file_test/programming.txt’

with open(filename, ‘w’) as file_object:
file_object.write(“I love programming.\n”)

测试记录:

C:\>more E:\python\file_test\programming.txt
I love programming.
I love creating new games.

C:\>

2.3 附加到文件
如果你要给文件添加内容,而不是覆盖原有的内容,可以附加模式 打开文件。你以附加模式打开文件时,Python不会在返回文件对象前清空文件,而你写入到文件的行都将添加到文件末尾。如果指定的文件不存在,Python将为你创建一个空文件。

代码:

filename = ‘E:/python/file_test/programming.txt’

with open(filename, ‘a’) as file_object:
file_object.write(“I also love finding meaning in large databases.\n”)
file_object.write(“I lowe creating apps that can run in a browser.\n”)

测试记录:

C:\>more E:\python\file_test\programming.txt
I love programming.
I love creating new games.
I also love finding meaning in large databases.
I lowe creating apps that can run in a browser.

三.存储数据
很多程序都要求用户输入某种信息,如让用户存储游戏首选项或提供要可视化的数据。不管专注的是什么,程序都把用户提供的信息存储在列表和字典等数据结构中。用户关闭程序时,你几乎总是要保存他们提供的信息;一种简单的方式是使用模块json 来存储数据。

模块json让你能够将简单的Python数据结构转储到文件中,并在程序再次运行时加载该文件中的数据。你还可以使用json 在Python程序之间分享数据。更重要的是,JSON数据格式并非Python专用的,这让你能够将以JSON格式存储的数据与使用其他编程语言的人分享。这是一种轻便格式,很有用,也易于学习。

3.1 使用json.dump() 和json.load()
我们来编写一个存储一组数字的简短程序,再编写一个将这些数字读取到内存中的程序。*个程序将使用json.dump() 来存储这组数字,而第二个程序将使用json.load() 。

函数json.dump() 接受两个实参:要存储的数据以及可用于存储数据的文件对象。下面演示了如何使用json.dump() 来存储数字列.

代码:

import json

numbers = [2 ,3 ,5 ,7 ,11 ,13]

filename = ‘E:/python/file_test/numbers.json’
with open(filename, ‘w’) as f_obj:
json.dump(numbers, f_obj)

测试记录:

C:\>more E:\python\file_test\numbers.json
[2, 3, 5, 7, 11, 13]

C:\>

下面演示了如何使用json.load() 来读取数字列.
代码:

import json

filename = ‘E:/python/file_test/numbers.json’
with open(filename) as f_obj:
numbers = json.load(f_obj)

print(numbers)

测试记录:

E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/venv/json_test1.py
[2, 3, 5, 7, 11, 13]

Process finished with exit code 0

3.2 保存和读取用户生成的数据
对于用户生成的数据,使用json 保存它们大有裨益,因为如果不以某种方式进行存储,等程序停止运行时用户的信息将丢失。下面来看一个这样的例子:用户首次运行程序时被提示输入自己的名字,这样再次运行程序时就记住他了。

我们先来存储用户的名字.

代码:

import json
# 如果以前存储了用户名,就加载它
# 否则,就用提示用户输入用户名并存储它

filename = ‘E:/python/file_test/username.json’

try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input(“What is your name?”)
with open(filename, ‘w’) as f_obj:
json.dump(username, f_obj)
print(“We’ll remember you when you come back, ” + username + “!”)
else:
print(“Welcome back, ” + username + “!”)

测试记录:

— *次
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/json_test2.py
What is your name? Oracle
We’ll remember you when you come back, Oracle!

Process finished with exit code 0

— 第二次
E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/json_test2.py
Welcome back, Oracle!

Process finished with exit code 0

3.3 重构
你经常会遇到这样的情况:代码能够正确地运行,但可做进一步的改进——将代码划分为一系列完成具体工作的函数。这样的过程被称为重构 。重构让代码更清晰、更易于理解、更容易扩展。

要重构json_test2.py,可将其大部分逻辑放到一个或多个函数中。json_test2.py的重点是问候用户,因此我们将其所有代码都放到一个名为greet_user() 的函数中,获取存量的用户名放在一个名为get_stored_username()的函数中,获取新的输入用户名的信息放在一个名为get_new_username()的函数中。

这样每个函数只做一件事情,greet_user() 没有过多的代码,直接调用其余的几个函数即可。

代码:

import json

def get_stored_username():
“””如果存储了用户名,就获取它”””
filename = ‘E:/python/file_test/username.json’
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
return None
else:
return username

def get_new_username():
“””提示用户输入用户”””
username = input(“What is your name?”)
filename = ‘E:/python/file_test/username.json’
with open(filename, ‘w’) as f_obj:
json.dump(usernmae, f_obj)
return username

def greet_user():
“””问候用户,并指出其名字”””
username = get_stored_username()
if username:
print(“Welcome back, ” + username + “!”)
else:
username = get_new_username()
print(“We’ll remeber you when you come back, ” + username + “!”)

greet_user()

测试记录:

E:\python\learn_python1\venv\Scripts\python.exe E:/python/learn_python1/json_test2.py
Welcome back, Oracle!

Process finished with exit code 0

参考:
1.Python编程:从入门到实践

python实现读取pdf格式文档

文章目录
一、 准备工作
二、部分变量的含义
三、PDFMiner类之间的关系
四、代码实现
python实现读取pdf格式文档
一、 准备工作
安装对应的库
pip install pdfminer3k
pip install pdfminer.six

二、部分变量的含义
PDFDocument(pdf文档对象)
PDFPageInterpreter(解释器)
PDFParser(pdf文档分析器)
PDFResourceManager(资源管理器)
PDFPageAggregator(聚合器)
LAParams(参数分析器)

三、PDFMiner类之间的关系%title插图%num

PDFMiner的相关文档(点击跳转)

四、代码实现
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# datetime:2021/3/17 12:12
# software: PyCharm
# version: python 3.9.2

def changePdfToText(filePath):
“””
解析pdf 文本,保存到同名txt文件中

param:
filePath: 需要读取的pdf文档的目录
introduced module:
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams
from pdfminer.pdfdocument import PDFDocument, PDFTextExtractionNotAllowed
import os.path
“””
file = open(filePath, ‘rb’) # 以二进制读模式打开
# 用文件对象来创建一个pdf文档分析器
praser = PDFParser(file)
# 创建一个PDF文档
doc = PDFDocument(praser, ”) # praser :上面创建的pdf文档分析器 ,第二个参数是密码,设置为空就好了
# 连接分析器 与文档对象
praser.set_document(doc)
# 检测文档是否提供txt转换,不提供就忽略
if not doc.is_extractable:
raise PDFTextExtractionNotAllowed
# 创建PDf 资源管理器 来管理共享资源
rsrcmgr = PDFResourceManager()
# 创建一个PDF设备对象
laparams = LAParams()
device = PDFPageAggregator(rsrcmgr, laparams=laparams)
# 创建一个PDF解释器对象
interpreter = PDFPageInterpreter(rsrcmgr, device)
result = [] # 内容列表
# 循环遍历列表,每次处理一个page的内容
for page in PDFPage.create_pages(doc):
interpreter.process_page(page)
# 接受该页面的LTPage对象
layout = device.get_result()
for x in layout:
if hasattr(x, “get_text”):
result.append(x.get_text())
fileNames = os.path.splitext(filePath) # 分割
# 以追加的方式打开文件
with open(fileNames[0] + ‘.txt’, ‘a’, encoding=”utf-8″) as f:
results = x.get_text()
# print(results) 这个句可以取消注释就可以在控制台将所有内容输出了
f.write(results) # 写入文件

# 调用示例 :

# path = u’E:\\1.pdf’
# changePdfToText(path)

pandas数值运算方法

pandas数值运算方法

1、通用函数:保留索引:
对Series或DataFrame对象使用numpy的通用函数时,返回的是保留索引的pandas对象

2、通用函数:索引对齐:
当两个Series或DataFrame对象进行二元计算时,pandas会在计算过程中自动,对齐两个对象的索引。

1.Series索引对齐,结果输出的是,索引的并集,但是只有交集才有计算结果,其他返回为空,当然,也可以设置空值,

添加fill_value参数,进行填补空值。若两个都是空值,则不进行填充(必须使用通用函数,例如add、sub)

2.DataFrame索引对齐,结果同上,只不过是同时对齐 列索引 和 行索引 。就算是顺序不同,结果的索引都会自动排列的。

若想补充空值,同样的使用通用函数,添加fill_value参数即可

运算符 通用函数
+ add()
– sub()、subtract()
* mul()、multiply()
/ div()
// floordiv()
% mod()
** pow()
以上通用函数,前面可以加一个r(例如radd()),表示顺序颠倒1+2变为2+1

3、通用函数:Series和DataFrame的计算

Series和DataFrame进行计算时,默认是从行上面减的(axis=1),若想在列上面减,可以使用通用函数,设置axis=0即可

他们进行计算时,与前面的一样,都是进行索引自动对其的。

python多进程

python多进程

1.使用进程完成多任务
1.1多进程示例程序
# from threading import Thread # 1 多线程方式1
import threading # 2 多线程方式2
import time
import multiprocessing # 多进程方式

def test1():
while True:
print(“1———-“)
time.sleep(1)

def test2():
while True:
print(“2———-“)
time.sleep(1)

def main():
# Thread() # 1
# tp1 = threading.Thread(target=test1) # 2
# tp2 = threading.Thread(target=test2)
# tp1.start()
# tp2.start()

tp1 = multiprocessing.Process(target=test1) # 2
tp2 = multiprocessing.Process(target=test2)
tp1.start()
tp2.start()

if __name__ == “__main__”:
main()

进程完成多任务所耗费的资源比较大

线程依赖于进程 没有进程就没有线程

2. 通过队列完成进程间的通信
示例程序

import multiprocessing

def download_from_web(q):
# 模拟从网络下载数据
data = [11, 22, 33, 44]
# 向队列写入数据
for temp in data:
q.put(temp)
print(“—download complete.—“)

def analysis_data(q):
“””数据处理”””
waiting_analysis_data = list()
# 从队列获取数据
while True:
data = q.get()
waiting_analysis_data.append(data)
if q.empty():
break
# 模拟数据处理
print(waiting_analysis_data)

def main():
# 1.创建一个队列
q = multiprocessing.Queue(3)
# 2.创建多个进程,将队列的引用当作实参进行传递到里面
p1 = multiprocessing.Process(target=download_from_web, args=(q,))
p2 = multiprocessing.Process(target=analysis_data,args=(q,))
p1.start()
p2.start()

if __name__ == “__main__”:
main()

3. 进程池
示例程序

import os
import multiprocessing

def copy_file(file_name, old_folder_name, new_folder_name):
“””完成问价的复制”””
print(“=====>模拟COPY文件:从%s—>到%s 文件名是:%s” %(old_folder_name, new_folder_name, file_name))

def main():
# 1.获取用户要复制的文件夹的名字
old_folder_name = input(“请输入要COPY的文件夹的名字:”)
# 2. 创建一个新的文件夹
try:
new_folder_name = old_folder_name + “[复件]”
os.mkdir(new_folder_name)
except:
pass
# 3. 获取文件夹的所有待COPY的文件名字 listdir()
file_names = os.listdir(old_folder_name)
# 4. 创建进程池
po = multiprocessing.Pool(5)
# 5. 向进程池中添加copy文件任务
for file_name in file_names:
po.apply_async(copy_file,args=(file_name, old_folder_name, new_folder_name))
po.close()
po.join()

# 5. 复制原文件夹中的文件到新的文件夹中

if __name__ == “__main__”:
main()

Python—random,time,PIL库

Python—random,time,PIL库

文章目录
random库
生成随机数字
列表随机挑选元素
time模块
PIL类
random库
random.seed(a=None, version=2)

设置随机种子,若不想让随机函数,有随机性,可以手动设置种子,以后每次随机出来的数字就会一样了

生成随机数字
random.randrange(stop)

random.randrange(start, stop[, step])

在range()中随机挑选一个数字。

从 range(start, stop, step) 返回一个随机选择的元素。 这相当于 choice(range(start, stop, step)) ,但实际上并没有构建一个 range 对象。

random.randint(a, b)

在[a,b]中随机挑选一个整数

列表随机挑选元素
random.choice(seq)

从非空序列 seq 返回一个随机元素。 如果 seq 为空,则引发 IndexError。

random.choices(population, weights=None, *, cum_weights=None, k=1)

从population中选择替换,返回大小为 k 的元素列表。 如果 population 为空,则引发 IndexError。

如果指定了 weight 序列,则根据相对权重进行选择。 或者,如果给出 cum_weights 序列,则根据累积权重(可能使用 itertools.accumulate() 计算)进行选择。 例如,相对权重[10, 5, 30, 5]相当于累积权重[10, 15, 45, 50]。 在内部,相对权重在进行选择之前会转换为累积权重,因此提供累积权重可以节省工作量。

若即未指定weight也未指定cum_weights,则以相等的概率进行选择,如果提供了权重序列,则它必须与population序列的长度相同。

有放回的随机抽样

random.shuffle(x[, random])

将x序列随机打乱位置。

没有返回值,在原序列上进行修改。

对于样本量大的对象,且不想打乱顺序的,可以打乱对象的索引。random.shuffle(range(len(x)))

random.sample(population, k)

返回从总体序列或者集合中选择的唯一元素的k长度的列表。无重复的随机抽样。

返回一个新列表,保持原始总体不变。

例如:sample(range(10000000), k=60)

random.random()

返回[0.0 , 1.0)范围内的一个随机浮点数。

random.uniform(a, b)

返回一个随机浮点数。范围[小,大]

eval(‘1+3’)它会将1+3字符串的引号去掉,然后计算它的值。

time模块
time.time()时间戳。从1970年1月1日00:00:00到现在的秒数

time.asctime()当地时间,返回一个字符串类型

time.localtime()本地时间,返回一个时间对象的字符串

time.ctime()当地时间,一般使用这个函数获取当地时间

time.strftime(‘%Y-%m-%d %H:%M:%S’)将时间转化为指定格式的字符串。

time.strptime(‘2020-05-29 14:27:21′,’%Y-%m-%d %H:%M:%S’)将指定格式的字符串,转化为时间类型的字符串

time.sleep(2)休眠2秒

PIL类
第三方库
%title插图%num

莱文斯顿距离(python版)

莱文斯顿距离(python版)

莱文斯顿距离(python版)
leetcode No.72
leetcode No.72
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的*少操作数 。

你可以对一个单词进行如下三种操作:

插入一个字符
删除一个字符
替换一个字符
示例:

输入:word1 = “intention”, word2 = “execution”
输出:5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)

首先,使用动态规划思想,首先创建一个二维数组subset,长度为len(word2) + 1,宽度为len(word1) + 1,二维数组中的每一个位置用来记录每一步的*小距离。其中*行表示word1为空字符串,并依次从空字符串变成word2(依次插入);*列表示word2为空字符串,并依次从word1变成空字符串(依次删除)。根据上面已知条件对数组进行初始化赋值。

然后,按照以下条件依次对二位数组中的每个位置(row, column)进行赋值:
(1)当word1[row – 1] != word2[column – 1]时,subset[row][column] 的取值等于该位置左方、上方、左上方距离为1的位置的*小值加1,即
subset[row][column] = min(subset[row – 1][column – 1], subset[row – 1][column], subset[row][column – 1]) + 1
(2)当word1[row – 1] == word2[column – 1]时,subset[row][column] 的取值等于该位置左上方的值,可以理解为由于字符相等编辑距离无需加1操作,即当前*小距离等于同时删除word1以及word2的当前字符的*小距离(左上方距离为1处的值)。

下面解释一下二维数组中的移动方向分别表示的意义:

↓ 表示删除word1的当前字符操作(距离+1)
→ 表示插入word2的当前字符操作(距离+1)
↘ 表示将当前word1的字符替换为word2的当前字符(距离+1)
↖ 可以理解为当前word2的字符与当前word1的字符相同时,同时将这两个字符删除(距离维持不变)
举例,word1=kitten,word2=sitting

%title插图%num
word1与word2*小编辑距离即为二维数组*右下方的值:
subset[-1][-1] == 3

代码(python):

def minDistance(word1, word2):
length1 = len(word1) + 1
length2 = len(word2) + 1
subset = [[0] * length2 for i in range(length1)]
for i in range(length2):
subset[0][i] = i
for j in range(length1):
subset[j][0] = j
for row in range(1, length1):
for column in range(1, length2):
if word1[row – 1] != word2[column – 1]:
subset[row][column] = min(subset[row – 1][column – 1],\
subset[row – 1][column], subset[row][column – 1]) + 1
else:
subset[row][column] = subset[row – 1][column – 1]
return subset[-1][-1]

测试:

word1, word2 = “horse”, “ros”
print(minDistance(word1, word2))

输出:

3

Python logging模块继承逻辑

 

0X00 起因
在使用一个第三方库时,在我定义的日志文件中一直有额外的日志输出,于是开始了DEBUG之路。

涉及到的相关知识:logger的继承关系、handler继承、basicConfig、导入另一个模块且该模块包含logger会引发什么现象

0X01 DEMO
可能起因中的话并不能很清晰的描述我到底碰到了什么情况,所以直接上代码,给几个DEMO,大伙可以分析分析代码的日志会怎么输出,输出到哪个文件,如果全部分析正确了,那么说明相关知识已经掌握了。如果分析不出来,那么就还没有弄清楚相关细节。以两个py文件为例,a.py和b.py,我们直接运行b.py,因为在b中会import a。

1.
a.py:

from logging.handlers import RotatingFileHandler
import logging

a_logger = logging.getLogger(__name__)
a_logger.setLevel(logging.WARNING)
formatter = logging.Formatter(‘%(asctime)s %(levelname)s [%(lineno)d]: %(message)s’)
update_debug = RotatingFileHandler(‘./a.log’, maxBytes=20*1024*1024, backupCount=5)
update_debug.setFormatter(formatter)
a_logger.addHandler(update_debug)

a_logger.warning(‘log from a’)
b.py:

import logging
import a

logging.basicConfig(
filemode=’a’,
filename=’./b.log’
)

logging.warning(‘log from b’)
结果:a.log中记录log from a,b.log中记录log from b

2.
a.py:

from logging.handlers import RotatingFileHandler
import logging

a_logger = logging.getLogger(__name__)
a_logger.setLevel(logging.WARNING)
formatter = logging.Formatter(‘%(asctime)s %(levelname)s [%(lineno)d]: %(message)s’)
update_debug = RotatingFileHandler(‘./a.log’, maxBytes=20*1024*1024, backupCount=5)
update_debug.setFormatter(formatter)
a_logger.addHandler(update_debug)

a_logger.warning(‘log from a’)
b.py:

import logging

logging.basicConfig(
filemode=’a’,
filename=’./b.log’
)

logging.warning(‘log from b’)

import a
结果:a.log中记录了log from a,b.log中先记录了log from b,再记录了log from a。

3.
a.py:

from logging.handlers import RotatingFileHandler
import logging

a_logger = logging.getLogger(__name__)
a_logger.setLevel(logging.WARNING)
formatter = logging.Formatter(‘%(asctime)s %(levelname)s [%(lineno)d]: %(message)s’)
update_debug = RotatingFileHandler(‘./a.log’, maxBytes=20*1024*1024, backupCount=5)
update_debug.setFormatter(formatter)
a_logger.addHandler(update_debug)

def func():
a_logger.warning(‘log from a’)
b.py:

import logging
import a

logging.basicConfig(
filemode=’a’,
filename=’./b.log’
)

logging.warning(‘log from b’)

a.func()
结果:a.log记录了log from a,b.log先记录了log from b,再记录了log from a

4.究*折磨
a.py:

import logging

logging.basicConfig(
filemode=’a’,
filename=’./a.log’
)

a_logger = logging.getLogger(__name__)
a_logger.warning(‘log from a’)
b.py:

import logging
import a

logger = logging.getLogger()
logger.warning(‘log from b’)
结果:a.log先记录了log from a,再记录了log from b

0X02 分析
关于logging模块有几个重要的知识点,掌握之后,便可以很好的分析日志究竟是怎么记录的了

1.默认情况下logger分为root logger和其他logger,basicConfig配置的就是root logger,创建的其他logger会自动继承于root logger,并且在调用其他logger记录日志时,会先调用logger自身配置的handler,然后调用父亲的handler。有点绕,给个例子:

import logging
# 设置root logger的handler为FileHandler,以a的模式将日志追加到a.log中
logging.basicConfig(
filemode=’a’,
filename=’./a.log’
)
# 获取一个__name__的logger,该logger自动继承于root logger,并且该logger在日志记录时
# 先会调用自身的handler,然后调用root logger的handler。在此处logger并未设置handler,所以
# 只会调用root logger的handler,也就会将日志记录到a.log中了
a_logger = logging.getLogger(__name__)
a_logger.warning(‘log from a’)
2.当导入的模块中定义了logger时,并且在*外层就进行了日志记录,那么在导入之后就会直接记录日志,因为python导入模块会将模块外层代码执行。参考00X1 DEMO中的1和2两个例子,先import a和后import a的日志记录情况是不同的。那么如何规避这种情况了,那就是在函数中进行日志记录,那么只有在调用该函数时才会记录日志,import模块时不会记录。

3.如何让每个logger只调用自己的handler,不要去调用父类的handler?添加一个配置即可:

logger.propagate = False
4.创建的logger默认只会继承root logger,两个同级logger并不会自动产生继承关系,除非手动指定,例如:

import logging

a_logger = logging.getLogger(‘a’)
b_logger = logging.getLogger(‘b’)
print a_logger.parent
print b_logger.parent
a_logger和b_logger的parent都为logging.RootLogger object

Pandas常用功能笔记

Pandas常用功能笔记

pandas包导入
import pandas as pd
单个sheet处理
# 读取excel数据
file = ‘./aa.xlsx’
data_1 = pd.read_excel(file)
data_1.to_excel(file_save, index=False, header=False)

# 写入excel数据
file_save = ‘./bb.xlsx’
sample_1 = [(1, 2), (3, 4), (5, 6)]
data_2 = pd.Data_Frame(sample_1)
data_2.to_excel(file_save, index=False, header=[‘odd’, ‘even’])

sample_2 = {‘odd’: [1, 3, 5], ‘even’: [2, 4, 6]}
data_3 = pd.DataFrame(sample_2)
data_3.to_excel(file_save, index=False, header=True)
多个sheet处理
# 读取sheet数据
file = ‘./aa.xlsx’
data_1 = pd.read_excel(file, sheet=’data_1′)

# 写入sheet数据
f_save = pd.ExcelWriter(‘./bb.xlsx’)
sample_1 = [(1, 2), (3, 4), (5, 6)]
sheet_1 = pd.Data_Frame(sample_1)
sheet_1.to_excel(file_save, index=False, header=[‘odd’, ‘even’], sheet_name=’tuple_data’)

sample_2 = {‘odd’: [1, 3, 5], ‘even’: [2, 4, 6]}
sheet_2 = pd.DataFrame(sample_2)
sheet_2.to_excel(file_save, index=False, header=True, sheet_name=’dict_data’)
数据选择
file = r’./aa.xlsx’
df = pd.read_excel(file)
odd_data = df[‘odd’]
odd_list = df[‘odd’].values.to_list()

# 按名称选择
odd, even = df.loc([:, [‘odd’, ‘even’]])
odd_part, even_part = df.loc([0:2, [‘odd’, ‘even’]]) # 选取前两行

# 按列顺序选择
odd, even = df.iloc([:, [0, 1]])
odd_part, even_part = df.iloc([0:2, [0, 1]])
数据去重
file = r’./aa.xlsx’
df = pd.read_excel(file)
df.drop_duplicates(subset=[‘odd’,’even’],keep=’first’,inplace=True) # 在原数据上操作

# 不在原数据上操作,重新生成副本
new_data = drop_duplicates(subset=[‘odd’,’even’],keep=’first’,inplace=False)
遍历excel中的所有sheet
file = r’./aa.xlsx’
df = pd.ExcelFile(file)

for name in df.sheet_names:
sheet = pd.read_excel(file, sheet_name=name)
……