Tenacity——Exception Retry 从此无比简单
Python 装饰器装饰类中的方法这篇文章,使用了装饰器来捕获代码异常。这种方式可以让代码变得更加简洁和Pythonic。
在写代码的过程中,处理异常并重试是一个非常常见的需求。但是如何把捕获异常并重试写得简洁高效,这就是一个技术活了。
Python 装饰器装饰类中的方法这篇文章,使用了装饰器来捕获代码异常。这种方式可以让代码变得更加简洁和Pythonic。
在写代码的过程中,处理异常并重试是一个非常常见的需求。但是如何把捕获异常并重试写得简洁高效,这就是一个技术活了。
Python作为一门动态语言,其变量的类型可以自由变化。这个特性提高了代码的开发效率,却也增加了阅读代码和维护代码的难度。
目前在中文网上能搜索到的绝大部分关于装饰器的教程,都在讲如何装饰一个普通的函数。本文介绍如何使用Python的装饰器装饰一个类的方法,同时在装饰器函数中调用类里面的其他方法。本文以捕获一个方法的异常为例来进行说明。
我们都有这样的生活体验
我清清楚楚的记得半个小时前还用手机打了电话,怎么现在手机找不到了?这半个小时我一直在房间里,难道手机还会长翅膀飞走了吗?
如果你有两个手机而且你的手机没有静音,那可以用另一个手机给不见的手机打一个电话。可是如果你的手机静音了呢?有人说可以等到晚上打电话,看家里哪里在发光。那么如果你的手机不仅静音,还屏幕朝下呢?
看了这篇文章以后,只要你的手机在家里,只要手机开机,只要手机可以上网,那么你就可以在30秒以内找到它,不论它是否静音。
在对安卓手机设计自动化测试用例的时候,判断一个测试场景是否可以自动化的依据在于其是否需要人的参与。对于wifi能否自动打开关闭,短信能否自动收发这样的场景,不需要人参与就可以通过程序来判断,因此对Wifi与短信这样的测试,可以通过程序来实现自动化测试。但是另外还有一些测试场景,需要人的眼睛来看,这种场景要实现自动化就比较困难。
闹钟已经成了我们生活中必不可少的东西。如果全球每个国家的当地时间明天早上,所有的闹钟突然都不响了,不知道会发生什么样的混乱。
然而我们要讨论另外一种情况,闹钟每天定时响起来,真的是最好的情况吗?你有过醒来以后等闹钟的经历吗?如果你有时候在闹钟响之前就起来了,那么你会不会希望闹钟能知道你已经起来了?如果你提前醒了,那么闹钟就不响,只有你一直睡着的时候,闹钟才会按时响起来。
virtualenv 可以虚拟出一个独立的Python环境,在这个环境中安装的第三方库不会对系统中的Python产生影响。作为一个系统洁癖,我的系统中的Python环境只安装最主要的第三方库,我在开发Python项目的时候一般使用virtualenv生成的独立环境来安装项目需要的第三方库。但是如果同时使用了zsh的alias 和virtualenv,有可能就会导致virtualenv下面的python不能使用第三方库。
一般我们会使用以下两种方式之一来运行Python:
1 | python xxx.py |
或者在代码的第一行加上python的路径:
1 | #! /usr/local/bin/python |
这两种方式,使用的是系统中的Python来解释代码。
如果电脑上安装了Python2 和Python3, 那么想运行Python3写的代码的时候,我们可以使用以下方法来运行:
1 | python3 xxx.py |
但是由于有人不想写数字3, 于是就使用了zsh的alias功能,在~/.zshrc
文件中,添加了一行:
1 | alias python=/usr/local/bin/python3 |
在这种情况下,使用:
1 | python xxx.py |
就可以通过Python3来解析代码了。这种方式使用系统中的Python没有问题,但是如果在virtualenv下面可就惨了。
我们创建一个虚拟环境并激活,安装Python的requests库,再启动python并导入requests库, 并其代码流程如下:
1 | $ virtualenv --python=python3 venv |
如果我们设置了上面的alias,那么你一定会得到下面的结果:
1 | Traceback (most recent call last): |
于是你打开venv/lib/python3.5/site-packages
却发现requests安安静静的躺在里面。于是你百思不得其解,明明pip 是把requests安装在虚拟环境下面的,为什么Python不能正常导入呢?于是你再执行以下代码查看环境变量:
1 | import sys |
你看到的可能是下面的结果:
1 | ['', |
全部是系统下面Python的路径,和你的virtualenv 没有一点点的关系。
然后你退出Python,在虚拟环境下面打印PATH,你却发现:
1 | $ echo $PATH |
你的virtualenv环境好好的躺在你的环境变量的最前面。于是你快要疯掉了,到底是什么鬼,怎么会发生如此灵异的事件?系统不应该是首先找环境变量第一个位置下面的Python吗?怎么会跳过虚拟环境,去打开了系统中的Python呢?应该直接打开虚拟环境下面的Python才对啊!
问题的根源就在你的alias上面。
zsh 的alias的优先级是非常高的,它会首先替换为等号后面的内容,然后再执行。那么即使在虚拟环境下,在终端输入python
并回车以后,实际执行的代码是:
1 | /usr/local/bin/python3 |
你使用了绝对路径打开了系统中的Python3。
而由于你没有对pip 设定alias, 因此你使用pip 安装requests的时候,它调用的是虚拟环境下面的pip,所以requests会正确安装在虚拟环境下面。
解决办法有两个:
~/.zshrc
中删除下面的代码,并重启终端:1 | alias python=/usr/local/bin/python3 |
~/.zshrc
中的:1 | alias python=/usr/local/bin/python3 |
修改为
1 | alias python=python3 |
本文首发地址: http://kingname.info/2016/06/27/alias-vs-virtualenv/转载请注明出处。
我曾经是一个对Java非常反感的人,因为Java的语法非常啰嗦。而用惯了动态类型的Python再使用静态类型的Java就会觉得多出了很多的工作量。
因为工作的关系,我开始使用Java来做项目。在这个过程中,我发现Java在某些方面确实和Python不一样。
有一句话说的好:
语言决定了世界观。
当我Java用的越来越多的时候,我渐渐发现我不是那么讨厌它了。
今天我要讲的,是我从Java里面学到的,一个被称为JavaBeans的东西。
In computing based on the Java Platform, JavaBeans are classes that encapsulate many objects into a single object (the bean). They are serializable, have a zero-argument constructor, and allow access to properties using getter and setter methods.
一句话概括起来: 当一些信息需要使用类似于字典套字典套列表这种很深的结构来储存的时候,请改用类来储存。
在Python里面,我以前会写这样的代码:
1 | person_list = [{ |
由于Python动态类型的特点,字典里面的value经常是包含了各种类型,有时候,字典里面包含了字典,里面的字典里面还有列表,这个内部字典里面的列表里面又包含了字典……
当我刚刚开始写Java代码的时候,也会保留了这个坏习惯,于是我定义的一个变量类似于这样:
1 | public Map<String, List<Map<String, Map<String, Object>>>> info = ..... |
并且由于Java是静态类型语言,有时候Map里面的Value类型还不一致,需要使用Object来代替,等要使用的时候再做类型转换。
对于这样的写法,真可谓是写代码一时爽,调试代码火葬场。我过几天读自己的代码,自己都不知道这个字典里面有哪些内容,也不知道它们有哪些类型,必须到定义的地方去看。
我的Mentor看了我的Java代码以后,让我去用一下JavaBeans,于是我的世界瞬间就简洁多了。后来我将JavaBeans的思想用到Python中,果然Python代码也变得好看多了。
使用上面person_list这个复杂的结构为例,我用JavaBeans的思想,在Python里面重构它:
1 | class Person(object): |
1 | class Detail(object): |
从这里可以看到,我把字典变成了类。于是,当我想保存我自己的信息和小明的时候,我就可以这样写:
1 | detail_kingname = Detail(address='xxx', work='engineer', salary=10000), |
这样写,虽然说代码量确实翻了不止一倍,但是当我们后期维护的时候或者遇到问题来调试代码,我们就能发现这样写的好处。
举一个很简单的例子,在写了代码一年以后,我已经对这段代码没有多少印象了,现在我得到了变量person_list
, 我想查看每个人的工资。首先,由于Person
和Detail
这两个类是已经定义好的,分别放在Person.py
和Detail.py
两个文件中,于是我点开它们,就知道,原来工资是保存在Detail
这个类中的,关键词是salary
, 而Detail
又是保存在Person
中的,关键词是detail
。
所以要查看每个人的工资,我可以这样写:
1 | for person in person_list: |
但是如果我使用的是最上面字典的那种方式,那么情况就没有这么简单了。因为我不知道工资是在这个字典的什么地方。于是我首先要找到person_list
是在哪里初始化的,然后看它里面有什么。在这个例子中,我是一次性把整个列表字典初始化完成的,直接找到列表初始化的地方就知道,原来这个person_list
下面有很多个字典,字典有一个key 叫detail
,这个detail
的value本身又是一个字典,它下面的keysalary
保存了工资的信息。这似乎还比较方便。但是如果字典里面的信息不是一次性初始化完成的呢?万一detail
这一个key是后面再加的呢?于是又要去找detail
初始化的地方……
第二个好处,使用Beans的时候,每个关键字是定义好的,salary
就只能叫做salary
,如果写成了salarv
, 集成开发环境会立刻告诉你,Detail
没有salarv
这个属性。但是如果使用字典的方式,我在给字典赋值的时候,一不小心:
1 | detail['salarv'] = 0.5 |
由于这里的salarv
是字符串,所以集成开发环境是不会报错的,只有等你运行的时候,尝试读取detail['salary']
里面的值,Python会告诉你:
1 | Traceback (most recent call last): |
将JavaBeans的思想用在Python中,避免字典套字典这种深层嵌套的情况,对于一些需要反复使用的字典,使用类来表示。这样做,别人读代码的时候会更加的容易,自己开发的时候,也会避免出现问题。
本文首发于:http://kingname.info/2016/06/19/bean-in-python/ 转载请注明出处。
MarkdownPicPicker 是基于Python3 的Markdown写作辅助工具, 作者是我。它能将剪贴板中的图片上传到网络图床中,并将markdown格式的图片链接()复制到剪贴板中。
项目地址:https://github.com/kingname/MarkdownPicPicker
第0.2版有以下功能:
配置文件保存在config.ini
文件中,其意义分别如下:
1 | [basic] |
其中access_key
和 secret_key
可以在七牛云的控制面板中看到,如图:
container_name
为下图所示内容:
short_key_one
和 short_key_two
为快捷键的两个按键,默认为左侧windows徽标键(Lwin
) 和 字母 C
。
将程序配置好以后运行,创建一个批处理文件markdownpicpicker.bat, 其内容如下:
1 | @echo off |
路径请根据实际情况修改。
由于我使用了virtualenv, 所以需要在批处理中进入virtualenv的环境才能正常运行程序。对于将requirements.txt里面包含的库直接安装在全局的情况,bat 可以简化:
1 | @echo off |
不论哪种方式,均不要在任何相关的路径上出现中文,否则会导致不可预知的问题。
然后右键选择批处理,发送到桌面快捷方式。接着右键快捷方式,属性,在“快捷键” 这一栏按下字母Q,它将自动填充为 Ctrl + Alt + Q
, 确定。
只需要首先使用QQ截图或者其他截图工具将图片保存到剪贴板中,然后按下设定好的快捷键即可。Markdown格式的图片链接就已经保存到剪贴板中了。在需要使用的地方直接粘贴。
不过这样设定的快捷键,按下以后会有大概一秒钟的延迟。推荐大家使用AutoHotKey来触发这个bat文件。
本程序使用了Pillow库中的 ImageGrab.grabclipboard()
方法来获取剪贴板中的数据,但是由于这个方法有一个bug, 导致可能会爆以下错误:
1 | Unsupported BMP bitfields layout |
这个问题从Pillow 2.8.0开始,一直到3.2.0都没有被官方解决。目前有一个间接的解决办法。
请打开Python安装目录下的\Lib\site-packages\PIL\BmpImagePlugin.py文件,将以下代码:
1 | if file_info['bits'] in SUPPORTED: |
修改为:
1 | if file_info['bits'] in SUPPORTED: |
就能解决本问题。
本程序还有一个功能是全局监听键盘,通过特殊的快捷键组合就可以直接触发读取图片上传图片的操作。但是由于这个功能使用到了pyHook这个库。但是这个库在设计上存在缺陷,如果当前窗体的标题包含Unicode字符时,会导致Python崩溃。因此这个功能默认不启动。
如果不清楚某个键盘按键对应的字符串是什么样子的,可以运行QueryKey.py这个文件,运行以后按下某个键,控制台上就会显示相应的信息。其中Key
就是可以设置到SHORT_KEY_ONE
和SHORT_KEY_TWO
的内容。如图为按下键盘左Shift键以后显示的信息。
本文首发地址-> http://kingname.info/2016/06/04/markdownPicPicker/ 转载请注明出处