Python Argument list Unpacking

今天遇到一个问题,假设有字符串[ccib_python]s = “INSERT INTO tbl VALUES({0}, {1}, {2}, {3}, {4})”[/ccib_python],如何用format函数将一个元组的内容映射到字符串上去呢?当然,最简单的就是:
[ccb_python]
t = (1, 2, 3, 4)
s.format(t[0], t[1], t[2], t[3])
[/ccb_python]
不过这种做法实在是too simple,too naive了。一点也不pythonic。正确的做法是:
[ccb_python]
s.format(*t)
[/ccb_python]
怎么样,这样是不是看起来顺眼多了?

如果m是一个列表或元组,那么f(*m)将会把列表中的元素分别作为函数f的位置参数。同样,如果m是个字典类型,那么f(*m)将把m中的每个key:value对作为函数f的关键字参数。

参考

  1. Unpacking Argument Lists
  2. The Python IAQ

[译]详解C++右值引用

C++0x标准出来很长时间了,引入了很多牛逼的特性[1]。其中一个便是右值引用,Thomas Becker的文章[2]很全面的介绍了这个特性,读后有如醍醐灌顶,翻译在此以便深入理解。

目录

  1. 概述
  2. move语义
  3. 右值引用
  4. 强制move语义
  5. 右值引用是右值吗?
  6. move语义与编译器优化
  7. 完美转发:问题
  8. 完美转发:解决方案
  9. Rvalue References And Exceptions
  10. The Case of the Implicit Move
  11. Acknowledgments and Further Reading

概述

右值引用是由C++0x标准引入c++的一个令人难以捉摸的特性。我曾偶尔听到过有c++领域的大牛这么说:

每次我想抓住右值引用的时候,它总能从我手里跑掉。

想把右值引用装进脑袋实在太难了。

我不得不教别人右值引用,这太可怕了。

右值引用恶心的地方在于,当你看到它的时候根本不知道它的存在有什么意义,它是用来解决什么问题的。所以我不会马上介绍什么是右值引用。更好的方式是从它将解决的问题入手,然后讲述右值引用是如何解决这些问题的。这样,右值引用的定义才会看起来合理和自然。

右值引用至少解决了这两个问题:

  1. 实现move语义
  2. 完美转发(Perfect forwarding)

如果你不懂这两个问题,别担心,后面会详细地介绍。我们会从move语义开始,但在开始之前要首先让你回忆起c++的左值和右值是什么。关于左值和右值我很难给出一个严密的定义,不过下面的解释已经足以让你明白什么是左值和右值。

在c语言发展的较早时期,左值和右值的定义是这样的:左值是一个可以出现在赋值运算符的左边或者右边的表达式e,而右值则是只能出现在右边的表达式。例如:

[ccb_c++]
int a = 42;
int b = 43;

// a与b都是左值
a = b; // ok
b = a; // ok
a = a * b; // ok

// a * b是右值:
int c = a * b; // ok, 右值在等号右边
a * b = 42; // 错误,右值在等号左边
[/ccb_c++]

在c++中,我们仍然可以用这个直观的办法来区分左值和右值。不过,c++中的用户自定义类型引入了关于可变性和可赋值性的微妙变化,这会让这个方法变的不那么地正确。我们没有必要继续深究下去,这里还有另外一种定义可以让你很好的处理关于右值的问题:左值是一个指向某内存空间的表达式,并且我们可以用&操作符获得该内存空间的地址。右值就是非左值的表达式。例如:

[ccb_c++]
// 左值:
//
int i = 42;
i = 43; // ok, i是左值
int* p = &i; // ok, i是左值
int& foo();
foo() = 42; // ok, foo()是左值
int* p1 = &foo(); // ok, foo()是左值

// 右值:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar()是右值
int* p2 = &foobar(); // 错误,不能取右值的地址
j = 42; // ok, 42是右值
[/ccb_c++]
如果你对左值和右值的严密的定义有兴趣的话,可以看下Mikael Kilpeläinen的文章[3]
继续阅读[译]详解C++右值引用

new的二三事

stackoverflow真是个绝佳的平台。基本上所有的问题都可以找到答案。今天遇到两个比较新鲜的关于new的问题,一个是operator new,另一个是placement new。

operator new

问个问题先:“new operator”和“operator new”有什么区别?new operator大家都很熟悉,就是平常用来创建对象的那个操作符咯。
[ccb_c++]
my_class *x = new my_class(0);
[/ccb_c++]
operator new是什么?好像从来没听过。operator new是用来分配内存的,仅此而已。在概念上来说,operator new和malloc类似。虽然operator new并不常用,但是如果要自己写容器之类的,那么operator new就有用武之地了。operator new可以这样用:
[ccb_c++]
char *x = static_cast(operator new(100));
[/ccb_c++]
operator new和new operator之间的区别在于,new operator会先用operator new去分配内存,然后调用类的构造函数去初始化对象。

placement new

上面说了,new的时候会先分配内存,然后调用构造函数。但是placement new允许在已经分配的内存上面直接构造对象。

这个东西是很有市场的。不用再次分配内存会节省很多时间,提高程序的效率。另外有时候我们不希望发生分配内存出错的情况,placement new就派上用场了,因为内存已经分配好了。placement new要这样用:
[ccb_c++]
char *buf = new char[sizeof(string)]; //pre-allocated buffer
string *p = new (buf) string(“hi”); //placement new
string *q = new string(“hi”); //ordinary heap allocation
[/ccb_c++]

参考

Difference between ‘new operator’ and ‘operator new’?
What uses are there for “placement new”?

Python Decorator

Python有很多漂亮的特性,decorator就是其中之一。什么是decorator?其他语言里面也有类似于decorator的东西,那就是宏。但是c里面的宏的用法是有点诡异的,Bruce Eckel都说,c里面的宏完全是另外一种语言[1]不能同意更多了,从好多#define都会被当做面试题就可以看出来了:D)。

废话少说,先上一个decorator过把瘾。

[ccb_python]
def my_decorator(f):

def new_f(*args, **kwargs):
print ‘enter new_f’
return f(*args, **kwargs)

return new_f

@my_decorator
def f(a, b):
return a + b
[/ccb_python]

上面的my_decorator只是在调用f之前打印“Enter new_f”出来,然后再返回f的结果。想要达到同样的目的,更普通一点的做法是:

[ccb_python]
def f(a, b):
return a + b

f = my_decorator(f)
[/ccb_python]
你会选择普通点的做法,还是文艺点的[ccib_python]@my_decorator[/ccib_python]呢?

用类做decorator

上面的例子用函数作decorator,类也是可以的,只要类实现了[ccib_python]__call__[/ccib_python]方法。其实用类做decorator是更普遍的做法。

[ccb_python]
class Decorator(object):

def __init__(self, f):
print ‘__init__()’
self.f = f

def __call__(self):
print ‘__call__’
self.f()
[/ccb_python]

用Decorator类修饰函数试下:

[ccb_python]
>>> @Decorator
… def f():
… print “in f()”

__init__()
>>> f()
__call__
in f()
[/ccb_python]
与前面的函数做decorator不同的是,用Decorator类修饰f()时产生了一句输出。其实这也很容易理解,因为python的函数本身也是对象,只是我们无法定义函数初始化时候的操作罢了。类就不同了,我们可以随意定义[ccib_python]__init__[/ccib_python]函数来实现想要的功能。

带参数的decorator

decorator也可以有自己的参数,比如:

[ccb_python]
@decorate(message)
def f(….)
[/ccb_python]

上面的等效于

[ccb_python]
temp = decorate(message)
f = temp(f)
[/ccb_python]

带参数的decorator和不带参数的其实是有很大不同的。不相信?那自己写一个函数实现的decorator,再同下面这个做下对比:

[ccb_python]
def decorate(message):
def wrap(f):
def wrapped_f(*args):
print message
return f(*args)
return wrapped_f
return wrap

@decorate(‘message’)
def f(a, b):
print ‘add a and b’
return a + b
[/ccb_python]
猜你的反应肯定是:“WTF!怎么会有这么多层函数!”。先别急,把最外面的一层函数去掉,不就是最简单的没有参数的decorator了吗?其实wrap只是在decoration阶段接收message参数,wrapped_f才是真正会调用的函数。

用类实现的就是下面这个样子的了:

[ccb_python]
class Decorator(object):

def __init__(self, message):
self.message = message

def __call__(self, f):

def wrapped_f(*args):
print self.message
return f(*args)

return wrapped_f
[/ccb_python]

Real word decorators

理解decorator的基础之后,再看几个例子。

我们都知道c++的类可以有static方法,这类方法并不属于某一个具体的实例,而是存在于整个类的命名范围之内的。所有的实例都共用这个方法。在python中,我们也可以实现。方法就是是借助[ccib_python]@staticmethod[/ccib_python]这个decorator:

[ccb_python]
class Foo(object):
@staticmethod
def add(x,y):
return x + y

x = Foo.add(3,4)
[/ccb_python]

另外一个常见的decorator就是[ccib_python]@classmethod[/ccib_python]。用classmethod修饰的方法和普通的方法不同,普通的方法第一个参数都是self,而classmethod的第一个参数则是类。例如:

[ccb_python]
class Times(object):
factor = 1
@classmethod
def mul(cls,x):
return cls.factor*x

class TwoTimes(Times):
factor = 2

x = TwoTimes.mul(4)
[/ccb_python]
还有更多的用法,参见这里

参考

  1. Decorators I: Introduction to Python Decorators
  2. Python Decorators II: Decorator Arguments
  3. PythonDecoratorLibrary

理解cpu load average

要问我平常使用频率最高的命令,那必须是top,没有之一。虽然天天用,但有的参数还真不是很清楚。比如一直没弄明白cpu百分比和load average这两个参数哪个更“权威”一点。其实是因为对load average这个参数没什么概念,只知道大的时候就说明cpu负载比较高。为了以后不再糊涂,所以仔细研究了一下cpu load average。
load

cpu百分比

首先需要搞清楚的是,cpu的使用状态是一个离散的变量。就是说某一时刻cpu要么就是正在执行指令,要么就是处于空闲状态,cpu的利用百分比要不就是100%,要不就是0%。而绝不会说执行某条指令使用了50%的cpu。那为什么top里面有时候会显示除了0%和100%呢?其实top里面的的cpu百分比是时间上的概念:

k: %CPU — CPU usage
The task’s share of the elapsed CPU time since the last screen update, expressed as a percentage of total CPU time. In a true SMP environment, if ‘Irix mode’ is Off, top will operate in ‘Solaris mode’ where a task’s cpu usage will be divided by the total number of CPUs. You toggle ‘Irix/Solaris’ modes with the ‘I’ interactive command.

以上内容出自top的manual。假设top里面更新一次的间隔是1s,进程a的cpu百分比为50%,那么说明在过去的一秒里面,cpu花了0.5秒来执行进程a的指令。如果总cpu百分比是70%,那么在过去的一秒中,总共有0.7秒cpu处于计算的状态,剩下的0.3秒处于空闲状态。这就是cpu百分比的真正含义。

load average

load average与cpu percentage主要有两点不同:第一,load average反映的不仅仅是某一瞬间的cpu利用情况,而是反映了一种趋势。第二,load average反映了系统对cpu的需求情况,而不只是cpu有多少时间处于活跃的状态。

为了更好的理解load average的概念,我们可以同交通流量做个类比。有一条单行道(cpu),最多只能容纳一定数量的车子在上面行驶(cpu执行任务)。车子在路上行驶可能有三种情况:

  1. 路上很空旷,很可以容纳更多的车辆行驶。
  2. 路上很挤,有很多车辆在排队等待通过。
  3. 路上的车辆数量跟道路的容量刚好相等。

以上3种情况,分别对应cpu load average小于1、大于1和刚好等于1。通过这样一个类比,load average的概念就清晰多了:

  1. load average小于1:任务数小于cpu的处理能力,cpu处于相对空闲的状态
  2. load average大于1:任务数大于cpu的处理能力,cpu处理不过来,某些任务排队等候处理
  3. load average等于1:任务数刚好等于cpu的处理能力,cpu既不繁忙也不空闲

如果cpu是多核的呢?那么我们不应该用单行道来做类比,而是双行道、四行道等等。因此多核的cpu 要根据核的数量判断load average高低。如果是双核,那load average等于2的时候刚刚好,以此类推。核的数量可以通过读取proc文件系统中的信息判断:
[ccb_bash]grep ‘model name’ /proc/cpuinfo | wc -l[/ccb_bash]

参考:

  1. http://www.linuxjournal.com/article/9001
  2. http://blog.scoutapp.com/articles/2009/07/31/understanding-load-averages

*args and **kwargs in Python

Python里面*args和**kwargs的用途和c里面[ccib_c]**argv[/ccib_c]的用法类似,都是用来表示可变参数。[ccib_c]int main (int argc, char **argv)//Variable-length arguments in c[/ccib_c]

*args和**kwargs的区别在于前者用于表示非关键字可变长度参数,后者表示关键字可变长度参数。

*args

[ccb_python]
def func_args(arg1, *args):
print ‘Normal argument:’, arg1
for arg in args:
print ‘variable arg:’, arg

>>> func_args(1, 2, ‘3’)
Normal argument: 1
variable arg: 2
variable arg: 3
[/ccb_python]

**kwargs

[ccb_python]
def func_kwargs(arg1, **kwargs):
print ‘Normal argument:’, arg1
for key in kwargs:
print ‘Keyworded variable arg:’, key, kwargs[key]

>>> func_kwargs(arg1=1, karg1=’2′, karg2=3)
Normal argument: 1
Keyworded variable arg: karg2 3
Keyworded variable arg: karg1 2
[/ccb_python]

除了定义函数,*args和**kwargs还可以用来调用函数。

[ccb_python]
def func(arg1, arg2, arg3):
print ‘arg1:’, arg1
print ‘arg2:’, arg2
print ‘arg3:’, arg3

>>> args = (2, ‘3’)
>>> kwargs = {‘arg2’:2, ‘arg3′:’3’}
>>> func(1, *args)
arg1: 1
arg2: 2
arg3: 3
>>> func(1, **kwargs)
arg1: 1
arg2: 2
arg3: 3
[/ccb_python]

Python调用c函数

如果你已经写好了一个c程序,但是又需要用脚本来实现同样的功能,应该怎么做?用python重新实现一次当然可以。但这样又得耗费不少精力,而且重复的劳动也没有意义。这种情况下就应该用ctypes模块了。

比如我想在脚本里面调用jenkins hash方法来计算某个序列的哈希值。python没有这样的模块可用。不过手头倒是有jenkins hash的c程序。看这段代码,如果用python再实现一次,是有点复杂的。所以最好的方式是把这段程序拿过来直接用。

[ccb_c height=”500″]
#include
#include
#define mix(a,b,c)
{
a -= b; a -= c; a ^= (c >> 13);
b -= c; b -= a; b ^= (a << 8); c -= a; c -= b; c ^= (b >> 13);
a -= b; a -= c; a ^= (c >> 12);
b -= c; b -= a; b ^= (a << 16); c -= a; c -= b; c ^= (b >> 5);
a -= b; a -= c; a ^= (c >> 3);
b -= c; b -= a; b ^= (a << 10); c -= a; c -= b; c ^= (b >> 15);
}

unsigned int bob_hash(void *val, unsigned int length)
{
char *k = (char *)val;
unsigned long a,b,c,len;

/* Set up the internal state */
len = length;
a = b = c = 0x9e3779b9; /* the golden ratio; an arbitrary value */

/* Handle most of the key */
while (len >= 12)
{
a += (k[0] +((unsigned long)k[1] << 8) +((unsigned long)k[2] << 16) +((unsigned long)k[3] << 24)); b += (k[4] +((unsigned long)k[5] << 8) +((unsigned long)k[6] << 16) +((unsigned long)k[7] << 24)); c += (k[8] +((unsigned long)k[9] << 8) +((unsigned long)k[10]<< 16)+((unsigned long)k[11] << 24)); mix(a,b,c); k += 12; len -= 12; } /* Handle the last 11 bytes */ c += length; switch(len) /* all the case statements fall through */ { case 11: c+=((unsigned long)k[10] << 24); case 10: c+=((unsigned long)k[9] << 16); case 9 : c+=((unsigned long)k[8] << 8); /* the first byte of c is reserved for the length */ case 8 : b+=((unsigned long)k[7] << 24); case 7 : b+=((unsigned long)k[6] << 16); case 6 : b+=((unsigned long)k[5] << 8); case 5 : b+=k[4]; case 4 : a+=((unsigned long)k[3] << 24); case 3 : a+=((unsigned long)k[2] << 16); case 2 : a+=((unsigned long)k[1] << 8); case 1 : a+=k[0]; } mix(a,b,c); return c; } int hash_string(void *tmpstr) { int hash = (int)bob_hash(tmpstr, strlen(tmpstr)); if(hash < 0) { hash = -hash; } return (int)(hash % 200); } int main() { printf("%d", hash_string("15882917276")); } [/ccb_c] 首先把这段程序编译为so文件。 [ccb_bash] gcc -fPIC -shared bob_hash.c -o bob_hash.so [/ccb_bash] 然后在python里面用ctypes加载刚才的动态库。argtypes和restype分别对应函数的参数和返回值的类型。这样就可以直接调用了。 [ccb_python] >>> from ctypes import CDLL, c_int, c_void_p
>>> bob_hash = CDLL(‘/home/jxq/code/bob_hash.so’)
>>> hash_string = bob_hash.hash_string
>>> hash_string.argtypes = [c_void_p]
>>> hash_string.restype = c_int
>>> hash_string(‘123’)
90
[/ccb_python]

Python修改函数参数?

有很多次尝试修改函数参数的值,因为不知道究竟能不能改,所以每次都写个函数测试一下。经过若干次的“测试”,发现还是没有明确的结论。好像对于不同类型的参数,结果不同。最终,在stackoverflow上面找到了问题的答案

先猜下这段代码的输出:
[ccb_python]
def f(n, x):
n = 2
x.append(4)
print ‘In f():’, n, x

def main():
n = 1
x = [0,1,2,3]
print ‘Before:’, n, x
f(n, x)
print ‘After: ‘, n, x

main()
[/ccb_python]

c语言的函数修改参数,参数类型必须为指针才可以。c++则是通过传递“引用”的方式。那么Python有类似的处理方式吗?
继续阅读Python修改函数参数?

理解python生成器

先看一个函数:
[ccb_python]
def group(seq, size):
“””
Returns an iterator over a series of lists of length size from iterable.

>>> list(group([1,2,3,4], 2))
[[1, 2], [3, 4]]
>>> list(group([1,2,3,4,5], 2))
[[1, 2], [3, 4], [5]]
“””
def take(seq, n):
for i in xrange(n):
yield seq.next()

if not hasattr(seq, ‘next’):
seq = iter(seq)
while True:
x = list(take(seq, size))
if x:
yield x
else:
break
[/ccb_python]
函数中没有常见的return,而是使用了yield。yield和return相同的地方是都用来向函数的调用者返回值。下面这个简单的例子展示了yield与return的不同。
继续阅读理解python生成器

用python和redis打造短网址服务

这篇文章的启发,用python+redis实现了文中的短网址服务。其中使用了web.py作为web框架,redis作为后台存储。部署在dotcloud上面。访问http://81aca6aa.dotcloud.com查看效果。由于使用了几个css3的效果,建议使用firefox、chrome或者ie 8以上的浏览器打开。代码放在GitHub

Web.py比django精简很多,使用起来也相对容易些。基本上对着文档,几分钟就可以写个服务出来。Django给人的感觉则是非常庞大,但是其功能是相当完善的。在框架的选择上,没有最好的,只有最适合的。这个短网址的服务不需要太复杂的功能,而且仅仅是作为一个demo写来玩玩而已,就选择了web.py。
继续阅读用python和redis打造短网址服务