熟悉和应用 Python 的装饰器

Python 在语法上除了冒号与强制缩进外其实也没有太多令人眼前一亮的东西,倒是它的装饰器(Decorator) 值得玩味。初读 《THE Quick Python Book》一书,关于 Decorator(装饰器) 这一节匆匆而过,只是觉得它像 Java 注解一样的东西,没太细究。后来慢慢看到还是不少地方在用装饰器,如 Python 的属性 @property, @name_attr.setter, 还有 Flask 中用于定义路由的 @app.route('/') 等。

因此还是有必要花些功夫去更深入的了解 Python 的装饰器,从目前对装饰器的理解,它兼具 Java 的注解与代理的功能,而且比 Java 中自定义注解的处理与动态代理的实现要简单的多,甚至不需要特别牵涉到到面向方面的编程这么一个专门的概念。Python 的装饰器并非指的设计模式中的装饰器模式,Python 的装饰器主要还是关于代理,或叫方法拦截,切面的。

装饰器简单说来就是一个高阶函数,即一个函数作为另一个函数的参数,比如说函数 A 作为函数 B 的参数,然后函数 B 的实现有能力决定实际调用 A 的前后作点手脚,甚至压根不调用 A。由此,装饰器完全可以实现面向方面的 @Before, @After, @Around, @AfterReturning, @AfterThrowing 所有语义。

Python 中的函数像 JavaScript 的一样是头等对象(first-class objects),所以函数本身可以作为参数任意传递,一个函数也可以返回另一个函数。Python 的函数中还允许用相同的 def func():... 语法定义内部函数。 阅读全文 >>

类别: Python. 标签: . 阅读(35). 评论(0) »

Python 包管理及虚拟环境的应用(二)

前两篇分别学习了 Python 如何进行依赖的管理,以及结合虚拟环境来使用 pip 进行依赖管理。而有人觉得把 virtualenv 与 pip 分开来操作太麻烦了,而且 requirements.txt 描述依赖的方式十分笨拙,所以在前两者之上创建了 pipenv, 也谈不上重新发明了轮子吧。

3. Pipenv: 新一代依赖管理与虚拟环境

倘若不是经由 virtualenv, venv 而来到 pipenv,没有对比也就无法体会到 pipenv 的妙处的。pipenv 在总结了 virtualenv/venv 的缺点之后由 Kenneth Reitz 于 2017 年 1 月发布的新型 Python 依赖管理器。

  1. 它不再需要单独用 virtualenv 和 pip,只要一条命令 pipenv 完成所有的事
  2. 不用手动管理 requirements.txt 文件,而是由  pipenv 自动维护 Pipfile 和 Pipfile.lock 文件
  3. 自动创建虚拟环境,并且虚拟环境与项目文件分离
  4. 更详尽的依赖图(例如 pipenv graph),像 mvn dependency:tree 那样显示依赖树
  5. 控制台下输出颜色更丰富

阅读全文 >>

类别: Python. 标签: , , , . 阅读(20). 评论(0) »

Python 包管理及虚拟环境的应用(二)

原本想在一篇之内覆盖到 Python 的包管理以及各类虚拟环境的应用,没想根本就是一发不可收拾,恐怕两篇都完不了,所以也要进行重构。这里只涉及到 Python 的虚拟环境 venv 和 virtualenv,至于标题的话,也不想再改了,只作一,二,三编号,必要时仍能连缀成长篇。最后一篇将单独学习 pipenv 的应用。

以下序号也是承接上一篇 Python 包管理及虚拟环境的应用(一)

2. Python 虚拟环境

关于创建 Python 项目的虚拟环境,有三个工具可用, venv, virtualenv, 以及后面单独要学到的 pipenv

  1. venv , 即 python3 -m venv 命令,Python 3.3 及新版本自带了,为 Python 3.4 及以后的版本创建的虚拟环境会有 pip 和 setuptools 命令
  2. virtualenv 需要单独安装,但是它支持 Python 2.7 和  Python 3.3+, 创建的虚拟环境中带有 pip, setuptools 和 wheel 命令
  3. 另外,pyvenv 脚本也可用来创建 Python 虚拟环境,不过它自 Python 3.6 不推荐使用,建议用 python3 -m venv 命令

阅读全文 >>

类别: Python. 标签: , , , . 阅读(12). 评论(0) »

Python 包管理及虚拟环境的应用(一)

话说 Python 的哲学之一就是: 用一种方法,最好是只有一种方法来做一件事。可以用 python -m this 或在  python 交互界面下 import this 看到 The Zen of Python 有一句:

There should be one-- and preferably only one --obvious way to do it.

然而 Python 在关于包管理(依赖管理)一事上却让人面临了众多的选择。

即使是 Java 日趋发展庞大的今天,包管理工具也没有如今的 Python 复杂,Java 的包管理工具经历了手工下载 jar 包,Maven, Ant+Ivy, Gradle, sbt, 但主流的也就 Maven 和 Gradle, 并且它们兼具项目构建的功能。

这里有一个 Python 包管理工具变迁的视频: Kenneth Reitz - Pipenv: The Future of Python Dependency Management - PyCon 2018。再更早的 Python 依赖管理的方式不说,视频中提到了 阅读全文 >>

类别: Python. 标签: , , , . 阅读(19). 评论(0) »

Python 中的 urlencode 和 urldecode 操作

Web  编程中由于需要用 Form 或 URL 来传递参数,所以必然会有 urlencode 和 urldecode 的操作,Python Web 也不例外。Python 对 URL 的编解码操作提供了 urllib 模块,下面例子中所使用的 Python 版本是  3.6.7,不同的 Python 版本可能略有差异。

简面言之本文就是关于以下六个函数的使用,更多关于 urllib 的用法请自行进一步研究。

from urllib.parse import urlencode, parse_ql, quote, quote_plus, unquote, unquote_plus

为什么两个 urlencode 和  urldecode 操作会涉及到六个函数的应用呢,分别来讲述

1. urlencode

Python 的  urllib 直接提供了  urlencode 函数,它的操作数是一个字典 阅读全文 >>

类别: Python. 标签: , , . 阅读(499). 评论(0) »

让 Python 的数据库查询返回字典记录

在使用  Python 进行数据库查询,通常情况下 cursor 的 fetchall, fetchmany 返回的是元组(Tuple) 的列表,所以对查询到的结果只能用索引下标来访问,而无法通过字段名来获取值。对 Java JDBC 的 ResultSet 操作,我们有两种获取值的方式,resultSet.getString(1) 和 resultSet.getString('name')。

其实只要能用数字索引访问到字段值也就足够了,查询后字段名可以由 cursor.description 获得。通过字段名来访问值唯一的好处估计是出错的概率小些罢了,比如 result['firstname'], result['lastname'] 总是比 result[1], result[2] 更不容易搞混,错误定位也会更轻松。

假如有下面的数据库表与两条记录 阅读全文 >>

类别: Python. 标签: , . 阅读(426). 评论(0) »

Python 版的 try-with-resources -- with 上下文管理器

作为一个  Java 为母语的程序员来讲,学习起其他新的语言就难免任何事都与 Java 进行横向对比。Java 7 引入了能省去许多重复代码的 try-with-resources 特性,不用每回 try/finally 来释放资源(不便之处有局部变量必须声明在  try 之前,finally 里还要嵌套 try/catch 来处理异常)。比如下面的  Java 代码

try(InputStream inputStream = new FileInputStream("abc.txt")) {
    System.out.println(inputStream.read());
} catch (Exception ex) {
}

它相应的不使用 try-with-resources 语法的代码就是 阅读全文 >>

类别: Python. 标签: . 阅读(26). 评论(0) »

用 .pth 文件附加 Python 模块搜索路径

上一篇 Python 的模块搜索路径,介绍了 Python 的模块搜索路径,最终起作用的是 sys.path 路径列表。如果要自定义自己的搜索路径,就是要怎么定制 sys.path 的内容。可以简单的用 PYTHONPATH 环境变量前向添加,这儿将要说的是用 .pth 文件的方式。也可由此进一步理解 Python 依赖管理工具,像  virtualenv 等的工作原理。

.pth 文件名是什么,无所谓,Python 只认扩展名。.pth 文件中每行指定一个路径 -- 绝对或相对路径(相对于本  .pth 文件所在的目录),另外还可以空行或 # 开始的注释行,还能有 import 语句,大概只用来校验是否能导入成功,程序代码中还是需要显示的 import 模块。

.pth 文件放在哪里

.pth 文件创建好后应该放到哪里去呢?不是 sys.prefix 指示的位置,也不是 sys.path 中任意一个目录,而是  sys.path 中属于 site.packages 的某一个目录中。可以用

>>> import site
>>> site.getusersitepackages()
>>> site.getsitepackages()

查看到, 看我在  Ubuntu Linux 中看到的内容(为便于阅读,显示列表内容时进行了换行处理) 阅读全文 >>

类别: Python. 标签: , . 阅读(69). 评论(0) »

Python 的模块搜索路径

一种语言要使用到外部库(模块) 时必然会涉及到从哪里以及按何顺序加载依赖,就像 LD_LIBRARY_PATH, CLASSPATH 那样,Python 也有其默认的模块搜索顺序, 依序找到想要的模块即停止。Python 中 sys.path 返回的列表包含了模块搜索的顺序,我们可以程序中修改该列表,或用 PYTHONPATH 环境变量前插路径,甚至是用  .pth 文件来附加路径。

简单的,可以执行命令 python3 -c "import sys; print(str(sys.path).replace(',', '\n'))" 来查看 python3 交互 shell 下的模块搜索路径,类似结果如下:

[''
'/usr/lib/python36.zip'
'/usr/lib/python3.6'
'/usr/lib/python3.6/lib-dynload'
'/home/yanbin/.local/lib/python3.6/site-packages'
'/usr/local/lib/python3.6/dist-packages'
'/usr/lib/python3/dist-packages'
'/usr/lib/python3.6/dist-packages']

注意,第一个元素是个空字符串,代表进入 python3 shell 时的当前目录。

如果在通过一个 py 脚本文件来打印 sys.path 的话显示稍微有所差异。比如在目录 /home/yanbin/Developers/ 下创建 test.py 文件,内容为 阅读全文 >>

类别: Python. 标签: . 阅读(42). 评论(0) »

Python 的 __str__ 和 __repr__ 方法比较

阅读到 Strings 中关于转换对象为字符串的内容,介绍了 repr 函数,趁着还没有真正了解 Python 面向对象的生疏与热度,感性上理解一下 repr 与 str 这两个函数的区别。

Python 的全局方法 repr 和 str 会映射到对象的 __repr__ 和 __str__ 的方法调用,还有 str(obj) 时会调用哪个方法,以及 print(obj) 和调试 Python 代码时的对象显示会调用哪个方法呢?这就是本文想要印证的内容。

恰如 Java 的 System.out.println(obj) 或 "hello" + obj 都会调用 Java 对象的 toString() 方法,那么 Python 中是怎么一回事呢?

来自某本 Python 入门书的解释 repr 和 str:

  1. repr: formal string representation of a Python object
  2. str: informal string representation of a Python object,或者说 printable string representation

首先 repr 是 representation 的意思,一个是正式,另一个是非正式,看起来 repr 比 str 显得重要些。 阅读全文 >>

类别: Python. 标签: . 阅读(56). 评论(2) »