高效的 itertools 模块

我们知道,迭代器的特点是:惰性求值(Lazy evaluation),即只有当迭代至某个值时,它才会被计算,这个特点使得迭代器特别适合于遍历大文件或无限集合等,因为我们不用一次性将它们存储在内存中。

Python 内置的 itertools 模块包含了一系列用来产生不同类型迭代器的函数或类,这些函数的返回都是一个迭代器,我们可以通过 for 循环来遍历取值,也可以使用 next() 来取值。

itertools 模块提供的迭代器函数有以下几种类型:

  • 无限迭代器:生成一个无限序列,比如自然数序列 1, 2, 3, 4, ...
  • 有限迭代器:接收一个或多个序列(sequence)作为参数,进行组合、分组和过滤等;
  • 组合生成器:序列的排列、组合,求序列的笛卡儿积等;

阅读全文 »

Python 中的单例模式

单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

在 Python 中,我们可以用多种方法来实现单例模式:

  • 使用模块
  • 使用 __new__
  • 使用装饰器(decorator)
  • 使用元类(metaclass)

阅读全文 »

Python 之旅

cover

在学习和使用 Python 的过程中,我作了不少笔记,并对一些笔记进行了加工和完善,发表在博客上。随着笔记的增加,我就萌生了写一本书的想法,希望能比较系统地总结相关知识,巩固自己的知识体系,而不是停留在『感觉好像懂了』的状态中。

有了想法之后,接下来就要开始写了。当然,从产生想法到付诸实践还是纠结了一段时间,毕竟,作笔记和写书很不一样啊。思想斗争过后,我下定决心要把它写出来。

首先,我参考一些相关的书籍,作了一个基础的思维导图,如下:

思维导图

接下来,就要开始写作了,这也是最艰难的一关。

我没有按照从头到尾的顺序写,而是从最感兴趣的知识点入手,比如函数式编程、类的使用等等。就这样,一点一点地写,实在不想写了,就先搁置一下,过两天继续写。

我在写作的过程中,给自己提了一个要求:尽量深入浅出,条理清晰。至于是否达到了,希望读者们多多批评指正,并给我提意见和建议。

目前,本书的目录如下(基本对应上面的思维导图):

  • 第 1 章:介绍一些基础知识,包括 Python 中的输入和输出,字符编码。
  • 第 2 章:介绍常用数据类型,比如字符串、列表和字典等。
  • 第 3 章:介绍函数的定义和函数参数魔法。
  • 第 4 章:介绍 Python 中的函数式编程,包括匿名函数、闭包和装饰器等。
  • 第 5 章:介绍 Python 中类的使用,包括类方法、静态方法、super 和元类的使用等。
  • 第 6 章:介绍 Python 中的高级特性,比如生成器,上下文管理器。
  • 第 7 章:介绍文件和目录操作,os 的使用。
  • 第 8 章:介绍使用 Python 处理进程、线程和协程。
  • 第 9 章:异常处理。
  • 第 10 章:单元测试。
  • 第 11 章:正则表达式,re 模块的使用。
  • 第 12 章:HTTP 服务,requests 模块的使用。
  • 第 13 章:一些标准模块的使用,比如 argparse、collections 和 datetime 等。
  • 第 14 章:一些第三方模块的使用。
  • 第 15 章:结束语。

本书的编码环境:

  • Python 版本以 2.7 为主,同时也会指出在 Python3 中的相应变化
  • 操作系统使用 macOS,代码结果,尤其是内存地址等由于运行环境的不同会存在差异

最后,附上书籍地址:

Python 正则表达式 re 模块

简介

正则表达式(regular expression)是可以匹配文本片段的模式。最简单的正则表达式就是普通字符串,可以匹配其自身。比如,正则表达式 ‘hello’ 可以匹配字符串 ‘hello’。

要注意的是,正则表达式并不是一个程序,而是用于处理字符串的一种模式,如果你想用它来处理字符串,就必须使用支持正则表达式的工具,比如 Linux 中的 awk, sed, grep,或者编程语言 Perl, Python, Java 等等。

正则表达式有多种不同的风格,下表列出了适用于 Python 或 Perl 等编程语言的部分元字符以及说明:

阅读全文 »

命令行神器 Click

Click

Click 是用 Python 写的一个第三方模块,用于快速创建命令行。我们知道,Python 内置了一个 Argparse 的标准库用于创建命令行,但使用起来有些繁琐,Click 相比于 Argparse,就好比 requests 相比于 urllib

快速使用

Click 的使用大致有两个步骤:

  1. 使用 @click.command() 装饰一个函数,使之成为命令行接口;
  2. 使用 @click.option() 等装饰函数,为其添加命令行选项等。

它的一种典型使用形式如下:

1
2
3
4
5
6
import click
@click.command()
@click.option('--param', default=default_value, help='description')
def func(param):
pass

阅读全文 »

异步任务神器 Celery

Celery

在程序的运行过程中,我们经常会碰到一些耗时耗资源的操作,为了避免它们阻塞主程序的运行,我们经常会采用多线程或异步任务。比如,在 Web 开发中,对新用户的注册,我们通常会给他发一封激活邮件,而发邮件是个 IO 阻塞式任务,如果直接把它放到应用当中,就需要等邮件发出去之后才能进行下一步操作,此时用户只能等待再等待。更好的方式是在业务逻辑中触发一个发邮件的异步任务,而主程序可以继续往下运行。

Celery 是一个强大的分布式任务队列,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。它的架构组成如下图:

Celery_framework

阅读全文 »

实例讲解基于 Flask+React 的全栈开发和部署

简介

我有时在 Web 上浏览信息时,会浏览 Github Trending, Hacker News稀土掘金 等技术社区的资讯或文章,但觉得逐个去看很费时又不灵活。后来我发现国外有一款叫 Panda 的产品,它聚合了互联网大多数领域的信息,使用起来确实很不错,唯一的遗憾就是没有互联网中文领域的信息,于是我就萌生了一个想法:写个爬虫,把经常看的网站的资讯爬下来,并显示出来。

有了想法,接下来就是要怎么实现的问题了。虽然有不少解决方法,但后来为了尝试使用 React,就采用了 Flask + React + Redux 的技术栈。其中:

  • Flask 用于在后台提供 api 服务
  • React 用于构建 UI
  • Redux 用于数据流管理

目前项目已经实现了基本功能,项目源码:Github 地址。目前界面大概如下:

home

阅读全文 »

Python 函数参数魔法

函数参数

在 Python 中,定义函数和调用函数都很简单,但如何定义函数参数和传递函数参数,则涉及到一些套路了。总的来说,Python 的函数参数主要分为以下几种:

  • 必选参数
  • 默认参数
  • 可变参数
  • 关键字参数

必选参数

必选参数可以说是最常见的了,顾名思义,必选参数就是在调用函数的时候要传入数量一致的参数,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> def add(x, y): # x, y 是必选参数
... print x + y
...
>>> add() # 啥都没传,不行
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly 2 arguments (0 given)
>>> add(1) # 只传了一个,也不行
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly 2 arguments (1 given)
>>> add(1, 2) # 数量一致,通过
3

阅读全文 »

熟悉又陌生的字符编码

字符编码是计算机编程中不可回避的问题,不管你用 Python2 还是 Python3,亦或是 C++, Java 等,我都觉得非常有必要厘清计算机中的字符编码概念。本文主要分以下几个部分介绍:

  • 基本概念
  • 常见字符编码简介
  • Python 的默认编码
  • Python2 中的字符类型
  • UnicodeEncodeError & UnicodeDecodeError 根源

基本概念

  • 字符(Character)

在电脑和电信领域中,字符是一个信息单位,它是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。比如,一个汉字,一个英文字母,一个标点符号等都是一个字符。

  • 字符集(Character set)

字符集是字符的集合。字符集的种类较多,每个字符集包含的字符个数也不同。比如,常见的字符集有 ASCII 字符集、GB2312 字符集、Unicode 字符集等,其中,ASCII 字符集共有 128 个字符,包含可显示字符(比如英文大小写字符、阿拉伯数字)和控制字符(比如空格键、回车键);GB2312 字符集是中国国家标准的简体中文字符集,包含简化汉字、一般符号、数字等;Unicode 字符集则包含了世界各国语言中使用到的所有字符,

  • 字符编码(Character encoding)

字符编码,是指对于字符集中的字符,将其编码为特定的二进制数,以便计算机处理。常见的字符编码有 ASCII 编码,UTF-8 编码,GBK 编码等。一般而言,字符集字符编码往往被认为是同义的概念,比如,对于字符集 ASCII,它除了有「字符的集合」这层含义外,同时也包含了「编码」的含义,也就是说,ASCII 既表示了字符集也表示了对应的字符编码

下面我们用一个表格做下总结:

概念 概念描述 举例
字符 一个信息单位,各种文字和符号的总称 ‘中’, ‘a’, ‘1’, ‘$’, ‘¥’, …
字符集 字符的集合 ASCII 字符集, GB2312 字符集, Unicode 字符集
字符编码 将字符集中的字符,编码为特定的二进制数 ASCII 编码,GB2312 编码,Unicode 编码
字节 计算机中存储数据的单元,一个 8 位(bit)的二进制数 0x01, 0x45, …

阅读全文 »

会打扮的装饰器

装饰器

我们知道,在 Python 中,我们可以像使用变量一样使用函数:

  • 函数可以被赋值给其他变量
  • 函数可以被删除
  • 可以在函数里面再定义函数
  • 函数可以作为参数传递给另外一个函数
  • 函数可以作为另一个函数的返回

简而言之,函数就是一个对象

对一个简单的函数进行装饰

为了更好地理解装饰器,我们先从一个简单的例子开始,假设有下面的函数:

1
2
def hello():
return 'hello world'

现在我们想增强 hello() 函数的功能,希望给返回加上 HTML 标签,比如 <i>hello world</i>,但是有一个要求,不改变原来 hello() 函数的定义。这里当然有很多种方法,下面给出一种跟本文相关的方法:

1
2
3
4
def makeitalic(func):
def wrapped():
return "<i>" + func() + "</i>"
return wrapped

在上面的代码中,我们定义了一个函数 makeitalic,该函数有一个参数 func,它是一个函数;在 makeitalic 函数里面我们又定义了一个内部函数 wrapped,并将该函数作为返回。

阅读全文 »