一些python
最近在试着读OpenStack Nova的源代码。不看别人的代码不知道自己是有多无知啊…
1.协程(Coroutine)
按我现在的理解,协程是比线程还要轻的一种程序并发执行方式。Python用“yield”这个关键字提供了对协程的支持。
看个例子就懂了:
def foo():
for i in range(10):
yield i
print 'foo: here ' + str(i)
bar = foo()
print bar.next()
print 'main: here'
print bar.next()
print bar.next()
例子的输出是:
0 main: here foo: here 0 1 foo: here 1 2
在协程里,yield起到的是类似return的作用,但是远没有return那么重:没有进程/线程调度,也就不必保存现场,函数只是暂停,过会儿还会从yield处继续执行。而如果yield后面不跟变量,甚至可以把yield看作一个标记,表示这个位置上,函数可以暂停。
上述例子中,代码的执行流程是这个样子的:第一个bar.next()输出i = 0,之后foo()函数暂停,main输出“main: here”,然后每次执行bar.next()输出“foo: here i”,然后返回打印出i。
协程的主要应用场景是服务器端的编程。因为它比线程更轻,所以可以支持更大的并发数。
举个例子,假如在服务器端生成了10000个协程,然后开始运行“调度”函数。当新的连接进入时,“调度”函数给新连接分配一个协程,而当这个协程进行IO时,会暂停让出CPU,“调度”函数再选择其它协程执行。跟进程调度很像,但是协程并没有被“阻塞”,事实上,上述的10000个协程可以是运行在一个线程中的。
OpenStack里面使用了一个叫eventlet的基于协程的网络编程库
2.@修饰符(decorator)
官方文档说修饰符只是一种语法糖(syntactic sugar),简单来说,就是下面两段代码是完全等价的。
def foo(arg):
some code
foo = bar(foo)
@bar
def f(arg):
some code
主要参考1
3. @classmethod和@staticmethod
在一个类里面,可以存在三种方法:实例方法、类方法、静态方法,定义方法如下:
class Foo(object):
def instanceFoo(self,x):
some code
@classmethod
def classFoo(cls,x):
some code
@staticmethod
def staticFoo(x):
some code
最显然的区别,就是他们接受的参数是不同的。实例方法必须接受一个实例(self),类方法必须接受一个类(cls),静态函数没有要求。
静态方法在python里用途不大,因为class.staticmethod()和module.normalfunction()不管从外观还是从作用都区别不大。而类方法可以用来进行类的实例化:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> x = dict.fromkeys('ab')
>>> print x
{'a': None, 'b': None}
>>> y = x.fromkeys('qwe')
>>> print x,y
{'a': None, 'b': None} {'q': None, 'e': None, 'w': None}
>>>
4.*arg,**arg
这个不是指针,当参数为*arg时,表示接受一个元组;当参数为**arg时,表示接受一个字典
主要参考1
5.继承/多重继承中的参数传递
在继承/多重继承中,参数是逐级向上传递的,最后传递给object(python里一切对象的基类)时,参数应该已经处理完毕。
看个例子:
class Service(object):
def __init__(self, host, binary, topic, manager, report_interval=None,
periodic_interval=None, *args, **kwargs):
print 'Initializing Service'
super(Service, self).__init__(*args, **kwargs)
print 'Service: ' + binary, args, kwargs
class Color(object):
def __init__(self, color='red', **kwargs):
print 'Initializing Color'
self.color = color
super(Color, self).__init__(**kwargs)
print 'Color: ', kwargs
class ColoredService(Service, Color):
def __init__(self, *args, **kwds):
print 'Initializing Colored Service'
super(ColoredService, self).__init__(*args, **kwds)
c = ColoredService('host', 'bin', 'top', 'mgr', 'ivl', color='blue')
输出是:
Initializing Colored Service
Initializing Service
Initializing Color
Color: {}
Service: bin () {'color': 'blue'}
在这个例子里,ColoredService继承了Service和Color,首先初始化ColoredService,然后是Service,此时类Service“吃掉”了传来的大部分参数,只剩下{‘color’: ‘blue’}。然后初始化Color,最后是object。假如传递到object时参数还没有被吃完,python就会报“TypeError: object.__init__() takes no parameters”的错误。
而在多重继承中继承顺序的确定是用了一种叫做C3 Method Resolution Order(MRO)的算法