分类目录归档:解决方案

为什么小黄鸭调试法在中国行不通

许多程序员都有向他人请教代码问题或解释代码的经历,而在解释的过程中,程序员可能就发觉了问题的解决方案,一边阐述代码的意图,一遍观察代码实际上产生的行为并调试,一旦有任何不协调的地方就能够迅速地发现并解决问题。

小黄鸭调试法就是这样,工作的时候,在电脑旁边放一只小黄鸭,耐心地跟它讲解每一行代码的逻辑和意义,以此来激发灵感和发现矛盾。

可惜,在当今中国的编码环境中,由于产品迭代周期极短,需求量大、代码量大,程序员根本没有时间在产品上线前实施小黄鸭调试。

而这样就引发了一个问题,代码没有经过小黄鸭调试,可能存在许多隐藏的Bug,而在程序员修复这些隐藏的Bugs的时候,可能会引入新的Bug…

更糟糕的是,如果修Bug的人不是当初写Bug的那个人,对整个代码逻辑和功能逻辑并不一定非常了解,那么有可能写出比原有Bug更加严重的Bug…

久而久之就形成了负反馈,产品功能越来越多,程序员越来越多,代码越写越糟糕,最终达到一种状态:能用就行

那么为什么?小黄鸭调试法在中国行不通的本质原因是什么?

1.“时间就是金钱,效率就是生命”

房价太高,结婚要买房,娃儿要读书,不急不行。上头急、组长急、产品急、开发急,大家都急,急急如厕令,厕所都得装个计时器,哪有时间跟你只鸭子折腾。

2.代码写得好,加班少,涨薪真的没你份儿

大部分开发者的目的都不是写出最优质的代码,而是赚最多的钱。为了钱而写代码,编程不过赚钱的工具,功能写得越多、钱就越多。

Bug多一点无所谓,毕竟老子写的功能比Bug多得多,那你小黄鸭调试法还有啥用,不是在拖累我赚钱的速度吗?

3.各种编程营销组织带坏编程风气

如果你是编程教育的细分领域,教量化投资、SaaS编程等技术含量高的课程也就算了。问题是一个教Python基础的课程起这样的标题是何居心?

总而言之,小黄鸭调试法的行不通,是因为中国程序员大量的时间(包括加班时间),花在了一些原本可以避免的Bug和可有可无的需求上。

从微观上看,是对KPI的焦虑、是对生活的担忧。

从宏观上看,是公司违法成本低、甚至根本不需要成本。

租下来的办公楼,多开几个小时灯就能多出一个新功能,成本近乎于零,没人用不亏,有人用则赚爆,何乐而不为?

但是许多人没想过的是,这样的生产成果,终究会化为垃圾,甚至对于整个产品而言单纯只是拖油瓶。真正长久不衰的功能,往往需要精心打造,而非急功近利。

在当今中国的编码环境中,我看不到有进行任何科学规划的团队,看不到有精心打造软件产品的公司。

就长期而言,我对中国的软件业持看空态度。为了急功近利的眼前效益,程序员生产的代码质量自然变得极差,就如同前面提到的负反馈效应,越往后,质量只会越来越差。

代码世界里的那些令人喷饭的注释

代码里的注释经常能让人嘀笑皆非,有些人喜欢在里边“搞事情”,另外有些人非常擅长写幽默搞笑的注释内容,还有些人无奈地在注释里告警后人…

下面就给大家展示一些国外程序员们写的注释。

注意:看的时候严禁喝水或进食。

1、亲爱的代码维护人员:

当您尝试优化这段代码但发现这是一个极端错误的决定的时候,请修改下面的计时器,以便警示后人。

总计浪费在这段代码的时间 = 16 小时

2、真的很有问题

3、谨以此代码献给我的妻子达琳,感谢她一直支持我,还有我三个孩子和一只狗。

4、神奇代码,请勿改动

5、喝醉啦,迟些再弄

6、你可能会认为你读得懂以下的代码。但是你不会懂的,相信我吧。

要是你尝试玩弄这段代码的话,你将会在无尽的通宵中不断地咒骂自己为什么会认为自己聪明到可以优化这段代码。

好了,现在请关闭这个文件去玩点别的吧。

7、程序员1(于 2002 年 6 月 7 日):在登陆界面临时加入一些调试代码

程序员2(于 2007 年 5 月 22 日):临你个屁啊

8、反正这个办法就修复了问题,我也不知道为什么会这样

9、要理解什么是递归的话,请参考本文件的底部

(在文件的底部)

要理解什么是递归的话,请参考本文件的顶部

10、狂插两下; //痛啊

11、亲爱的未来的我自己,请原谅我。

我有着难以表达的歉意。

12、我不对以下代码负责。

是他们逼我写的,是违背我意愿的。

13、疯了吗?欢迎来到斯巴达。

14、要是你能修正这个问题的话,我会送给你两个七十二岁的处女

15、没有注释留给你,难写的代码必定难读

16、IE 浏览器的 Hack (在这里先假设 IE 是浏览器)

17、有待修正。 修正什么啊?

18、要是再让我看到这种代码,我会带着枪来上班的

19、有只龙在这里……

20、在你阅读以下代码时,你要先搞懂为什么我在这样做。

我想读取一个根节点下面所有的子节点,以便控制根节点不会显示在选择框上。但那个傻逼的 DBA 找了一些某些傻逼的借口不让我用索引去读取这些数据,而要求我用他们傻逼的迭代器。所以有了以下代码。

21、当我写这段代码的时候,只有老天和我自己知道我在做什么。

现在,只剩老天知道了。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python制作国际空间站实时跟踪器

Open Notify是一个开源项目,旨在为NASA的一些出色数据提供简单的编程接口。

open-notify.org 的作者做了一些工作,以获取原始数据并将其转换为与太空和航天器有关的API

本文将通过这个接口,获取得到国际空间站的位置,并实时地绘制到地图上:

感谢cr0sis/Real-time-International-space-station-tracker

为了实现本文的目标,你得先安装ISS_Info:

pip install ISS-Info

下面分步骤讲解整套绘制流程

1.地图初始化

为了实时展示国际空间站的路径,需要使用turtle绘制曲线,因此可以创建一个turtle画布,将背景设为地球:

  
import ISS_Info
import turtle
import time
import json
import urllib.request

screen = turtle.Screen()
screen.setup(720,360)
screen.setworldcoordinates(-180,-90,180,90)
screen.bgpic("map.png")
screen.bgcolor("black")
screen.register_shape("isss.gif")
screen.title("Real time ISS tracker")

iss = turtle.Turtle()
iss.shape("isss.gif")

2.获取空间站的人数

如果能知道空间站上的宇航员人数,我们就能更加准确的跟踪国际空间站。幸运的是open-notify确实提供了这样的接口。

为了获取人数信息,我们必须向:
http://api.open-notify.org/astros.json
请求拿到数据,并将相应的宇航员名字写在左上角:

astronauts = turtle.Turtle()
astronauts.penup()
astronauts.color('black')
astronauts.goto(-178,86)
astronauts.hideturtle()
url = "http://api.open-notify.org/astros.json"
response = urllib.request.urlopen(url)
result = json.loads(response.read())
print("There are currently " + str(result["number"]) + " astronauts in space:")
print("")
astronauts.write("People in space: " + str(result["number"]), font=style)
astronauts.sety(astronauts.ycor() - 5)

people = result["people"]

for p in people:
    print(p["name"] + " on: " + p["craft"])
    astronauts.write(p["name"] + " on: " + p["craft"], font=style)
    astronauts.sety(astronauts.ycor() - 5)

3.绘制空间站位置

为了能够绘制空间站的实时位置,我们需要请求拿到空间站的位置信息。请求的接口是:
http://api.open-notify.org/iss-now.json

不过作者将其封装成了一个函数,我们直接调用 iss_current_loc 即可,循环获取国际空间站位置:

while True:  
    location = ISS_Info.iss_current_loc()
    lat = location['iss_position']['latitude']
    lon = location['iss_position']['longitude']
    print("Position: \n latitude: {}, longitude: {}".format(lat,lon))
    pos = iss.pos() 
    posx = iss.xcor()
    if iss.xcor() >= (179.1):           ### Stop drawing at the right edge of  
        iss.penup()                     ### the screen to avoid a 
        iss.goto(float(lon),float(lat)) ### horizontal wrap round line
        time.sleep(5)
    else:
      iss.goto(float(lon),float(lat))
      iss.pendown()
      time.sleep(5)

我们还可以标出自己目前所处的位置,以查看和国际空间站的距离及空间站经过你上空的时间点(UTC)。

# 深圳
lat = 112.5118928
lon = 23.8534489

prediction = turtle.Turtle()
prediction.penup()
prediction.color('yellow')
prediction.goto(lat, lon)
prediction.dot(5)
prediction.hideturtle()

url = 'http://api.open-notify.org/iss-pass.json?lat=' +str(lat-90) + '&lon=' + str(lon)
response = urllib.request.urlopen(url)
result = json.loads(response.read())

over = result ['response'][1]['risetime']

prediction.write(time.ctime(over), font=style) 

不过这里值得注意的是,iss-pass.json这个接口的纬度计算必须在-90到90之内,因此深圳的纬度需要减去90.

最终效果如下:

在Python实用宝典公众号后台回复“国际空间站”或者“ISS”即可获得本文完整源代码哦。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 导出word所有图片并转化格式

作者:叶庭云

日常工作中,你是否遇到过这样的场景,领导发来一份 Word 文档,要求你将文档中的图片存储到一个文件夹内,并且还要将图片都改成 .jpg 或者 .png,你会怎么办?

你是不是一边内心崩溃,一边开始一张张的 另存为

今天,我就教你两招省时省力的方法,不管文档中有几张甚到几百张图片,你都可以快速保存下来。

一、分析

图片在文档的应用已经是十分普遍的现象了,在Word文档中插入合适的图片无疑会让我们的文档变得更美观。

先来回想一下,我们平常是如何在Word中插入图片的?

  • 在本地电脑中事先存储好需要的图片素材,然后插入到Word中

其实,第二种方法有一个弊端在于图片只存在 Word 中,如果我们需要将它们保存到本地电脑中以供日后使用,最常用的方法是单击鼠标右键,选择 另存为图片,然后选择路径进行保存。

这种方法在只需要处理少数几张图片时还算适用,一旦图片数量增多,处理工作就会变得繁琐且容易出错。

那么,我们怎样可以将这些图片批量保存呢?

二、提取出 Word 文档里的图片

解决方法就是:更改文件格式。直接将 Word 文档的后缀名改成 “.rar” (“.zip”也是可以的)的压缩格式。打开压缩文件,点击【word】-【media】,文档中使用的图片就出现在这里,只需要选中解压出来即可。

用于测试的 Word 文档如下:

操作方法如下:

点击查看,选择详细信息,勾上文件扩展名。

直接将 Word 文档的后缀名改成 “.rar” (“.zip”也是可以的)的压缩格式。

打开压缩文件,点击【word】-【media】,文档中使用的图片就出现在这里,只需要选中解压出来即可。

三、利用 python 批量转换格式

# -*- coding: UTF-8 -*-
"""
@File    :test_01.py
@Author  :叶庭云
@CSDN    :https://yetingyun.blog.csdn.net/
"""
# 导入os模块
import os

# 不存在 jpg图片 这个文件夹  创建
if not os.path.exists('jpg图片'):
    os.mkdir('jpg图片')


path = r'.\jpg图片'
# 列出 media 文件夹下所有图片
files = os.listdir(r'.\media')

for item in files:
    # 拼接出media 文件夹下所有图片路径
    file_1 = '.\media' + '/' + item
    # 读取图片数据
    with open(file_1, 'rb') as f:
        con = f.read()
    # 重新写入  以 .jpg 格式 并保存到jog图片文件夹
    file_name = path + '/' + item.split('.')[0] + '.jpg'
    with open(file_name, 'wb') as f:
        f.write(con)

运行效果如下:

程序运行,嗖的一下,图片格式都转换成了 .jpg 并保存到新的文件夹里。

作者:叶庭云

CSDN:https://blog.csdn.net/fyfugoyfa

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 列表去重的4种方式及性能对比

​列表去重是Python中一种常见的处理方式,任何编程场景都可能会遇到需要列表去重的情况。

列表去重的方式有很多,本文将一一讲解他们,并进行性能的对比。

让我们先制造一些简单的数据,生成0到99的100万个随机数:

from random import randrange

DUPLICATES = [randrange(100) for _ in range(1000000)]

接下来尝试这4种去重方式中最简单最直观的一种方法:

1.新建一个数组,遍历原数组,如果值不在新数组里便加入到新数组中。

# 第一种方式
def easy_way():
    unique = []
    for element in DUPLICATES:
        if element not in unique:
            unique.append(element)
    return unique

进入ipython使用timeit计算其去重耗时:

%timeit easy_way()
# 1.16 s ± 137 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

平均耗时在1.16秒左右,但是在这个例子中我们使用了数组作为存储对象,实际上如果我们改成集合存储去重后的结果,性能会快不少:

def easy_way():
    unique = set()
    for element in DUPLICATES:
        if element not in unique:
            unique.add(element)
    return unique
%timeit easy_way()
# 48.4 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

平均耗时在48毫秒左右,改善明显,这是因为集合和数组的内在数据结构完全不同,集合使用了哈希表,因此速度会比列表快许多,但缺点在于无序。

接下来看看第2种方式:

2.直接对数组进行集合转化,然后再转回数组:

# 第二种去重方式
def fast_way()
    return list(set(DUPLICATES))

耗时:

%timeit fast_way()
# 14.2 ms ± 1.73 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

平均耗时14毫秒,这种去重方式是最快的,但正如前面所说,集合是无序的,将数组转为集合后再转为列表,就失去了原有列表的顺序。

如果现在有保留原数组顺序的需要,那么这个方式是不可取的,怎么办呢?

3.保留原有数组顺序的去重

使用dict.fromkeys()函数,可以保留原有数组的顺序并去重:

def save_order():
    return list(dict.fromkeys(DUPLICATES))

当然,它会比单纯用集合进行去重的方式耗时稍微久一点:

%timeit save_order()
# 39.5 ms ± 8.66 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

平均耗时在39.5毫秒,我认为这是可以接受的耗时,毕竟保留了原数组的顺序。

但是,dict.fromkeys()仅在Python3.6及以上才支持。

如果你是Python3.6以下的版本,那么可能要考虑第四种方式了。

4. Python3.6以下的列表保留顺序去重

在Python3.6以下,其实也存在fromkeys函数,只不过它由collections提供:

from collections import OrderedDict
def save_order_below_py36():
    return list(OrderedDict.fromkeys(DUPLICATES))

耗时:

%timeit save_order_below_py36()
# 71.8 ms ± 16.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

平均耗时在72毫秒左右,比 Python3.6 的内置dict.fromkeys()慢一些,这是因为OrderedDict是用纯Python实现的。

我们的文章到此就结束啦,如果你喜欢今天的 Python 教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!

给作者打赏,选择打赏金额
¥1¥5¥10¥20¥50¥100¥200 自定义

​Python实用宝典 ( pythondict.com )
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python MySQL与Influxdb对比及迁移方案

最近遇到一个新的应用场景:将MySQL存放的时序数据迁移到influxDB中。

这么做的好处在于:

1.Influxdb 读写速度更快。

写数据对比

读数据对比

2.在磁盘占用率上,Influxdb更低。

3.此外,Influxdb的数据可以使用Chronograf进行实时预览

如果以前是将时序数据存放在MySQL,现在为了获取更好的性能和使用更优的可视化工具,我们需要将数据从MySQL迁移到Influxdb中。

这看起来是一个常见场景,经过我一番查阅,发现了 GreatLakesEnergy/Mysql-to-influxdb 这个项目。

可惜的是,作者是基于Python2进行开发的,而且用了几个非常难搭建的模块。想在Python3中重新使用这个项目比较困难,因此我对它进行了改造,改造后的代码如下:

https://github.com/Ckend/Mysql-to-influxdb

如果你有这样的迁移需求,可以继续看下面的详细教程。

1.准备

开始之前,你要确保Python和pip已经成功安装在电脑上噢,如果没有,请访问这篇文章:超详细Python安装指南 进行安装。如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda

Windows环境下打开Cmd(开始—运行—CMD),苹果系统环境下请打开Terminal(command+空格输入Terminal),准备开始输入命令安装依赖。

当然,我更推荐大家用VSCode编辑器,把本文代码Copy下来,在编辑器下方的终端运行命令安装依赖模块,多舒服的一件事啊:Python 编程的最好搭档—VSCode 详细指南。

下载或Git Clone我修改好的代码:
https://github.com/Ckend/Mysql-to-influxdb

进入该目录后,输入以下命令安装依赖:

pip install -r requirements.txt

看到 Successfully installed xxx 则说明安装成功。

2.迁移配置

在迁移开始前,请在你需要迁移的表里加一个字段 transfered,这个字段用于检测某条数据是否被迁移,默认设为0。一旦迁移完成,这个字段会被设为1.

此外,你需要找到你表里的时间序列字段(time)和分类字段(tag)。

分类字段可能比较难理解,比如说你有一张表记录了每支股票每天的开盘价,那么股票id字段便可理解为一个tag,即下面配置中的siteid_field.

在解压后的目录里新建一个settings.ini, 配置以下信息:

[mysql]
host : mysql host # (本地为127.0.0.1)
port : mysql 端口号 # Default is3306
username : 用户名
password : 密码
db : 数据库
table : 要迁移的表
check_field : 检测字段,默认为0,如果迁移完成,该字段会被设为1
time_field : 时间字段
siteid_field : 分类字段(tag)


[influx]
host : influxdb host # (本地为127.0.0.1)
port : 端口号 # Default:8086
username : 用户名
password : 密码
db : 要迁移进入的数据库

[server]
interval : 5 

配置完上述信息后,执行命令即可开始迁移:

python mysql2influx.py -d -c settings.ini -s

3.迁移是否完成

如何检测迁移任务是否完成,还记得我们刚新增了一个字段 transfered 用于检测某条数据是否被迁移吗?

你只需要在mysql中输入以下sql查询是否还有未被迁移的数据即可:

SELECT count(1) FROM your_table where transfered = 0;

若不为0则说明还有数据未被迁移成功。

不过值得注意的是,迁移脚本里是先进行数据迁移,再回来修改transfered的值。

如果你的数据量非常大,更新MySQL数据有可能会耗时极长,因此查询transfered数量的结果有可能不正确。这点需要特别关注。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

healthchecks, 基于Django监控Cron任务的神器

在运维服务器的时候经常会用到一些Crontab任务。

当你的Crontab中的任务数超过10个的时候,你会发现这些任务管理起来非常困难。

尤其是当这些Cron任务执行失败的时候,比如 Python 实用宝典网 每个月初都会执行一次https证书刷新,有一次协议更新之后,我的脚本失效了三个月,导致证书过期时网站宕机了一天,直到我发现并修复了这个问题。

这就是Crontab任务的一个劣势:没有方便的通知功能。

不过,现在有一个非常方便的开源Django项目能在这些Crontab失效的时候通知你,它就是healthchecks.

它通过一个回调接口判断你的Crontab任务有没有顺利执行。

比如说你有一个python脚本定时执行,healthchecks给定的回调URL是:

http://localhost:8000/ping/880cb4d2

在配置Crontab脚本的时候,就需要这么写:

8 6 * * * python /home/user/test.py && curl -fsS -m 10 --retry 5 -o /dev/null http://localhost:8000/ping/880cb4d2

如果未按时调用回调接口,healthchecks将会通过邮件等通知方式告警。

那么这个“未按时”能否设定宽限呢?比如我有个任务要跑1个小时左右,那么这个任务应该是预计在一个半小时内调用(Ping)回调接口,超过一个半小时如果没有调用回调接口则告警。答案是肯定的。

上图中Period指的是两次Ping之间的时间间隔。下方Grace表示“宽限期”,自从上次Ping以来的时间已超过Period+Grace则会发送告警通知。

如果你用不习惯这种可视化的选择器,它还提供了Crontab表达式给你定义Period和Grace:

真乃神器啊!支持的通知方式如下:

国内用户可能一般只会用到Email和Teams,高级点的用户可能会用到IFTTT的Webhooks和普罗米修斯。总之,按你的爱好来就行。

本地开发

下面教大家如何在本地搭建这个项目:

1. 下载项目

https://github.com/healthchecks/healthchecks

如果你访问不了github,可在【Python 实用宝典】公众号后台回复 healthchecks 下载完整源代码

2.创建虚拟环境

推荐使用Python 3.6+,如果你有conda,那就非常方便了,创建healthchecks虚拟环境:

conda create -n healthchecks python=3.6
activate healthchecks

如果你没有conda,你需要先安装Python3.6,然后使用pip安装virtualenv,在终端输入以下命令创建healthchecks虚拟环境

python3 -m venv healthchecks
source healthchecks/bin/activate

不同系统中命令可能不太一样,遇到问题多利用搜索引擎查询就好了。

3.安装依赖

进入到上述创建好的虚拟环境后,cd进入项目根目录,输入以下命令安装依赖:

pip install -r requirements.txt

4.数据库配置(可选)

该项目默认使用SQLite,这意味着你不需要特殊配置也可照常运转。

如果你需要配置MySQL或PostgreSQL,请阅读hc/local_settings.py.example文件进行配置即可。

5.数据表迁移

Django项目当然少不了这个环节,虚拟环境下,在根目录里运行以下命令进行数据表的迁移:

python manage.py migrate

当然,还要创建超管用户:

python manage.py createsuperuser

6.运行项目

大功告成,输入以下命令即可运行项目:

python manage.py runserver

点击右上角login in登录到超管用户就可以开始使用了。

如果你需要对这个项目进行大规模的改动,建议使用Pycharm作为编程工具,因为使用Pycharm来写Django实在是太爽了,详细可以参考这篇文章:《Pycharm+Django 安装及配置指南》

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应红字验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

关于Python3.9,你不可不知的4个新特性

1.词典联合运算符

这是我最喜欢的功能之一,语法非常优美。

在Python3.9,如果你有两个词典,现在可以用这些运算符进行合并和更新。

合并运算符 “|”:

还有update运算符|=,它会更新原始字典:

a = {1: 'a', 2: 'b', 3: 'c'}
b = {4: 'd', 5: 'e'}
a |= b
print(a)
{1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e'}

如果我们的词典共享一个key,那么将使用第二个词典中的value:

a = {1: 'a', 2: 'b', 3: 'c', 6: 'in both'}
b = {4: 'd', 5: 'e', 6: 'but different'}
print(a | b)
{1: 'a', 2: 'b', 3: 'c', 6: 'but different', 4: 'd', 5: 'e'}

使用可迭代对象进行字典更新

|=操作符的另一个很酷的特性是能够使用可迭代对象(例如列表或生成器)使用新的键值对更新字典:

a = {'a': 'one', 'b': 'two'}
b = ((i, i**2) for i in range(3))
a |= b
print(a)
{'a': 'one', 'b': 'two', 0: 0, 1: 1, 2: 4}

当然,如果你用|这样做,则会得到TypeError,因为它只能用于dict类型之间的联合。

2.字符串方法

removeprefix()和removesuffix()

str.removeprefix(substring: string) 是一个方法,接收一个substring参数,顾名思义,它将删除字符串对应的substring后缀,如果没有对应的后缀,返回原字符串。

str.removesuffix(substring: string) 是一个方法,接收一个substring参数,它将删除字符串的对应substring前缀,如果没有对应的前缀,返回原字符串。

当然,两个函数执行你可以通过使用string[len(prefix):]前缀和string[:-len(suffix)]后缀来实现。

这些是非常简单的操作,因此也是非常简单的功能,考虑到你可能经常执行这些操作,Python3.9 提供的这两个内置函数应该能让你非常爽。

3.新的数学函数

Python 3.9 的数学模块进行了不少的优化并添加了许多新功能。

比如以前gcd计算最大公因数的函数只能应用于2个数字,这就很蛋疼,我们必须使用 math.gcd(80, math.gcd(64, 152))来处理大于2个数字的情况。

现在 gcd 允许计算任意数量的数字。

import math

# Greatest common divisor
math.gcd(80, 64, 152)
# 8

Math模块中,第一个新增的功能是:

# 最小公倍数
math.lcm(4, 8, 5)
# 40

用于计算最小公倍数:math.lcm,与gcd一样,它允许可变数量的参数。

4.新解析器

这一个更改你可能看不见、摸不着,但它可能改变Python的未来。

以前Python使用 LL(1) 解析器,现在Python开始使用 PEG 解析器,官方认为,这个更改会使得他们更加方便地构建新功能。

因此,请期待Python 3.10,Python团队或许能给我们带来更多的惊喜!

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 最好用的8个VS Code扩展

1. Python extension for Visual Studio Code

这个扩展是由微软官方提供的,支持但不仅限于以下功能:

  • 通过Pylint或Flake8支持代码检查
  • 在VS Code编辑器中调试代码
  • IntelliSense支持自动完成,代码导航和格式化。
  • 支持Jupyter Notebook,Pytest和Unittest
  • 在编辑器中轻松切换Python环境

2.Python Preview

这个插件很牛皮,能够实时可视化你的代码结果。

不仅如此,还能为VSCode切换各种主题皮肤。

3.Sort lines

这个扩展很有意思,可以给你按字母大小排序(升序、降序),也可以进行排序+去重。而且还能将所有文本打乱顺序。

做短文本分类的训练,清洗数据集的时候,这个工具大有用处。

4.Git Graph

这玩意可是Git神器,堪比Pycharm内的Git管理器。

通过这个扩展,可以清楚地看见当前分支的commit记录和变化,可以通过按钮的方式轻易地创建、切换分支、cherry pick、merge等操作。

对比分支、查看未提交的修改……还有许多可定制的扩展设置。

5.Python Snippets

很多时候,我们用到的代码片段都是类似的,比如for循环、try/catch等等,现在有了这个工具,我们只需要输入命令生成代码片段,然后再进行微调,就能完成功能的开发。

此外,有些时候我们可能会忘记某些内置函数的用法,这个工具也能给你提供示例代码做参考,而不用你再去搜索引擎搜索示例,实在非常方便。

6.Better Comments

这是一个让你能更好地编写注释的工具,它能根据关键词用不同的颜色高亮代码片段。支持以下类型的高亮:

1. 感叹号 “!” 代码警告。
2. 问号“?”代表存留疑问。
3. TODO 代码未来将要进行的操作。
4. @param 参数

此外,它还支持在设置中自定义需要高亮句子的首部关键词。

7.autoDocstring

这个扩展我应该已经推荐了好多次,能够自动生成函数的注释格式,通过tab键快速切换填充块编写相应的注释。

8.Python Indent

你有没有觉得VSCode里对Python的自动缩进有点不准确?甚至可以用“丑”来形容。每次我都喜欢强行矫正VSCode给我做的自动缩进。

经过一番查阅,我终于找到了能纠正VSCode缩进错误的扩展,它就是Python Indent,看看下面的示例,相信你也会安装它。

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典

Python 简单实用的日志装饰器

在写代码的时候,往往会漏掉日志这个关键因素,导致功能在使用的时候出错却无法溯源。

其实,只需要写一个非常简单的日志装饰器,我们就能大大提升排查问题的效率。

1.简陋版

写一个装饰器非常简单,因为本质上装饰器就是一个返回函数的“高阶”函数而已:

1.函数作为参数传递进装饰器。
2.装饰器内定义一个函数,处理作为参数传递进来的函数。
3.返回这个装饰器内定义的函数

import datetime


def log(func):
    """
    日志装饰器,简单记录函数的日志

    Args:
        func (function): 函数
    """
    def inner(*args):
        timestamp = str(datetime.datetime.now()).split(".")[0]
        res = func(*args)
        print(f"[{timestamp}] ({func.__name__}) {args} -> {res}")
        return res
    return inner

用一下试试看:

@log
def pluser(a, b):
    return a + b

pluser(1, 2)

效果如下:

虽然这样可以实现我们所需要的功能,但其实有很大的优化空间。

2.普通版

第一版代码中有一个显而易见的问题,装饰器内定义的处理函数不支持kwargs,而在装饰器中支持kwargs仅仅是举手之劳而已。

第二个问题是,生成时间戳的时候采用字符串截取的形式,这种形式过于粗暴。其实可以使用strftime做字符串转换。

修改如下:

import datetime


def log(func):
    """
    日志装饰器,简单记录函数的日志

    Args:
        func (function): 函数
    """
    def inner(*args, **kwargs):
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        res = func(*args, **kwargs)
        print(f"[{timestamp}] ({func.__name__}) {args} -> {res}")
        return res
    return inner

似乎优化地差不多了,不过依然存在改进空间。

3.优化版

在前两版代码中,我们使用print进行日志输出,其实这种处理日志的方式并不标准。

使用logging模块控制日志输出是一个更好地选择。

为了使用logging模块记录日志,我们需要先配置好logging相关的选项。

1.首先,生成一个日志记录器,并配置日志等级:

import logging

# 获取日志记录器,配置日志等级
logger = logging.getLogger(__name__)
logger.setLevel('DEBUG')

2.配置日志格式、增加handler控制输出流:

# 默认日志格式
formatter = logging.Formatter("%(asctime)s - [%(levelname)s] - %(message)s")
# 输出到控制台的handler
chlr = logging.StreamHandler()
# 配置默认日志格式
chlr.setFormatter(formatter)

此处可以设置handler所需要处理的日志等级,没有设置则默认使用logger自身的Level,即DEBUG等级。

3.最后,将此handler加入到日志记录器内:

# 日志记录器增加此handler
logger.addHandler(chlr)

logging 完整配置如下:

import logging

# 获取日志记录器,配置日志等级
logger = logging.getLogger(__name__)
logger.setLevel('DEBUG')

# 默认日志格式
formatter = logging.Formatter("%(asctime)s - [%(levelname)s] - %(message)s")
# 输出到控制台的handler
chlr = logging.StreamHandler()
# 配置默认日志格式
chlr.setFormatter(formatter)

# 日志记录器增加此handler
logger.addHandler(chlr)

使用的时候非常简单,就是把print换成logger.debug即可:

def log(func):
    """
    日志装饰器,简单记录函数的日志

    Args:
        func (function): 函数
    """
    def inner(*args, **kwargs):
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        res = func(*args, **kwargs)
        logger.debug(f"func: {func.__name__} {args} -> {res}")
        return res
    return inner

效果如下:

这样,一个比较完善的日志装饰器就完成了。

附常用的日志等级配置:

我们的文章到此就结束啦,如果你喜欢今天的Python 实战教程,请持续关注Python实用宝典。

有任何问题,可以在公众号后台回复:加群,回答相应验证信息,进入互助群询问。

原创不易,希望你能在下面点个赞和在看支持我继续创作,谢谢!


​Python实用宝典 (pythondict.com)
不只是一个宝典
欢迎关注公众号:Python实用宝典