字符串在 Python 2.x 和 3.x 下的适配

RQ 提交了一个 Pull Request 来解决 issue#437 .

最开始的提交 我做了以下的工作:

  • 找到问题所在
  • 写新的单元测试
  • 将相关串做 decode 操作
  • 跑单元测试通过, 提交 Pull Request

然后….就遇到问题了, Travis 跑完发现 Python2.x 下都没问题, 但是 Python3.x 都跑不过, 原因很简单, python3.x 的时候已经不区分 string 和 unicode, 统一采用 unicode, 因此也取消了 decode 方法. 那么我们如何来同时适配 2.x 和 3.x 版本呢. 我想过很多方法, 但是都觉得不够优雅, 后来还是在 RQ 这个库本身里找到了答案.

在 RQ 中, 对字符串的获取都会经过一个 as_text 的函数处理, 该函数位于 compat/__init__.py, 就是为了同时适配 2.x 和 3.x 版本, 函数如下:

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
if not PY2:
# Python 3.x and up
text_type = str
string_types = (str,)
def as_text(v):
if v is None:
return None
elif isinstance(v, bytes):
return v.decode('utf-8')
elif isinstance(v, str):
return v
else:
raise ValueError('Unknown type %r' % type(v))
def decode_redis_hash(h):
return dict((as_text(k), h[k]) for k in h)
else:
# Python 2.x
text_type = unicode
string_types = (str, unicode)
def as_text(v):
if v is None:
return None
return v.decode('utf-8')
def decode_redis_hash(h):
return h

首先通过 six 这个库来判断 Python 版本, 然后根据版本的不同, 声明 as_text 方法的具体实现, 这样在整个库在处理字符串时, 不需要考虑版本差异, 直接调用 as_text 进行处理即可.

用了pyenv-virtualenv, 天黑都不怕

之前就有听大妈推荐过 pyenv. 最近给一个项目这个库提交 Pull Request, 但 Python3.X 的单元测试没有跑过, 而我的机器上没有 Python3.X, 也不想把现有的 Python2.7 替换掉, 所以就用起了这个库.

简单的说, pyenv 是一个Python管理工具, 这个是和我们常用的 virtualenv 有所不通, 前者是对 Python 的版本进行管理, 实现不同版本的切换和使用. 后者测试创建一个虚拟环境, 与系统环境以及其他 Python 环境隔离, 避免干扰.

安装方法我就不做赘述了, pyenv readme 已经写的特别详尽

pyenv使用方法

简单的说一下使用方法

安装不同版本的 Python

1
2
pyenv install <version> #安装特定版本的 Python
pyenv install 3.3.0 #安装 Python 3.3.0

当我的系统 Python 版本是 2.7, 但是有个 叫做 py3-project 需要用 Python3 来运行的时候, 只需要这样做:

1
2
3
4
cd py3-project #进入项目目录
pyenv local 3.3.0 #将当前目录下的Python环境切换为3.3.0
pyenv version #运行显示通过pyenv设置之后的python版本, 得到结果是3.3.0
python --version #查看Python版本, 得到结果也是3.3.0

此时就可以通过 python3.3 来运行项目了, 才这个项目之外的目录运行 Python, 你会发现仍然是系统版本. 通过pyenv可以给不同的目录设置不同的 Python 版本, 还可以通过 pyenv global 这个命令切换整个全局的 Python版本. 赞爆了是不是.

告别virtualenv

接下来, 再介绍一个工具, 配合pyenv, 让我告别了用了很久了virtualenv.这个工具叫做 pyenv-virtualenv, 安装方法依然跳过, 至于使用, 你只需要记住三条命令:

1
2
3
pyenv virtualenv 3.3.0 env #创建一个 Python 版本为 3.3.0 的环境, 环境叫做 env
pyenv activate env_name #激活 env 这个环境, 此时 Python 版本自动变为 3.3.0, 且是独立环境
pyenv deactivate #离开已经激活的环境

嗯, 写完这篇继续去修复那段 Python3.X 下通不过单元测试的程序.

再见了, virtualenv.

go语言学习(一)

包的导入方法1:

1
2
3
4
import (
"fmt"
"math"
)

包的导入方法2:

1
2
import "fmt"
import "math"

作为 Pytonista, 更喜欢第 2 种方式 更加简洁.

包的变量导出

Go 语言通过命名来确定该变量是否是可以导出到外部供别的包所使用.可以被导出的变量通过将变量名的首字母大写来标志确定.

函数

一个函数可以收 0 到任意多个参数. 接收的参数类型在参数名之后声明:

1
2
3
func add(x int, y int) int {
return x+y
}

如果一个函数接受的所有参数是同一个类型的时候, 那么可以不需要每一个参数都标明类型, 只需要在最后一个参数上标明类型就可以.

1
2
3
func add(x, y int){ #当多个参数是同一类型时, 可以省略只声明一次.
return x+y
}

一个函数可以返回多个值

1
2
3
func swap(x, y int) int, int{
return y, x
}

go也可以对返回变量命名

1
2
3
4
func split(sum int) (x, y int){
x = sum * 4 / 9
y = sum - x
}

变量

变量声明

go 通过 var 关键字来声明变量, 和函数参数声明一致, 变量类型在变量名之后声明:

1
2
var i int
var c, python, java bool #三个值都为bool类型

变量初始化

变量可以在声明的时候立刻初始化:

1
2
var i, j int = 1, 2
var c, python, java = true, false, "no!"

短变量声明

短变量声明是一个特殊的使用方法, 有以下特点:

  • 只能在函数内部使用
  • 不需要var关键字和类型
  • 类型通过赋值时隐式声明
1
2
3
4
5
func main(){
var i, j int = 1, 2
k := 3
c, python, java = true, false, "No!"
}

变量类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte // alias for uint8
rune // alias for int32
// represents a Unicode code point
float32 float64
complex64 complex128

常量

常量只能使用const关键字生成

1
const Pi = 3.14

postgres-snippet

创建数据库

1
CREATE DATABASE DATABASE_NAEM;

删除数据库

1
DROP DATABASE DATABASE_NAME;

查看所有数据库

1
2
\list #或者\l
\l+ #显示更详尽的数据库信息

查看所有用户

1
2
\du
\du+ #显示更详尽的用户信息

创建用户

1
CREATE USER USERNAME;

删除用户

1
DROP USER USERNAME;

授予用户操作某个DATABASE的所有权限

1
GRANT ALL ON DATABASE DATABASE_NAME TO USERNAME;