Archive for the ‘ 笔记本 ’ Category

一些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的基于协程的网络编程库

主要参考12

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}
>>>

主要参考 12

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)的算法

主要参考12

Qwt样例之tvplot

Qwt的tvplot这个样例主要讲的是如何画柱状图(Histogram)

tvplot

整个过程从继承自QwtPlot的TVPlot开始,建立画布、座标轴、图例,然后在图上画网格线和柱状图

最后进行图像的初始化,确保右边图例的点按状态和图像显示一致

其实也比较简单,用别人的库最重要的是熟悉每个类和成员函数…

main.cpp和tvplot.h可以忽略不计,重点在tvplot.cpp:

#include <stdlib.h>
#include <qpen.h>
#include <qwt_plot_layout.h>
#include <qwt_legend.h>
#include <qwt_legend_item.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_histogram.h>
#include <qwt_column_symbol.h>
#include <qwt_series_data.h>
#include "tvplot.h"

class Histogram: public QwtPlotHistogram
{
public:
    Histogram(const QString &, const QColor &);

    void setColor(const QColor &);
    void setValues(uint numValues, const double *);
};

Histogram::Histogram(const QString &title, const QColor &symbolColor):
    QwtPlotHistogram(title)
{
    setStyle(QwtPlotHistogram::Columns);

    setColor(symbolColor);
}

void Histogram::setColor(const QColor &symbolColor)
{
    QColor color = symbolColor;
    color.setAlpha(180);  // 真烧包,还半透明

    setPen(QPen(Qt::black));
    setBrush(QBrush(color));

    QwtColumnSymbol *symbol = new QwtColumnSymbol(QwtColumnSymbol::Box);
    symbol->setFrameStyle(QwtColumnSymbol::Raised);
    symbol->setLineWidth(2);
    symbol->setPalette(QPalette(color));
    setSymbol(symbol);
}

void Histogram::setValues(uint numValues, const double *values)
{
    // QwtIntervalSeriesData = QwtIntervalSample * n
    // QwtIntervalSample = value + interval
    // interval = minValue + maxValue
    // value,minValue,maxValue : double
    QVector<QwtIntervalSample> samples(numValues);
    for ( uint i = 0; i < numValues; i++ )
    {
        QwtInterval interval(double(i), i + 1.0);
        interval.setBorderFlags(QwtInterval::ExcludeMaximum);

        samples[i] = QwtIntervalSample(values[i], interval);
    }
    setData(new QwtIntervalSeriesData(samples));
}

TVPlot::TVPlot(QWidget *parent):
    QwtPlot(parent)
{
    setTitle("Watching TV during a weekend");

    setCanvasBackground(QColor(Qt::gray));
    plotLayout()->setAlignCanvasToScales(true);

    setAxisTitle(QwtPlot::yLeft, "Number of People");
    setAxisTitle(QwtPlot::xBottom, "Number of Hours");

    QwtLegend *legend = new QwtLegend;
    legend->setItemMode(QwtLegend::CheckableItem);
    insertLegend(legend, QwtPlot::RightLegend);

    populate();

    // 点选图例时,显示相应的图像
    connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)),
        SLOT(showItem(QwtPlotItem *, bool)));

    replot(); // creating the legend items

    // itemList()返回当前attach到plot上的item,参数是类型
    QwtPlotItemList items = itemList(QwtPlotItem::Rtti_PlotHistogram);
    for ( int i = 0; i < items.size(); i++ )
    {
	// items.size()是2,即一个夏天一个冬天
        if ( i == 0 )
        {
	    // 根据item[i]查出相应的图例
            QwtLegendItem *legendItem = 
				(QwtLegendItem *)legend->find(items[i]);
           if ( legendItem )
                legendItem->setChecked(true);

            items[i]->setVisible(true);
        }
        else
            items[i]->setVisible(false);
    }

    setAutoReplot(true);
}

void TVPlot::populate()
{
    QwtPlotGrid *grid = new QwtPlotGrid;
    grid->enableX(false);    // 网格线整体开关
    grid->enableY(true);
    grid->enableXMin(false);
    grid->enableYMin(false);    // 最小刻度网格线
    // 网格线有两种,major和minor(最小刻度)
    // 下面是设置mojor线的样式
    grid->setMajPen(QPen(Qt::black, 0, Qt::DotLine));
    grid->attach(this);

    const double juneValues[] = { 7, 19, 24, 32, 10, 5, 9, 9 };
    const double novemberValues[] = { 4, 15, 22, 34, 13, 8, 4, 5 };

    Histogram *histogramJune = new Histogram("Summer", Qt::red);
    histogramJune->setValues(
        sizeof(juneValues) / sizeof(double), juneValues);
    histogramJune->attach(this);

    Histogram *histogramNovember = new Histogram("Winter", Qt::blue);
    histogramNovember->setValues(
        sizeof(novemberValues) / sizeof(double), novemberValues);
    histogramNovember->attach(this);
}

void TVPlot::showItem(QwtPlotItem *item, bool on)
{
    item->setVisible(on);
}

Qwt安装与初步

Qwt,即”Qt Widgets for Technical Applications”,是一个用来画各种数据图的Qt库

据说写得比较完善,可以帮人省不少代码…类LGPL许可,毕设的画图部分就用这个东西了

安装参考install文件,比较顺利,不过Mac下面还是得稍微折腾下,具体过程:

cd $QwtDir
qmake -spec macx-g++
make
sudo make install
sudo ln -s /usr/local/qwt-6.0.0/lib/qwt.framework/qwt /usr/lib/qwt

其中$QwtDir是源码文件夹,最后一句ln做符号链接的时候注意版本号要与时俱进

要使用的话在所建工程的.pro文件里加入下面一句:

include(/usr/local/qwt-6.0.0/features/qwt.prf)

而官方文档上的说法,即加入CONFIG += qwt,在我这跑不通…

网上资料很少,只有啃自带的例子,一个最简单的例子

#include <cmath>
#include <qwt_series_data.h>
#include <qwt_plot_curve.h>
#include <qwt_plot.h>
#include <qapplication.h>

class SinusData: public QwtSyntheticPointData
// QwtSyntheticPointData包含在qwt_series_data.h
{
public:
    SinusData():
        QwtSyntheticPointData(100)
// 括号里的参数是在一个特定的区间所计算的点的数目
// 自然,数字越大画出来的图越平滑
    {
    }
    virtual double y(double x) const
    {
        return qSin(x);
    }
};

int main(int argc, char **argv)
{
    QApplication a(argc, argv);

    QwtPlot plot;
    plot.setAxisScale(QwtPlot::xBottom, 0.0, 10.0);
    plot.setAxisScale(QwtPlot::yLeft, -1.0, 1.0);

    QwtPlotCurve *curve = new QwtPlotCurve("y = sin(x)");
    curve->setData(new SinusData());
    curve->attach(&plot); //把曲线附加到图上
			// Qwt貌似是这样,先建立画图区域plot,然后往上面添加曲线和点

    plot.show();
    return a.exec();
}

上面的注释是我加的,因为也是刚刚接触没多久,所以用了很多”貌似”

以后准备把看过的样例发个注释版出来…

参考了

做遵纪守法的好公民

今天早上翻一本讲MySQL的书,看到许可证的问题时,明白了为什么Qt没把MySQL的driver打包进去

书上的原文是这样的:

可一旦把开发的解决方案销售给别人,许可证问题就来了.

(MySQL 5权威指南,p10)

因为诺基亚不知道你是要把Qt拿去干嘛,为了规避不必要的麻烦,就把这个麻烦丢给用户了…= =b…

MySQL是双许可的,GPL和MySQL Network,后者是一个商业许可.Qt也是,LGPL和一个商业许可.

GNU的这两个协议都是有传染性的,”出来混,迟早要还”,用了开源界的东西,就要把自己的代码也贡献给出去…LGPL稍微宽松一点,允许链接到库文件的程序不被”感染”

也就是说,基于Qt库开发的程序是允许商业发布的,而MySQL就不行,所以果断改用SQLite,因为据研究生学长说那个项目是拿去卖的…

SQLite比较共产主义,直接把代码丢到Public domain了…这是何等的觉悟啊:

The author disclaims copyright to this source code. In place of a legal notice, here is a blessing:
May you do good and not evil.
May you find forgiveness for yourself and forgive others.
May you share freely, never taking more than you give.

其它常见的许可还有BSD和Apache,都允许商业开发,没有传染性(不要求开源),只需做必要的说明和致谢就可以了…