Python技术

Python技术 's Blog


  • 首页

  • 标签

  • 归档

  • 关于

国庆长假已结束,Python 告诉你 6 亿国人都去哪儿浪了

发表于 2020-10-12 | 分类于 python

2020 注定是不平凡的一年,一开年就被新冠疫情来了当头一棒,一瞬间大家都不约而同的采取家里蹲策略,在政府的得力领导下,全部人民上下一条心,到了四五月份终于将疫情稳定控制住了,时隔半年,国内疫情早已趋于稳定,人们的生活也基本恢复正常。

恰逢国庆中秋两个节日重合,在家憋这么久的人们怎么能不出去看看祖国的大好河山。据新华网消息,整个国庆长假外出游玩人次达 6.37 亿人次,那么这么多人都到哪儿去玩了呢,今天我们就用 Python 做一个全国热门景区热点图。

阅读全文 »

你在享受十一长假时,Python 已悄悄地变了

发表于 2020-10-11 | 分类于 python

标题图

Python 3.9 在经历了将近一年的试用期后,于 10月5日(2020年)发布了稳定版,意味着,在下一版本发布之前,不会在做改动,童鞋们可以放心大胆地更新了。享受完惬意的十一长假后,我们快来看看新版本带来了哪些惊喜

阅读全文 »

Office 文件转 PDF 之服务实战

发表于 2020-09-29 | 分类于 Office 文件转 PDF 之服务实战

小编之前写了一篇关于 Office 文件转 PDF 的实战文章,详见Python 小技之 Office 文件转 PDF 但是在平时的工作中,咱们需要通过接口的形式来调用具体的转换逻辑,同时开可以将文件转换写成服务的形式,将服务开启后传入参数或者地址即可直接调用逻辑转换,今天的文章主要讲解如何将文件转换写成服务;

一起拭目以待吧!!!

文件服务器

Office 文件转 PDF 涉及到文件的传输,所以考虑用文件服务器来进行文件的传递,客户端如果有文件服务器的话, 同样在服务端也需要写一个文件服务器来返回转换完成的文件,以供客户端使用,文件服务器实现思路如下:

逻辑结构

文件结构结构逻辑图如下:

代码结构

前端文件上传下载页面

1
2
3
4
5
6
7
8
9
10
<body>
    <form action="download" method="GET",enctype="multipart/form-data">
        要下载的文件: <input type="text" value="请上传文件" name="filename" />
        <input type="submit" value="download">
    </form>

    <form action="/file_server/cgi-bin/upload.py" method="POST" enctype="multipart/form-data">
        要上传的文件: <input type="file" name="filename" />
        <input type="submit" value="upload">
    </form>

上传文件

上传文件 upload.py 部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import cgi, os

form = cgi.FieldStorage()

item = form["filename"]

if item.filename:
    fn = os.path.basename(item.filename)
    open("/home/sxhlinux/data/" + fn, "wb").write(item.file.read())
    msg = "File" + fn + ' upload successfully !'
else:
    msg = 'no file is uploaded '

print("""\
Content-type: text/html\n
<html>
<head>
<meta charset="utf-8">
<title>Hello world</title>
</head>
<body>
<h2>名称: %s</h2>
</body>
<html>
""" % (msg,))

下载文件

下载文件 download.py 部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
form = cgi.FieldStorage()

filename = form.getvalue('filename')

dir_path = "F:/WorkSpace/FilesToPDF/file_server/tmp"

target_path = dir_path + str(filename)

if os.path.exists(target_path) == True:
    print("Content-Type: application/octet-stream")
    print('Content-Disposition: attachment; filename = "%s"' % filename)

    print(target_path)

    sys.stdout.flush()
    fo = open(target_path, "rb")
    sys.stdout.buffer.write(fo.read())
    fo.close()
else:
    print("""\
            Content-type: text/html\n
            <html>
            <head>
            <meta charset="utf-8">
            <title>File server</title>
            </head>
            <body>
            <h1> %s doesn't exist in the server:
            files in the server list below: </h1>""" % filename)

    for line in os.popen(filename):
        name = line.strip().split(' ', 8)
        type(name)
        if len(name) == 9:
            print("""
            <form action="/cgi-bin/download.py" method="get">%s
            <input type="submit" name="filename" value="%s">
            </form>""" % (line, name[8]))

文件服务

文件服务入口 server.py 部分代码如下:

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

if __name__ == '__main__':
    try:
        handler = CGIHTTPRequestHandler
        handler.cgi_directories = ['/cgi-bin', '/htbin']
        #port = int(sys.argv[1])
        port = 8001
        print('port is %d' % port)
        server = HTTPServer(('', port), handler)
        print('Welcome to my website !')
        server.serve_forever()

    except KeyboardInterrupt:
        print('^C received, shutting down server')
        server.socket.close()	

以上服务启动后即可使用。

转换逻辑接口

转换接口使用了 Python Flask框架,在文件转换逻辑里面需要引入具体的转换逻辑,接口逻辑实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from flask import Flask, render_template,request
import requests
import config
from requests import get
import files2pdf  # 引入转换逻辑
import os, shutil
from flask import Flask, render_template, url_for, send_from_directory,json,make_response,jsonify

app = Flask(__name__, static_folder='/static')
app.config.from_object(config)
app.config["SECRET_KEY"] = "123456"

@app.route('/')
def index():
    return "Welcome to You,Please visit the url:http://IP:5000/upload_file?filePath=xxx.pptx"

#pathname = ''
@app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
        if request.method == 'POST' or request.method == 'GET':
            file_url = request.args.get('filePath', '')
            req = get(file_url)
            if req.status_code == 404:
                print("no file")

                return
            # 取正确的转换文件名称
            filename = file_url.split('/')[-1]
            name = filename.split('?')[1]
            ppt_name = name.split('=')[-1]
            print(ppt_name)

            with open(ppt_name, "wb") as file:
                # get request
                # response = get(url)
                # write to file
                file.write(req.content)

            # 判断要转换的文件是否存在
            if os.path.exists(ppt_name) and not os.path.exists(file_path + '/' + ppt_name):
                shutil.move(ppt_name, file_path)
            elif os.path.exists(ppt_name) and os.path.exists(file_path + '/' + ppt_name):
                print('file alreadly exists')
                os.remove(ppt_name)
                print("already deleted exists file")

            pdfConverter = files2pdf.PDFConverter(file_path + '/' + ppt_name)  # 调用文件转换逻辑
            # print("transform complete:"+pdfConverter)
            pdfConverter.run_conver()

            # file transform finshed --> Get file's name
            re_name = ppt_name.replace('.pptx', '.pdf')
            print('New name is:' + re_name)
            # /static/%E6%B0%B4%E9%92%A2%E9%9B%86%E5%9B%A2%E6%99%BA%E6%85%A7%E5%85%9A%E5%BB%BA%E5%9F%B9%E8%AE%AD%E8%B5%84%E6%96%990420%282%29.pdf
            re_url = 'IP:8001'  # 文件服务地址
            # urlfor = url_for('static', filename=re_name)
            return re_url + url_for('static', filename=re_name)
            #return  render_template('result_link.html')

if __name__ == '__main__':

    app.run(host='0.0.0.0', port=5000)
    

调用

先启动 server.py 后再启动 flaskdemo.py 传入参数即可调用逻辑。也可以用 postman 调用,调用实例如下:

调用实例

总结

今天的文章主要是继上一篇 Python 实战之小工具的运用的延申,希望对大家有所帮助,如有问题咱们讨论区见!

So 今天的小 Tip 你安利到了吗?

示例代码 Office 文件转 PDF 之服务实战

阅读全文 »

工具需用好,阅读源码没烦恼

发表于 2020-09-28 | 分类于 python

工具需用好,阅读源码没烦恼

每当我们接手一个新项目时,面对庞杂的模块、繁复的代码,想必心情是非常绝望的,“这都特么啥呀?”

如果你也有这样的烦恼,那你就应该看这篇文章。

阅读全文 »

Python少有人走过的坑

发表于 2020-09-28 | 分类于 python

Python少有人走过的坑

毫无疑问,print函数是我们日常最常用的函数,无论是格式化输出还是打印中间变量进行调试,几乎没有print接不了的活儿。

但是上一次阿酱就差点被print给坑了。

阅读全文 »

用 Python 制作音乐聚合下载器

发表于 2020-09-27 | 分类于 用 Python 制作音乐聚合下载器

现在的音乐APP有很多,为了不下载很多的APP,所以咱用python做了一个聚合的音乐下载器,现在聚合了咪咕音乐、QQ音乐,下面是效果图

阅读全文 »

2020年,那些已经死亡的公司

发表于 2020-09-22 | 分类于 2020年,那些已经死亡的公司

大家都知道 2020 年因为新冠疫情的原因,有些公司为了生存下去做了降薪、裁员、加班等一系列动作,还有一部分公司直接死亡了,大家一起来看看吧。

阅读全文 »

Python 小技之 Office 文件转 PDF

发表于 2020-09-21 | 分类于 Python 小技之 Office 文件转 PDF

在平时的工作中,难免需要一些 小Tip 来解决工作中遇到的问题,今天的文章给大家安利一个方便快捷的小技巧,将 Office(doc/docx/ppt/pptx/xls/xlsx)文件批量或者单一文件转换为 PDF 文件。 不过在做具体操作之前需要在 PC 安装好 Office,再利用 Python 的 win32com 包来实现 Office 文件的转换操作。

安装 win32com

在实战之前,需要安装 Python 的 win32com,详细安装步骤如下:

使用 pip 命令安装

1
2
3

pip install pywin32

如果我们遇到安装错误,可以通过python -m pip install –upgrade pip更新云端的方式再进行安装即可:

1
2
3

python -m pip install --upgrade pip	
   

下载离线安装包安装

如果 pip 命令未安装成功的话还可以下载离线包安装,方法步骤如下: 首先在官网选择对应的 Python 版本下载离线包:https://sourceforge.net/projects/pywin32/files/pywin32/Build%20221/ 下载好后傻瓜式安装好即可。

文件转换逻辑

详细代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class PDFConverter:
    def __init__(self, pathname, export='.'):
        self._handle_postfix = ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'] # 支持转换的文件类型
        self._filename_list = list()  #列出文件
        self._export_folder = os.path.join(os.path.abspath('.'), 'file_server/pdfconver')
        if not os.path.exists(self._export_folder):
            os.mkdir(self._export_folder)
        self._enumerate_filename(pathname)

    def _enumerate_filename(self, pathname):
        '''
        读取所有文件名
        '''
        full_pathname = os.path.abspath(pathname)
        if os.path.isfile(full_pathname):
            if self._is_legal_postfix(full_pathname):
                self._filename_list.append(full_pathname)
            else:
                raise TypeError('文件 {} 后缀名不合法!仅支持如下文件类型:{}。'.format(pathname, '、'.join(self._handle_postfix)))
        elif os.path.isdir(full_pathname):
            for relpath, _, files in os.walk(full_pathname):
                for name in files:
                    filename = os.path.join(full_pathname, relpath, name)
                    if self._is_legal_postfix(filename):
                        self._filename_list.append(os.path.join(filename))
        else:
            raise TypeError('文件/文件夹 {} 不存在或不合法!'.format(pathname))

    def _is_legal_postfix(self, filename):
        return filename.split('.')[-1].lower() in self._handle_postfix and not os.path.basename(filename).startswith(
            '~')

    def run_conver(self):
        print('需要转换的文件数是:', len(self._filename_list))
        for filename in self._filename_list:
            postfix = filename.split('.')[-1].lower()
            funcCall = getattr(self, postfix)
            print('原文件:', filename)
            funcCall(filename)
        print('转换完成!')

doc/docx 转换为 PDF

doc/docx 转换为 PDF 部分代码如下所示:

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

    def doc(self, filename):
        name = os.path.basename(filename).split('.')[0] + '.pdf'
        exportfile = os.path.join(self._export_folder, name)
        print('保存 PDF 文件:', exportfile)
        gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 0, 8, 4)
        pythoncom.CoInitialize()
        w = Dispatch("Word.Application")
        pythoncom.CoInitialize()  # 加上防止 CoInitialize 未加载
        doc = w.Documents.Open(filename)
        doc.ExportAsFixedFormat(exportfile, constants.wdExportFormatPDF,
                                Item=constants.wdExportDocumentWithMarkup,
                                CreateBookmarks=constants.wdExportCreateHeadingBookmarks)
        w.Quit(constants.wdDoNotSaveChanges)
	def docx(self, filename):
        self.doc(filename)

ppt/pptx 转换为 PDF

ppt/pptx 转换为 PDF 部分代码如下:

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

	def ppt(self, filename):
        name = os.path.basename(filename).split('.')[0] + '.pdf'
        exportfile = os.path.join(self._export_folder, name)
        gencache.EnsureModule('{00020905-0000-0000-C000-000000000046}', 0, 8, 4)
        pythoncom.CoInitialize()
        p = Dispatch("PowerPoint.Application")
        pythoncom.CoInitialize()
        ppt = p.Presentations.Open(filename, False, False, False)
        ppt.ExportAsFixedFormat(exportfile, 2, PrintRange=None)
        print('保存 PDF 文件:', exportfile)
        p.Quit()

    def pptx(self, filename):
        self.ppt(filename)

xls/xlsx 转换为 PDF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    def xls(self, filename):
        name = os.path.basename(filename).split('.')[0] + '.pdf'
        exportfile = os.path.join(self._export_folder, name)
        pythoncom.CoInitialize()
        xlApp = DispatchEx("Excel.Application")
        pythoncom.CoInitialize()
        xlApp.Visible = False
        xlApp.DisplayAlerts = 0
        books = xlApp.Workbooks.Open(filename, False)
        books.ExportAsFixedFormat(0, exportfile)
        books.Close(False)
        print('保存 PDF 文件:', exportfile)
        xlApp.Quit()

    def xlsx(self, filename):
        self.xls(filename)	

执行逻辑转换

1
2
3
4
5
6
7
8
if __name__ == "__main__":
    # 支持文件夹批量导入
    #folder = 'tmp'
    #pathname = os.path.join(os.path.abspath('.'), folder)
    # 也支持单个文件的转换
    pathname = "G:/python_study/test.doc"
    pdfConverter = PDFConverter(pathname)
    pdfConverter.run_conver()

总结

今天的文章主要是 Python 实战之小工具的运用,希望对大家有所帮助,下一期将讲解如何通过接口的方式通过文件服务器来下载文件并转换,敬请期待。。。 So 今天的小 Tip 你安利到了吗?

示例代码 Python 小技之 Office 文件转 PDF

阅读全文 »

还在为多张Excel汇总统计发愁?Python 秒处理真香!

发表于 2020-09-20 | 分类于 python

为什么越来越多的非程序员白领都开始学习 Python ?他们可能并不是想要学习 Python 去爬取一些网站从而获得酷酷的成就感,而是工作中遇到好多数据分析处理的问题,用 Python 就可以简单高效地解决。本文就通过一个实际的例子来给大家展示一下 Python 是如何应用于实际工作中高效解决复杂问题的。

阅读全文 »

做硬核老爸,我用 Python

发表于 2020-09-18 | 分类于 python

前几天,给儿子买了个飞行棋,甚是喜欢,每天都要和我来两盘,昨天准备大战一场时,发现骰子弄丢了,没有骰子就没法玩了,正想要用橡皮做一个,突然想到了个更好的办法,经过一顿折腾,终于搞定了,结果……

阅读全文 »

用 Python 为老师送上节日的祝福

发表于 2020-09-09 | 分类于 python

提到老师,大家首先想到的可能就是在学校中教我们文化课的人,除此之外,在生活或工作中给予我们指导及帮助的人也可称之为老师,今天是教师节,本文我们就使用 Python 来为所有的老师送上节日的祝福。

阅读全文 »

Flask + echarts 轻松搞定 nginx 日志可视化

发表于 2020-09-08 | 分类于 python

最近,线上的业务系统不太稳定,需要分析下访问情况,能拿到的数据只有 nginx 服务器的访问日志,不过难不倒我,用合适的工具,分分钟做出图形化展示,看看怎么做的吧

阅读全文 »

xlwings-能让 Excel 飞上天

发表于 2020-09-07 | 分类于 xlwings-能让 Excel 飞上天

人生苦短,我用 Python!

Python 作为一种脚本语言,其编程方式越来越受程序员们的青睐,同时其应用也越来越广泛,其中数据分析岗位人才需求也日益渐增,运用 Python 相关模块进行数据分析能大大提升工作效率,减轻数据分析人员的工作负担。 在日常办公中,使用 Python 的场景也越来越多,很多重复的工作直接交给程序执行效率会大大提高,所以 Python 操作 Excel 也成为每一个数据分析人员的必备技能,今天的文章就一起来看看 Python 中能操作 Excel 工作表的神器。

Python 操作 Excel 模块简介

Python 操作 Excel 的模块,网上提到的模块大致有:xlwings、xlrd、xlwt、openpyxl、pyxll 等,他们提供的功能归纳起来无非有两种形式:

  • 1、用 Python 读写 Excel 文件,实际上就是读写有格式的文本文件,操作 excel 文件和操作 text、csv 文件没有区别,Excel 文件只是用来储存数据。

  • 2、除了操作数据,还可以调整Excel文件的表格宽度、字体颜色等。另外需要提到的是用 COM 调用 Excel 的 API 操作 Excel 文档同样也是可行的,相当麻烦基本和 VBA 没有区别。

关于 xlwings

为什么 xlwings 能让 Excel 飞起来呢,因为 xlwings 支持 Excel 的读写操作。具体使用请参照 官网 ,一切技术的出现都是为了满足人的惰性,因此 xlwings 能让繁琐的工作简单化、简洁化。

Xlwings 是开源且免费的工具,能够非常方便的读写 Excel 文件中的数据,并且能够进行单元格格式的修改。

xlwings 还可以和 matplotlib、numpy 以及 pandas 无缝连接,支持读写 numpy、pandas 数据类型,将 matplotlib 可视化图表导入到 excel 中。

最重要的是 xlwings 可以调用 Excel 文件中 VBA 写好的程序,也可以让 VBA 调用用 Python 写的程序。

xlwings 优点

  • xlwings 能够非常方便的读写 Excel 文件中的数据,并且能够进行单元格格式的修改
  • xlwings 可以和 Matplotlib 以及 Pandas 无缝连接
  • xlwings 可以调用 Excel 文件中 VBA 写好的程序,也可以让 VBA 调用 Python 写的程序。
  • xlwings 开源免费,并且一直在更新

xlwings 基本操作

xlwings 基本对象

xlwings 安装和使用

和其他模块使用一样,xlwings 在使用之前也需要安装,本文环境为 Python 3.6 版本的 Windows 环境。

模块安装

安装xlwings的最简单方法是通过pip:

1
2
3

 pip install xlwings
 

或者使用conda:

1
2
3

 conda install xlwings
 

再或者

1
2
3
 
 conda install -c conda-forge xlwings
 

引入模块使用

1
2
3

import xlwings as xw

Python to Excel

连接到工作簿最简单便捷的方法是由 xw.Book 提供:它在所有应用程序实例中查找该工作簿并返回错误,但如果同一个工作簿在多个实例中打开,要连接到活动应用程序实例中的工作簿,则需要使用 xw.books 并引用特定应用程序, 使用区别如下:

Header1 Header2 Header3
New book xw.Book() xw.books.add()
Unsaved book xw.Book(‘Book1’) xw.books[‘Book1’]
UBook by (full)name xw.Book(r’D:/test/file.xlsx’) xw.books.open(r’D:/test/file.xlsx’)

注:在 Windows 上指定文件路径时,应该通过在字符串前放置一个 r 来使用原始字符串,或者使用双反斜杠:D:\Test\file.xlsx

Excel 活动对象

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

# 活动应用程序(即Excel实例)
app = xw.apps.active

# 活动工作簿
wb = xw.books.active  # 在活动app
wb = app.books.active  # 在特定app

# 活动工作表
sht = xw.sheets.active  # 在活动工作簿
sht = wb.sheets.active  # 在特定工作簿

# 活动工作表的Range
xw.Range('A1')  #在活动应用程序的活动工作簿的活动表上

基本操作

以下代码展示相关基本操作:

  • 打开表格
  • 引用工作表
  • 引用单元格
  • 引用区域
  • 写入数据(数据写入默认按照行写入,如果要指定相应的列写入则需要添加相应参数,指定参数为:transpose = True)
  • 读取数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

import xlwings as xw
# 打开表格
file_path = r'D:/test/file.xlsx'

xw.Book(file_path)   # 固定打开表格
xw.books.open(file_path) # 频繁打开表格

# 引用工作表
sht = wb.sheets['sheet1']

# 引用单元格
rng = xw.Range('A1')
# rng = sht[0,0] # 此代码第一行的第一列即a1,相当于 pandas 的切片

# 引用区域
rng = sht.range('a1:a5')
# rng = sht['a1:a5']
# rng = sht[:5,0]

# 写入数据

sht.range('a1').value = 'Hello Excel' # 指定一个单元格写入数据

# 按行写入数据
sht.range('a1').value = [1, 2, 3, 4,5,6,7,8]

# 按照列写入数据
sht.range('a2').options(transpose=True).value = [2, 3, 4, 5, 6, 7, 8]

# 按照二维列表的方式写入数据

sht.range('a9').expand('table').value = [['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i'],['j', 'k', 'l']]

# 读取写入的数据

print(sht.range('A1:D5').value)

xlwings 结合 matplotlib

xlwings 结合 Matplotlib 使用能讲图画贴入到 Excel 中,具体使用 pictures.add() 方法就可以很容易地将Matplotlib图作为图片粘贴到表格中。 详细代码如下:

1
2
3
4
5
6
7
8
9

 fig = plt.figure()  # 指定画布
 # plt.plot([1, 2, 3, 4, 5])
 plt.plot([36,5,3,25,78])
 plt.plot([9,10,31,45])
 plt.plot([6,14,45,31])
 sht = xw.Book(r'G:/test/test.xlsx').sheets[0]
 sht.pictures.add(fig, name='myplt', update=True)

结果图片

总结

磨刀不误砍柴工,今天的文章主要是操作 Excel 的工具 xlwings 介绍,大家都用工具操练起来,好好修炼如何拧好螺丝的内功,奥利给!

示例代码 xlwings-能让 Excel 飞上天

阅读全文 »

为妹子打抱不平,我深夜爬取了严选的男性内裤数据,结果……

发表于 2020-09-02 | 分类于 python

上一篇文章通过爬取网易严选的评论数据来探究妹子们的内衣尺码、颜色偏好以及对内衣的评价,通过大家的反响发现好像无意中得罪了某类群体,又满足了某类群体的某种特殊癖好。作为无意的举动,作者深感愧疚。为了为妹子打抱不平,工作加班到深夜之后,我毅然牺牲睡觉时间,来爬取网易的男性内裤数据,看看有什么发现。

阅读全文 »

我半夜爬了严选的女性文胸数据,发现了惊天秘密

发表于 2020-08-30 | 分类于 python

刚刚过去的七夕,相信大家看到最多的是朋友圈秀恩爱(晒花),路上随处可见的也是某某女性手捧鲜花,各种大小花店一抢而空,只剩下满店狼藉。鲜花固然代表着美丽,代表着各种美好的含义,但是也不能教师节送花,母亲节送花,情人节也送花呀!作为情侣以及准情侣之间的礼物,能不能花点心思,送点不一样的,比如内衣……

有的男性朋友会跳出来骂了:说得好听,你知道送花多难吗?这种隐秘的数据,又不好直接开口问,又不能直接丈量,万一送错了不得把美好的事情搞砸了?

钢铁直男的想法总是这么赤果果,其实想知道妹子喜欢什么颜色的内衣,尺码是怎样的,不一定需要直接询问,可以有各种方法可以获取到,这里就不展开这个话题了。

为了探究妹子们的平常对内衣的普遍选择,我连夜爬取了网易严选关键词为“文胸”的商品评论数据,从中挑选了几个代表性的属性来做分析。

阅读全文 »

你只知道with,那with该with who呢?

发表于 2020-08-24 | 分类于 python

你只知道with,那with该with who呢?

在长期的编程实践中,我们必然已经有过使用下面这段代码的经验:

1
2
with open("test.txt", "r", encoding="utf-8") as f:
    s = f.readlines()

有的人知道这么写的原因;但也有很多人不知道,只是单纯地“别人都这么写,我也应该这么写”。

同时,很多知道原因的人也只是知其然而不知其所以然:with语句可以替我们自动关闭打开的文件对象。但是这是通过什么机制办到的呢?

阅读全文 »

当我print时,Python做了什么

发表于 2020-08-24 | 分类于 python

当我print时,Python做了什么

写了这么久的程序,不知道大家有没有思考过,Python到底在干嘛呢?

或者换句话说,当我们执行Python代码的时候,是怎么实现的呢?

阅读全文 »

不用一行代码,用 API 操作数据库,你信吗

发表于 2020-08-23 | 分类于 python

数据库的重要性不言而喻,但是数据库操作起来却不容易,需要用到各种管理工具,各种不同的连接方式,如果有方便的,屏蔽不同数据库细节的工具该多好,功夫不负有心人,我还真找了这样一个工具,不仅支持多种数据库,更厉害的是,不用为适配写一行代码,来了解下吧

阅读全文 »

如何优雅地解析命令行选项

发表于 2020-08-23 | 分类于 python

如何优雅地解析命令行选项

随着我们编程经验的增长,对命令行的熟悉程度日渐加深,想来很多人会渐渐地体会到使用命令行带来的高效率。

自然而然地,我们自己写的很多程序(或者干脆就是脚本),也希望能够像原生命令和其他程序一样,通过运行时输入的参数就可以设定、改变程序的行为;而不必一层层找到相应的配置文件,然后还要定位到相应内容、修改、保存、退出……

想想就很麻烦好吗

阅读全文 »

什么是 MVCC

发表于 2020-08-22 | 分类于 python

上一篇文章我们说到数据库的四种事务隔离级别,可以通过加锁的方式来实现,只是效率太低,事实上,MySQL 是通过 MVCC(多版本并发控制)来实现的。

具体原理有一点点复杂,需要你用点心才能看懂,今天我们就以「可重复读隔离级别」为例来详细说明其具体原理。

假设数据库有如下记录。

我们都知道 InnoDB 引擎下,每一个事务都有一个事务 ID,叫做 transaction id,是在事务开始时系统自动分配的,且该 id 是递增的。同时这个 id 也会记录在数据行上面。言外之意就是数据库表的每行记录是有多个版本的,用事务 ID 来标示这行记录是属于哪个事务操作的。既然是有多个版本,那怎么拿到旧版本的数据记录呢,答案就是在添加一个指针,指向前一个事务 ID 标识的记录。

而这个指针就是我们通常诉所说的 undo log,事实上,旧版本的行记录都不是物理存在的,而是通过 undo log 实时计算出来的。

一致性视图

好了,了解了行记录事务 ID 和回滚指针的概念之后,我们来看看一致性视图。

当在一个事务 A 中查询数据时,只需要确定行记录的数据版本是否在事务 A 启动之前生成的即可,如若是,则可见;否则不可见,则需通过回滚指针找到上一个版本来继续判断属否可见,

因此,就需要在事务启动时,为该事务构造一个事务数组,用来保存该事务启动瞬间,系统中正在活跃的所有事务 ID,也就是启动了但还未提交的事务 ID。

数组中的最小值我们简记为低位,系统中的最大事务 ID 记录为高位,正是这个高位和视图数组组成了我们说的「一致性视图」。

因此,对于任何一个事务 A 来说,任何数据版本的可见行都可以通过一致性视图来得到。

  1. 如果数据版本小于低位,说明是已经提交的记录,则可见。
  2. 如果大于高位,说明是由未来的事务生成的,则不可见。
  3. 如果在高位和低位之间:
    1. 若在数组中,说民该事务还未提交,则不可见,
    2. 如果不在数组中,说明该事务是已经提交了的,则可见。

实战分析

我们针对上图的数据记录,假设有以下三个事务,我们来具体分析下,其一致性视图是怎么样的。

假设(1,1)这行记录的事务 ID 是 90;事务 A 开启前,系统里面只有一个活跃的事务,ID = 99;事务 A、B、C 的版本号分别是 100、101、102。

现在,事务 A、B、C 的视图数组和高位分别是[99,100]/101,[99,100,101]/102,[99,100,101,102]/103。

你要知道,读取数据是从当前版本往前读的,对于事务 A 来说:

  1. 当读取到 (1,3) 的时候,事务 ID = 101,高于高位,不可见。
  2. 往前读取历史版本(1,2),事务 ID = 102,高于高位,不可见。
  3. 继续往前读取历史版本(1,1),事务 ID = 90,低于低位,可见。

这样,我们就通过一致性视图和事务 ID 找到了可见的数据版本,不论事务 A 是什么时候查询的,看到的记录都是一致的。

读提交

上面我们分析了可重复读隔离级别下的一致性视图,那么在读取提交的隔离级别下,又是怎么样的呢?

事实上,他们最主要的区别就是一致性视图的创建时间不一样,对于可重复读隔离级别,一致性视图是在事务开启时刻生成的,之后在该事务中的查询都共用这个一个视图。而对于读提交隔离级别,每一个语句执行前都会生成一个新的视图。

因此,事务 A、B、C 的视图数组和高位分别是[99,100,101]/103,[99,101]/103,[99,102]/103。

对于事务 A 来说:

  1. 当读取到 (1,3) 的时候,事务 ID = 101,在数组中,不可见。
  2. 往前读取历史版本(1,2),事务 ID = 102,不在数组中,可见。

总结

今天我们学习了 MVCC(多版本并发控制)的底层实现方式,虽然过程略显复杂,但这保证了在不加锁的情况下,保证了可重复读,和读提交。读写不互相干扰,能极大的提高并发能力。

别看上面的分析步骤较复杂,事实上我们只需要记住以下两条规则即可。在可重复读隔离级别下,查询只能看到在事务启动前已经提交的数据。在读提交隔离级别下,查询只能看到在语句启动前已经提交的数据。

参考

极客时间 「MySQL实战45讲 08节」。

阅读全文 »
1 … 3 4 5 … 17
Python Geek Tech

Python Geek Tech

一群热爱 Python 的技术人

332 日志
52 分类
45 标签
RSS
GitHub 知乎
Links
  • 纯洁的微笑
© 2019 - 2021 Python Geek Tech
由 Jekyll 强力驱动
主题 - NexT.Mist