Mac OS 安装 PIL

最近涉及一个验证码识别的项目,此个方法应也适用linux,特记录

给两个下载地址:
libjpeg:http://www.ijg.org/files/jpegsrc.v7.tar.gz
zlib: http://nchc.dl.sourceforge.net/project/libpng/zlib/1.2.8/zlib-1.2.8.tar.gz

安装libjpeg:
$ tar zxvf jpegsrc.v7.tar.gz
$ cd jpeg-7
$ ./configure –enable-shared –enable-static
$ make
$ sudo make install

默认安装在了:/usr/local/lib下。
安装zlib:
[plain] view plaincopy
$ tar zxvf zlib-1.2.7.tar.gz
$ ./configure
$ make
$ sudo make install

默认安装在了:/usr/local/lib下。
修改PIL的setup.py:
[python] view plaincopy
JPEG_ROOT = “/usr/local/include”
ZLIB_ROOT = “/usr/local/include”

编译PIL:
[python] view plaincopy
$ python setup.py build_ext -i

测试:
[python] view plaincopy
$ python selftest.py

如果提示:
[plain] view plaincopy
“57 tests passed.”

则可以安装了: python setup.py install

记录flask + gunicorn + supervisor 的配置

0、前提:安装好了python以及pip,系统环境:centos 6.5

关于gunicorn:
gunicorn可以指定多个工作进程,底层实现应该是通过调用fork函数创建子进程,这样就可以很好的利用服务器多核的特性了,实现并发功能。进程数应该指定多少呢,可以参考gunicorn官网上的一个例子:workers = multiprocessing.cpu_count() * 2 + 1。为了减少服务端的压力,对访问比较多的页面做了静态化处理(使用nginx来代理,静态资源将被cache)。

1、安装flask

为了不污染大家的开发环境,建议使用virtualenv。(python的沙箱,自行百度)
给一个必要的包LIST, 通过pip install -r requirements.txt安装:

Flask==0.10.1
Flask-Login==0.2.11
Flask-Mail==0.9.1
Flask-Moment==0.4.0
Flask-PageDown==0.1.5
Flask-SQLAlchemy==2.0
Flask-Script==2.0.5
Flask-WTF==0.10.2
Flask-Cache==0.13.1
Flask-Restless==0.15.0
Flask-Uploads==0.1.3
Jinja2==2.7.3
Mako==1.0.0
Markdown==2.5.1
MarkupSafe==0.23
SQLAlchemy==0.9.8
WTForms==2.0.1
Werkzeug==0.9.6
html5lib==1.0b3
itsdangerous==0.24
six==1.8.0
awesome-slugify==1.6

2、安装gunicorn
pip install gunicorn==19.4.1

3、关于hello.py

from flask import Flask
from werkzeug.contrib.fixers import ProxyFix

app = Flask(__name__)

@app.route(‘/’)
def hello_world():
return ‘Hello World!’

app.wsgi_app = ProxyFix(app.wsgi_app)

if __name__ == ‘__main__’:
app.run()

4、配置gunicorn.conf
workers = 5 (服务器是双核,所以2*2+1)
bind = ‘0.0.0.0:5000’
proc_name = ‘app’
pidfile = ‘/tmp/blacklist.pid’
logfile = ‘/var/log/blacklist.log’

5、supervisor的配置(root权限安装supervisor)

先说下放置沙箱环境和应用的结构:
/virtualenv/

  • /bin
    • gunicorn

/www/

  • gunicorn.conf
  • hello.py

则supervisor的配置文件为:
/etc/supervisord.conf
[include]
files = supervisord.d/*.ini

./supervisord.d/

demo.ini

[program:demo]
# 注意要让directory放在前面,至少我一开始因为这个原因一直没有成功运行
directory=/root/www
command=/root/blacklist/bin/gunicorn –config /root/www/gunicorn.conf hello:app
user=root
autostart=true
autorestart=true
stdout_logfile=/root/logs/demo.log

然后supervisorctl reload即可。

 

错误记录:

gunicorn,一定需要directory,估计跟main:app的环境有关系。

打印了日志的话,不要直接print 一些中文,貌似因为这个原因出错了,取消打印后就没问题了..

flask快速入门

对接一个项目,本身从django换到flask来,应该是差不多的东西,做点笔记吧,很久没发博了。
看一个最简单的应用:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/ching/')
def hello_ching():
    return 'Hello Ching!'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

把它保存为 hello.py 或其他类似名称并用你的 Python 解释器运行这个文件。
$ python hello.py
* Running on http://127.0.0.1:5000/

对以上代码的一个解释:
1、首先我们导入了 Flask 类。这个类的实例将会成为我们的 WSGI 应用。
2、接着我们创建了这个类的实例。第一个参数是应用模块或者包的名称。如果你使用一个单一模块(就像本例),那么应当使用 __name__ ,因为名称会根据这个模块是按 应用方式使用还是作为一个模块导入而发生变化(可能是 ‘__main__’ ,也可能是 实际导入的名称)。这个参数是必需的,这样 Flask 就可以知道在哪里找到模板和 静态文件等东西。更多内容详见 Flask 文档。
3、然后我们使用 route() 装饰器来告诉 Flask 触发函数的 URL 。
函数名称可用于生成相关联的 URL ,并返回需要在用户浏览器中显示的信息。
4、最后,使用 run() 函数来运行本地服务器和我们的应用。 if __name__ == ‘__main__’: 确保服务器只会在使用 Python 解释器运行代码的 情况下运行,而不会在作为模块导入时运行。而指明host=’0.0.0.0’则代表了让服务器监听你的主机ip。(公网ip)

调试模式:每次修改应用之后都需要手动重启服务器。这样不是很方便, Flask可以做得更好。如果你打开调试模式,那么服务器会在修改应用之后自动重启,并且当应用出错时还会提供一个有用的调试器。
app.debug = True
app.run(host=’0.0.0.0′)
即可达到调试模式的效果。或者,app.run(host=’0.0.0.0′, debug=True)

路由:非常简单清晰

app.route('/')
def index():
    return 'Index Page'

@app.route('/hello/')
def hello():
    return 'Hello World'

变量规则:配合路由使用,动态变化url变量规则
通过把 URL 的一部分标记为 就可以在 URL 中添加变量。标记的 部分会作为关键字参数传递给函数。通过使用 ,可以 选择性的加上一个转换器,为变量指定规则。请看下面的例子:

@app.route('/user/')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id

现有的转换器有:
int	接受整数
float	接受浮点数
path	和缺省情况相同,但也接受斜杠

唯一的 URL / 重定向行为
看下面这个实例:

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'

它们看上去很相近,不同之处在于 URL 定义 中尾部的斜杠。第一个例子中 prjects 的 URL 是中规中举的,尾部有一个斜杠,看起来就如同一个文件夹。访问 一个没有斜杠结尾的 URL 时 Flask 会自动进行重定向,帮你在尾部加上一个斜杠。

但是在第二个例子中, URL 没有尾部斜杠,因此其行为表现与一个文件类似。如果 访问这个 URL 时添加了尾部斜杠就会得到一个 404 错误。

为什么这样做?因为这样可以在省略末尾斜杠时仍能继续相关的 URL 。这种重定向 行为与 Apache 和其他服务器一致。同时, URL 仍保持唯一,帮助搜索引擎不重复索引同一页面。

HTTP 方法

HTTP ( web 应用使用的协议)) 协议中有访问 URL 的不同方法。缺省情况下,一个路由 只回应 GET 请求,但是可以通过 methods 参数使用不同方法。例如:

@app.route(‘/login’, methods=[‘GET’, ‘POST’])
def login():
if request.method == ‘POST’:
do_the_login()
else:
show_the_login_form()
如果当前使用的是 GET 方法,会自动添加 HEAD ,你不必亲自操刀。同时还会确保 HEAD 请求按照 HTTP RFC (说明 HTTP 协议的文档)的要求来处理,因此你可以 完全忽略这部分 HTTP 规范。与 Flask 0.6 一样, OPTIONS 自动为你处理好。

完全不懂 HTTP 方法?没关系,这里给你速成培训一下:

HTTP 方法(通常也被称为“动作”)告诉服务器一个页面请求要 做 什么。以下是常见 的方法:

GET
浏览器告诉服务器只要 得到 页面上的信息并发送这些信息。这可能是最常见的 方法。
HEAD
浏览器告诉服务器想要得到信息,但是只要得到 信息头 就行了,页面内容不要。 一个应用应该像接受到一个 GET 请求一样运行,但是不传递实际的内容。在 Flask 中,你根本不必理会这个,下层的 Werkzeug 库会为你处理好。
POST
浏览器告诉服务器想要向 URL 发表 一些新的信息,服务器必须确保数据被保存好 且只保存了一次。 HTML 表单实际上就是使用这个访求向服务器传送数据的。
PUT
与 POST 方法类似,不同的是服务器可能触发多次储存过程而把旧的值覆盖掉。你 可能会问这样做有什么用?这样做是有原因的。假设在传输过程中连接丢失的情况 下,一个处于浏览器和服务器之间的系统可以在不中断的情况下安全地接收第二次 请求。在这种情况下,使用 POST 方法就无法做到了,因为它只被触发一次。
DELETE
删除给定位置的信息。
OPTIONS
为客户端提供一个查询 URL 支持哪些方法的捷径。从 Flask 0.6 开始,自动为你 实现了这个方法。
有趣的是在 HTML4 和 XHTML1 中,表单只能使用 GET 和 POST 方法。但是 JavaScript 和未来的 HTML 标准中可以使用其他的方法。此外, HTTP 近来已经变得相当 流行,浏览器不再只是唯一使用 HTTP 的客户端。比如许多版本控制系统也使用 HTTP 。

静态文件

如果没有用nginx之类的做静态文件的代理,也可以使用flask来做。

使用选定的 ‘static’ 端点就可以生成相应的 URL 。:
url_for(‘static’, filename=’style.css’)
这个静态文件在文件系统中的位置应该是 static/style.css

渲染模板
在 Python 内部生成 HTML 不好玩,且相当笨拙。因为你必须自己负责 HTML 转义,以 确保应用的安全。因此, Flask 自动为你配置的 Jinja2 模板引擎。

使用 render_template() 方法可以渲染模板,你只要提供模板名称和需要 作为参数传递给模板的变量就行了。下面是一个简单的模板渲染例子:

from flask import render_template

@app.route(‘/hello/’)
@app.route(‘/hello/‘)
def hello(name=None):
return render_template(‘hello.html’, name=name)
Flask 会在 templates 文件夹内寻找模板。因此,如果你的应用是一个模块,那么模板 文件夹应该在模块旁边;如果是一个包,那么就应该在包里面:

情形 1: 一个模块:

/application.py
/templates
/hello.html
情形 2: 一个包:

/application
/__init__.py
/templates
/hello.html
你可以充分使用 Jinja2 模板引擎的威力。更多内容,详见官方 Jinja2 模板文档 。

centos6.5 安装python, easy-install, pip, scrapy

0. python -V
1. yum -y update
2. yum groupinstall -y development
3. yum install -y zlib-dev openssl-devel sqlite-devel bzip2-devel
4. wget http://www.python.org/ftp/python/2.7.6/Python-2.7.6.tar.xz
5. tar -xvf Python-2.7.6.tar.xz
6. cd Python-2.7.6
7. ./configure
8. make && make altinstall
9. mv /usr/bin/python /usr/bin/python2.6
10. ln -s /usr/local/bin/python2.7 /usr/bin/python
11. vi /usr/bin/yum(#!/usr/bin/python 改为 #!/usr/bin/python2.6)
12. wget –no-check-certificate https://pypi.python.org/packages/source/s/setuptools/setuptools-1.4.2.tar.gz
13. tar -xvf setuptools-1.4.2.tar.gz
14. cd setuptools-1.4.2
15. python setup.py install
16. ln -s /usr/local/bin/easy_install-2.7 /usr/bin/easy_install
17. easy_install pip
18. curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py | python2.7
19. yum -y install libxslt-devel
20. yum -y install libffi-devel (一定要先安装libffi-devel,再执行下一步)
21. pip install scrapy

监督学习(Supervised Learning)-局部线性回归(Locally Weighted Linear Regression)

线性回归的一个可能是由可能出现欠拟合现象,因为它求的是具有最小均方误差的无偏估计。显而易见,如果模型欠拟合将不能取得很好的预测效果,所以有些方法允许在估计中引入一些偏差,从而降低预测的均方误差。

其中一个方法就是lwlr,在这个方法中,给待预测点附近的每个点赋予一个权重,距离近的权重更大,然后就和之前提到的线性回归一样,求最小均方差来进行普通的回归。显而易见,这样子每次我们算的权重都会不一样(只要输入的参数不一样。)

算回归系数的式子为:

 

lmlr_e

其中:

lrlm

其中t是唯一需要我们去确认的参数,可以参考下图:

lmlr-func

 

图1是原始数据的情况,图2是t=0.5时,整个权重函数的分布情况,图3是t=0.1时,权重函数的分布情况,图4是t=0.01时,整个权重函数的分布情况。

可以看见,t越小,则离待预测点的权重影响越大,而远离预待测点的权重影响越小。

很明显,局部加权回归在每一次预测新样本时都会重新确定参数,以达到更好的预测效果。当数据规模比较大的时候计算量很大,学习效率很低。并且局部加权回归也不是一定就能避免欠拟合。

sklearn并没有提供局部加权线性回归可以直接使用的函数,所以我这里给大家提供一个python写的,数据集还是用的sklearn里面带的糖尿病人的那个数据:

__author__ = 'qing'
# -*- coding: utf8 -*-
# !/usr/bin/env python

from numpy import *
from sklearn import datasets
import matplotlib.pyplot as plt


def lwlr(testPoint, xArr, yArr, k):  #这里的k即上文的t, 为了与.T区分开
    xMat = mat(xArr); yMat = mat(yArr).T  #T是转置矩阵
    m = shape(xMat)[0]
    weights = mat(eye((m))) #创建一个单位矩阵
    for j in range(m):                      #根据该点建立权重
        diffMat = testPoint - xMat[j,:]
        weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))
    xTx = xMat.T * (weights * xMat)
    if linalg.det(xTx) == 0.0:#先检测行列式是否为0,0则不存在逆
        print "This matrix is singular, cannot do inverse"
        return
    ws = xTx.I * (xMat.T * (weights * yMat))  #I是矩阵的逆
    return testPoint * ws

def lwlrTest(testArr, xArr, yArr, k):  #loops over all the data points and applies lwlr to each one
    m = shape(testArr)[0]
    yHat = zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

# 图形化显示局部加权线性回归结果, 包括数据集及它的最佳拟合直线
def lwlrPlot(xArr, yArr, yHat):
    xMat = mat(xArr)
    srtInd = xMat[:, 3].argsort(0)
    xSort = xMat[srtInd][:, 0, :]
    # 画线
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(xSort[:, 3], yHat[srtInd])
    # 画点
    ax.scatter(xMat[:, 3].flatten().A[0],
               mat(yArr).T[:, 0].flatten().A[0],
               s=2, c='red')
    plt.show()

def rssError(yArr, yHat):
    return ((yArr - yHat)**2).sum()


if __name__ == "__main__":
    diabetes = datasets.load_diabetes()
    diabetes_X_train = diabetes.data[:-20]
    diabetes_X_test  = diabetes.data[-20:]
    diabetes_y_train = diabetes.target[:-20]
    diabetes_y_test  = diabetes.target[-20:]
    lwlrResult = lwlrTest(diabetes_X_test, diabetes_X_train, diabetes_y_train, 0.14)
    print diabetes_y_test
    print lwlrResult
    print corrcoef(lwlrResult, diabetes_y_test)
    print rssError(lwlrResult, diabetes_y_test)
    lwlrPlot(diabetes_X_test, diabetes_y_test, lwlrResult)

最后我们可以看到,相关性的结果以及差平方和是:

[[ 1. 0.75591378]
[ 0.75591378 1. ]]

55830.0971546

plot
以及可以看到lwlr得到的拟合效果(对未知数据的预测,这里我任意选取了输入的一个特征作为横坐标)

代码开放在:

 https://github.com/ching1221/machine-learning

 

监督学习(Supervised Learning)-线性回归(Linear Regression)

打算开个系列把机器学习的基础算法都用心走一遍,顺手记录点东西,配套使用python的scikit-learn包。

先简要介绍下这个包,http://scikit-learn.org/stable/

About scikit-learn:

  • Simple and efficient tools for data mining and data analysis
  • Accessible to everybody, and reusable in various contexts
  • Built on NumPy, SciPy, and matplotlib
  • Open source, commercially usable – BSD license

要义:开源,机器学习、数据分析工具包,需要预装numpy,scipy,matplotlib等模块

scikit-learn的基本功能主要被分为六个部分,分类,回归,聚类,数据降维,模型选择,数据预处理。

今天先介绍它回归这一部分的功能。

线性回归

优点:结果易理解,计算不复杂。

缺点:对非线性数据拟合地不好。

适用数据类型:数值型以及标称型。

比如:你可能这样子来预测一个人的学习的成效:

score = 0.7*timeSpendOnStudy + 0.3*Gift

这就是一个回归方程,0.7和0.3在这里称为回归系数,我们利用一堆已知输入输出来求回归系数的过程就叫回归。

有了这些回归系数后,用回归系数乘以输入值,再将结果加在一起,就可以得到预测值了。

回归的一般方法

1、收集数据。

2、准备数据,回归需要数值型数据,标称型数据需要先转成二值型数据。

3、分析数据,数据可视化将有助于对数据做出理解和分析,在采用缩减法(shrinkage)求得新回归系数之后可以将新旧曲线绘在图上作对比。

4、训练算法:找到回归系数。

5、测试算法:使用R^2或者预测值和数据的拟合度,来分析模型的效果。

6、使用算法。

算法:

关于线性回归的最小二乘法矩阵求法,参考这篇博文,不再造轮子:http://blog.csdn.net/acdreamers/article/details/44662633

(为什么这样做,可以参考这片博文:http://blog.csdn.net/acdreamers/article/details/44662823

最后推导的结果:

lm_result

 

x为m组*n个自变量输入的m*n维矩阵,y为m*1的对应因变量输出,得到n*1的参数矩阵,即利用最小二乘法得到的最佳参数估计。

数据:

sklearn自带的糖尿病人的一些数据:

该数据集包含了442个病人的10项特征(年龄,性别,体重,血型等),以及一年后他们的疾病指数。

程序:

import numpy as np
from sklearn import linear_model
from sklearn import datasets


diabetes = datasets.load_diabetes()
diabetes_X_train = diabetes.data[:-20]
diabetes_X_test  = diabetes.data[-20:]
diabetes_y_train = diabetes.target[:-20]
diabetes_y_test  = diabetes.target[-20:]
lm = linear_model.LinearRegression()
lm.fit(diabetes_X_train, diabetes_y_train)
print(lm.coef_)
# The mean square error
print np.mean((lm.predict(diabetes_X_test)-diabetes_y_test)**2)

 # Explained variance score: 1 is perfect prediction
 # and 0 means that there is no linear relationship
 # between X and Y.
print lm.score(diabetes_X_test, diabetes_y_test)

结果:

系数:

[ 3.03499549e-01

-2.37639315e+02

5.10530605e+02

3.27736980e+02

-8.14131709e+02

4.92814588e+02

1.02848452e+02

1.84606489e+02
7.43519617e+02

7.60951722e+01]

方差:
2004.56760269

预测的准确率:

0.585075302269

 

再给一个有趣的测试,用线性回归来做图像处理:

数据:

uci提供的钢笔手写数字的图像(8*8图像矩阵, 0-16的像素值)和对应的识别结果

http://archive.ics.uci.edu/ml/datasets/Pen-Based+Recognition+of+Handwritten+Digits

程序:

from sklearn import datasets
from sklearn.linear_model import LinearRegression

digits = datasets.load_digits()  # 自带上述数据

trainingInput = digits.data[:1300]  # 数据一共有1797条,抽取前1300行作为训练数据
trainingOutput = digits.target[:1300]
testInput = digits.data[1300:]
testOutput = digits.target[1300:]
lm = LinearRegression()
lm.fit(trainingInput, trainingOutput).score(trainingInput, trainingOutput)  # 训练数据
print lm.predict(testInput) # 预测结果
print "the accurate is: " + str(lm.score(testInput, testOutput))  # 输出准确率

然而你会发现,这两个例子用线性回归做的效果并不好,准确率很低。后面将用其他机器学习的方法去做测试。

 

代码开放在:

 https://github.com/ching1221/machine-learning

python 多线程处理 - thread

Python 标准库提供了 thread 和 threading 两个模块来对多线程进行支持。其中, thread 模块以低级、原始的方式来处理和控制线程,而 threading 模块通过对 thread 进行二次封装,提供了更方便的 api 来处理线程。 虽然使用 thread 没有 threading 来的方便,但它更灵活。先介绍 thread 模块的基本使用,之后再说threading

学习代码时说道理并没有什么卵用,先来一段代码:

# -*- coding: utf8 -*-
import thread, time
def threadFunc(a = None, b = None, c = None, d = None):
    print time.strftime('%H:%M:%S', time.localtime()), a
    time.sleep(1)
    print time.strftime('%H:%M:%S', time.localtime()), b
    time.sleep(1)
    print time.strftime('%H:%M:%S', time.localtime()), c
    time.sleep(1)
    print time.strftime('%H:%M:%S', time.localtime()), d
    time.sleep(1)
    print time.strftime('%H:%M:%S', time.localtime()), 'over'

thread.start_new_thread(threadFunc, (3, 4, 5, 6))   #创建线程,并执行threadFunc函数。
thread.start_new_thread(threadFunc, (3, 4, 5, 6))   #创建线程,并执行threadFunc函数。
time.sleep(5)
thread.exit()
然后你会看到打印的信息,可以判断这两次函数的运行几乎是同时执行的。

在上面这个示例中,这两个函数分别是:

thread.start_new_thread ( function , args [ , kwargs ] )

函数将创建一个新的线程,并返回该线程的标识符(标识符为整数)。参数 function 表示线程创建之后,立即执行的函数,参数 args 是该函数的参数,它是一个元组类型;第二个参数 kwargs 是可选的,它为函数提供了命名参数字典。函数执行完毕之后,线程将自动退出。如果函数在执行过程中遇到未处理的异常,该线程将退出,但不会影响其他线程的执行。

thread.exit ()

结束当前线程。调用该函数会触发 SystemExit 异常,如果没有处理该异常,线程将结束。

thread.interrupt_main ()

在主线程中触发 KeyboardInterrupt 异常。子线程可以使用该方法来中断主线程。下面的例子演示了在子线程中调用 interrupt_main ,在主线程中捕获异常 :

import thread, time
thread.start_new_thread(lambda : (thread.interrupt_main(), ), ())
try:
    time.sleep(2)
except KeyboardInterrupt, e:
    print 'error:', e
print 'over'


在我们处理多个客户端请求时,一般都会遇到某个资源是被所有客户共用的,比如在抢购时,涉及到某一件商品的数量修改,我们希望同时只有一个人可以在进行这个操作,那我们就需要用到锁机制。下面介绍 thread 模块中的琐,琐可以保证在任何时刻,最多只有一个线程可以访问共享资源。

thread.LockType 是 thread 模块中定义的琐类型。它有如下方法:

lock.acquire ( [ waitflag ] )

获取琐。函数返回一个布尔值,如果获取成功,返回 True ,否则返回 False 。参数 waitflag 的默认值是一个非零整数,表示如果琐已经被其他线程占用,那么当前线程将一直等待,只到其他线程释放,然后获取访琐。如果将参数 waitflag 置为 0 ,那么当前线程会尝试获取琐,不管琐是否被其他线程占用,当前线程都不会等待。

lock.release ()

释放所占用的琐。

lock.locked ()

判断琐是否被占用。

在进行锁机制具体的实现之前,我先引入一个没有使用锁的程序给大家看看:

import thread, time, random
count = 0
def threadTest():
    global count
    for i in xrange(10000):
        count += 1
for i in range(10):
    thread.start_new_thread(threadTest, ()) 
time.sleep(3)
print count 

粘贴进入你的ide中,然后看看结果,是100000吗?我想答案是no,多运行几次呢,我想结果也是不一样的,读下代码呢,它将全局变量逐一的增加 10000 ,然后在主线程中开启了 10 个子线程来调用 threadTest 函数。但结果并不是预料中的 10000 * 10 ,原因主要是对 count 的并发操作引来的。全局变量 count 是共享资源,对它的操作会串行的进行。

下面对这段代码进行修改,在对 count 操作的时候,进行加锁处理。看看程序运行的结果是否和预期一致。修改后的代码:
count = 0
lock = thread.allocate_lock() # 创建一个锁对象
def threadTest():
    global count, lock
    lock.acquire() # 获取锁
    for i in xrange(10000):
        count += 1
    lock.release() # 释放锁
for i in xrange(10):
    thread.start_new_thread(threadTest, ())
time.sleep(3)
print count

是不就是100000了?

python – MySQLdb 基本操作

import MySQLdb
//连接
conn = MySQLdb.connect(host=’localhost’, user=’root’, passwd=”, port=3306)
//获取游标
cur = conn.cursor()
//执行sql语句
cur.execute(sql)
//执行多条sql语句
cur.executemany(sql, values)
//插入数据时光有execute是不行滴,一定要commit(),否则无效

cur.execute(sql)
for row in cur.fetchall():
    print row[0], row[1]

//一个简单的查询后的使用方法

conn.commit()
//关闭游标
cur.close()
//关闭数据库连接
conn.close()

Django- 表单

对于一个在线选题网站来说,那必须得有数据提交到服务器

那么肯定是要用到表单的。

从Request对象中获取数据

前面我们写过如下的代码:

from django.http import HttpResponse

def hello(request):
    return HttpResponse("Hello world")
很明显,这里的request我们是没有用到的。

URL相关信息

HttpRequest对象包含当前请求URL的一些信息:

属性/方法 说明 举例
request.path 除域名以外的请求路径,以正斜杠开头 "/hello/"
request.get_host() 主机名(比如,通常所说的域名) "127.0.0.1:8000" or"www.example.com"
request.get_full_path() 请求路径,可能包含查询字符串 "/hello/?print=true"
request.is_secure() 如果通过HTTPS访问,则此方法返回True, 否则返回False True 或者 False

有关request的其它信息

request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP地址和用户Agent(通常是浏览器的名称和版本号)。 注意,Header信息的完整列表取决于用户所发送的Header信息和服务器端设置的Header信息。 这个字典中几个常见的键值有:

  • HTTP_REFERER,进站前链接网页,如果有的话。 (请注意,它是REFERRER的笔误。)

  • HTTP_USER_AGENT,用户浏览器的user-agent字符串,如果有的话。 例如:"Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17" .

  • REMOTE_ADDR 客户端IP,如:"12.345.67.89" 。(如果申请是经过代理服务器的话,那么它可能是以逗号分割的多个IP地址,如:"12.345.67.89,23.456.78.90" 。)

 

POST  和 GET,这个其实我在以前学PHP的时候就已经接触过了,包括之前说HTTP协议的时候,也分析过,所以不再赘述。

除了基本的元数据,HttpRequest对象还有两个属性包含了用户所提交的信息: request.GET 和 request.POST。二者都是类字典对象,你可以通过它们来访问GET和POST数据。

比如我通过post传了一个bookid=3的一对键值,那么我可以通过request.POST[‘bookid’]来获取。

类字典对象

我们说“request.GET和request.POST是类字典对象”,意思是他们的行为像Python里标准的字典对象,但在技术底层上他们不是标准字典对象。 比如说,request.GET和request.POST都有get()、keys()和values()方法,你可以用用 for key in request.GET 获取所有的键。

那到底有什么区别呢? 因为request.GET和request.POST拥有一些普通的字典对象所没有的方法。 我们会稍后讲到。

你可能以前遇到过相似的名字:类文件对象,这些Python对象有一些基本的方法,如read(),用来做真正的Python文件对象的代用品。

POST数据是来自HTML中的〈form〉标签提交的,而GET数据可能来自〈form〉提交也可能是URL中的查询字符串(the query string)。

在做完post请求之后我们应该使用django.http中的HttpResponseRedirect来做重定向:

return HttpResponseRedirect('/contact/thanks/')

原因就是: 若用户刷新一个包含POST表单的页面,那么请求将会重新发送造成重复。 这通常会造成非期望的结果,比如说重复的数据库记录;若用户刷新一次,如果是在收集表单数据,则数据库中会得到2次同样的结果,但 如果用户在POST表单之后被重定向至另外的页面,就不会造成重复的请求了。

我们应每次都给成功的POST请求做重定向。 这就是web开发的最佳实践。