Skip to content Skip to main navigation Skip to footer

python

python中复制和引用用法实例

本文主要讲述如何在python中使用复制和引用,并通过实例演示python引用和复制的用法。

本文实例讲述了python中引用与复制用法。分享给大家供大家参考。具体分析如下:

在python中,任何不可变对象是传值的,而可变对象是传引用的。

不管是向函数传递参数或者是任何形式的对象复制来说,不可变对象(比如整数,字符串)被真正复制,而可变对象只是复制了一个对他们的引用,即在内存中只有一份对象,而引用两份。
 
a=b 这样的赋值,就会创建对b的引用,对于象数字和字符串这样的不可变的对象,这种赋值实际是创建了b的一个副本

>>> a='hello'
>>> b=a
>>> id(a)
29326432
>>> id(b)
29326432
>>> b is a
True
>>> a=1000
>>> b
'hello'
 

对于可变对象,比如字典和列表,a和b引用的是同一个对象,修改其中任意一个变量都会影响到另一个。

>>> a=[1,2,3,4]
>>> b=a
>>> id(a)
29280896
>>> id(b)
29280896
>>> b[3]='ccccccccc'
>>> a
[1, 2, 3, 'ccccccccc']
>>>
 

列表和字典这样的容器对象,可以使用两种赋值操作:浅复制和深复制。浅复制创建一个新对象,但它包含的是对原始对象中包含的项的引用。

比如下面的浅复制:

>>> a=[1,2,3,4,[9,0]]
>>> b=a
>>> a=[1,2,3,4,[9,0]]
>>> b=list(a)
>>> b is a
False
>>> b[0]=1000
>>> b
[1000, 2, 3, 4, [9, 0]] #注意,b修改了b[0]以后,对a没有影响
>>> a
[1, 2, 3, 4, [9, 0]]
>>> b[4][1]='cccc'  #注意,b修改了 b[4][1]以后,对a有影响
>>> b
[1000, 2, 3, 4, [9, 'cccc']]
>>> a
[1, 2, 3, 4, [9, 'cccc']]
 

深复制将创建一个新对象,并且递归的复制它包含的所有对象,没有内置对象可以创建深复制,可以使用copy.deepcopy()函数完成。

>>> import copy
>>> a=[1,2,3,[4,5]]
>>> b=copy.deepcopy(a)
>>> id(b)
29582240
>>> id(a)
29581840
>>> a is b
False
>>> b[0]=1000
>>> b
[1000, 2, 3, [4, 5]] #注意修改了b[0]之后对a没有影响
>>> a
[1, 2, 3, [4, 5]]
>>> b[3][1]='gggg'
>>> b
[1000, 2, 3, [4, 'gggg']] #修改了 b[3][1]之后对a也没有影响,这是和浅复制的区别
>>> a
[1, 2, 3, [4, 5]]
 

希望本文所述对大家的Python程序设计有所帮助。


python中引用和复制的用法就这样,欢迎大家参考。。。。

Python: 【译】Python的优雅技巧

枚举

不要这么做:

i = 0
for item in iterable:
    print i, item
    i += 1

而是这样:

for i, item in enumerate(iterable):
    print i, item

Enumerate可以接受第二个参数,例如:

>>> list(enumerate('abc'))
[(0, 'a'), (1, 'b'), (2, 'c')]
>>> list(enumerate('abc', 1))
[(1, 'a'), (2, 'b'), (3, 'c')]
 

字典/集合 解析

你可能知道列表解析,但不知道字典/集合解析。字典/集合解析简单而且高效,例如:

my_dict = {i: i * i for i in xrange(100)}
my_set = {i * 15 for i in xrange(100)}
# There is only a difference of ':' in both
 

强制浮点数除法

如果我们除以一个整数,即使结果是一个浮点数,Python(2) 依旧会给我们一个整数。为了规避这个问题,我们需要这样做:

result = 1.0/2

但是现在有一种别的方法可以解决这个问题,甚至在之前我都没有意识到有这种方法存在。你可以进行如下操作:

from __future__ import division
result = 1/2
# print(result)
# 0.5
 

需要注意的是这个窍门只适用于Python 2。在Python 3 中就不需要进行import 操作了,因为它已经默认进行import了。

简单的服务器

你想快速简单的分享目录下的文件吗?可以这样做:

# Python2
python -m SimpleHTTPServer
# Python 3
python3 -m http.server
 

这回启动一个服务器

Python表达式求值

我们都知道 eval,但也许并不是所有人都知道 literal_eval.可以这么做:

import ast
my_list = ast.literal_eval(expr)

而不是这样:

expr = "[1, 2, 3]>"
my_list = eval(expr)

我相信对于大多数人来说这种形式是第一次看见,但是实际上这个在Python中已经存在很长时间了。

分析脚本

按下面的方式运行脚本,可以很简单的对其进行分析:

python -m cProfile my_script.py

对象自检

在Python中,可以通过dir()来检查对象,例如:

>>> foo = [1, 2, 3, 4]
>>> dir(foo)
['__add__', '__class__', '__contains__',
'__delattr__', '__delitem__', '__delslice__', ... ,
'extend', 'index', 'insert', 'pop', 'remove',
'reverse', 'sort']
 

调试脚本

你可以使用 pdb模块在脚本中设置断点来调试脚本,就像这样:

import pdb
pdb.set_trace()

你可以在脚本的任何地方加入 pdb.set_trace(),该函数会在那个位置设置一个断点。超级方便。你应该多阅读 pdb
函数的相关内容,因为在它里面还有很多鲜为人知的功能。

简化if结构

如果必须检查一些值,可以用

if n in [1,4,5,6]:

而不是用复杂的if结构:

if n==1 or n==4 or n==5 or n==6:

字符串/数列 逆序

下面的方式可以快速反转一个列表:

>>> a = [1,2,3,4]
>>> a[::-1]
[4, 3, 2, 1]
# This creates a new reversed list.
# If you want to reverse a list in place you can do:
a.reverse()
 

这种方式同样适用于字符串:

>>> foo = "yasoob>"
>>> foo[::-1]
'boosay'
 

优雅地打印

下面的方式可以用优雅的方式打印字典和列表:

from pprint import pprint
pprint(my_dict)

这用于字典打印是非常高效的,如果你想从文件中快速优雅的打印出json,可以这样做:

cat file.json | python -m json.tools

三元运算

三元运算是if-else 语句的快捷操作,也被称为条件运算。这里有几个例子可以供你参考:

[on_true] if [expression] else [on_false] x, y = 50, 25
small = x if x < y else y [/code]

译文出处: http://www.ido321.com/1576.html

本文根据@Nicolas Bevacqua的 《nifty-python-tricks》
所译,整个译文带有我自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: https://freepythontips.wordpress.com/2015/04/19/nifty-python-tricks/

原文:http://segmentfault.com/a/1190000002869103

Python: python实现grep查找功能

写这个程序的原因是Windows下的搜索功能不好用,有尝试过下载一下小工具来补偿搜索功能,但都不尽如人意,所以就干脆自己写一个了.

功能:在任何装有python2.7(或2.7以上3.0以下版本)的机器上运行文件名搜索、文件内容搜索.

代码 grep.py:

import os
import re
import argparse
def inred( s ):
	return"%s[31;2m%s%s[0m>"%(chr(27), s, chr(27))
def parseInput():
	parser = argparse.ArgumentParser()
	parser.add_argument("-p>", nargs='*')
	parser.add_argument('-s',nargs='*')
	parser.add_argument('-k',nargs='*')
	args = parser.parse_args()
	return args.p, args.s, args.k
def searchFile(mfile,patterns):
	fr = open(mfile,'r')
	line_num = 0
	flag = True
	while True:
		line = fr.readline()
		line_num += 1
		if line:
			for eachp in patterns:
				if(eachp.findall(line)):
					if flag:
						print mfile
						flag = False
					print "line>",line_num,line,
		else:
			break
	if not flag:
		print ">"
if __name__ == "__main__>":
	mpaths,filefilters,mkeys = parseInput()
	if mpaths == None:
		mpaths = [os.getcwd()]
	print "Search paths:>",mpaths
	print "File filters:>",filefilters
	print "Search keys:>",mkeys
	print ">"
	file_pattern = []
	key_pattern = []
	if filefilters:
		for eachff in filefilters:
			file_pattern.append(re.compile(eachff,re.I))
	if mkeys:
		for eachkey in mkeys:
			key_pattern.append(re.compile(eachkey,re.I))
	for eachp in mpaths:
		list_dirs = os.walk(eachp)
		for root, dirs, files in list_dirs:
			for f in files:
				if filefilters != None:
					for eachfp in file_pattern:
						if(eachfp.findall(f)):
							fname = os.path.join(root, f)
							if mkeys != None:
								searchFile(fname,key_pattern)
							else:
								print fname
							break
				elif mkeys != None:
					fname = os.path.join(root, f)
					searchFile(fname,key_pattern)
				else:
					print 'USAGE: -p paths -s file_filters(must be regular expression) -k keys(must be regular expression)'
					quit()
 

用法:

首先确保你的电脑有安装 python27

将grep.py文件放入有被设为环境变量的文件夹,这样可以直接在命令行运行命令.

然后打开命令行,去到你想搜索的目录(或者-p ),运行:

grep.py -p <you_dir> -s <file_filter_re_pattern> -k <key_word_re_pattern> 

这样就可以查找指定目录下的文件内容,如果你的命令行已经在该目录,则-p选项可选,如果不指定文件名过滤,-s选项可选.如果想直接搜索文件名则可省去-k选项

grep.py -p  -s 

另外,-s和-k选项支持正则表达式,所以要注意使用转义符号,各个选项都支持多参数.

原文:http://linxianyan.cn/python实现linux下grep查找功能/

Python: Python |(基础)函数默认参数必须指向不可变对象

测试

Python 默认参数提高了变成效率,但是这里面的坑也是坑死人不偿命,使用稍微不正确,会造成致命的失误

#!/usr/bin/env python
# -*- coding: utf-8 -*-
def test(lang=[]):
  lang.append('python')
  return lang
 

当老实调用时,结果如你所愿

print(test(['js','go']))
print(test(['c','java']))

结果如下

['js', 'go', 'python']
['c', 'java', 'python']
[Finished in 0.1s]
 

但是如果多次使用默认参数调用时,奇迹出现了

print(test())
print(test())

结果如下:

['python']
['python', 'python']
[Finished in 0.1s]

或许有人对此感到很困惑,为什么默认参数会记住更新过的默认参数

分析:

函数在定义的时候,默认参数 lang的值就已经声明了,即空的 [],也就是说 默认参数指向对象 [],在多次调用默认参数的情况下,就改变了 默认参数指向对象的数据, 默认参数指向对象的数据变了,下次再调用时,默认参数已经变了,即不再是你希望的空的 []

为了便于理解等同下面这段:

temp = []
def test(lang=temp):
  lang.append('python')
  return lang
 

这样就好看多了,多次调用时, temp也在不断的变化

注意函数默认参数和函数中的参数的上下文环境

结论

定义函数默认参数时,函数默认参数必须指向不变对象,建议使用 None,str 这些不可变对象处理

重新修改代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
def test(lang=None):
  if lang is None:
    lang = []
  lang.append('python')
  return lang
 

调用

print(test())
print(test())

结果:

['python']
['python']
[Finished in 0.2s]

原文:http://segmentfault.com/a/1190000002869653

Python: Django搭建及源码分析(三)—+uWSGI+nginx

每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的。如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当你将一个框架的优势使用到极致时一定是非常舒服和顺手的一件事。但同时也有可能衍生另一个问题,这个框架只解决了你的问题一,没有解决问题二、三等等,因此,就出现了多个框架/应用相结合的情况。比如Django + uWSGI + nginx。

本人初学python,找了一些实例进行了一些操作,以下纯属目前的理解,如有偏差,欢迎修正。

一、关于Django、uwsgi、nginx这三者关系的理解。

Django是一个WEB框架。所谓WEB框架,那么一定是搭建了一些模型,在安装完框架后,可以很方便的调用框架的方法,实现web功能。Django的特点在于MVC,模型–视图–控制。关于MVC不同的框架有不同的定义,不用纠结去统一MVC的定义,只需要理解各个框架自身的设计的特点的优势。关于Django框架,M模型:指的的数据库模型的管理(对于Django更多的在数据库相关的应用程序开发上有一点的优势);V视图:指的是如何根据业务需求来显示M中的哪些数据,更多是与业务相关;C控制:指的是用户访问的浏览器的地址与视图的映射关系。由于C比较简单已经由Django封装好了,基本上只用按正则表达示写一些类似配置文件的东西即可。而人们说到MVC时一般会有一个表示层,即业务数据在页面如果显示,以表格还是其它方式,表格的样式如何等等,该层在Django中也可被称为T模板,被合并到V中。所以使用Django,我们一般关心的是MTV的管理。

既然Django其重点在于MVC的模架管理,虽然也可以使用Django完成WEB服务器的功能(执行命令 python manage.py runserver),但是仅仅是在测试环境中使用,对于要求稳定性和性能的生产环境,它无法达到。因此需要加入uWSGI。wsgi是一种协议,仅仅是协议并未实现,而uwsgi也是一种协议,两者有所不同。而uWSGI就是使用python将wsgi与uwsgi进行实现的WEB服务器,Django + uWSGI其WEB服务器的功能要更优于Django本身自带的web服务器。

那么有了uWSGI为什么还需要nginx?因为nginx具备优秀的静态内容处理能力,然后将动态内容转发给uWSGI服务器,这样可以达到很好的客户端响应。

二、环境搭建。

1、安装Django。

关于Django的使用网上资料很多,本人选择了两个比较合适的资料进行了实战操作,觉得不错。可参见”Django搭建及源码分析(一)“,提到了搭建方法和,参考资料。下面进入本节主题。

本人的系统环境centos6.0、python2.6、Django1.6,虽然都比较老了,但是不影响了解事物的本质的特点。继续…

2、安装uWSGI。

Django环境的搭建与配置请参见"Django搭建及源码分析(一)“,在保证Django可以访问之后,加入uWSGI。

使用 pip install uwsgi

我安装的是uwsgi 2.0.1版本。

3、验证uWSGI是否安装成功。

新建test.py文件,内容如下:

def  application(env, start_response):
    start_response( ' 200 OK ' , [(' Content-Type ' ,' text/html ' )])
     return  " Hello World >"  

执行
uwsgi

http
:
8000
 

wsgi

file test
. py

在浏览器内输入:http://ip:8001,查看是否有”Hello World>”输出,若没有输出,请检查你的安装过程。

4、验证Django+uWSGI是否连接成功。

uwsgi –http :8000 –wsgi-file /home/MyDjProj/MyDjProj/wsgi.py

将test.py修改为Django项目中生成的wsgi.py,通过浏览器访问Django框架中的页面,成功。则说明两者连接正常。

5、安装nginx。

下载自已喜欢的nginx版本,我下的是当前最新稳定版nginx-1.8.0.tar.gz。

./
configure

prefix
=
/usr/
local
/
nginx

1.8




with

http_stub_status_module

with
http_gzip_static_module

make
&& make install

6、配置uwsgi

uwsgi支持ini、xml等多种配置方式,本文以 ini 为例在/etc下创建uwsgi8000.ini

[ uwsgi ]
socket  = 127.0.0.1:8000
master  = true         //主进程
vhost  = true          //多站模式
no-stie  = true        //多站模式时不设置入口模块和文件
workers  = 2           //子进程数
reload-mercy  = 10
vacuum  = true         //退出、重启时清理文件
max-requests  = 1000
limit-as  = 512
buffer-size  = 30000
pidfile  = /var/run/uwsgi8000.pid    //pid文件,用于下面的脚本启动、停止该进程
daemonize  = /var/log/uwsgi8000.log  //日志文件
pythonpath  = /usr/lib/python2.6/site-packages //同环境变量PYTHONPATH 

7、配置nginx

找到nginx的安装目录(如:/usr/local/nginx-1.8/),打开conf/nginx.conf文件,修改server配置:

	server {
		listen	    80;
 		server_name  localhost;
		#charset koi8-r ;
		#access_log  logs/host.access.log  main ;
		location /{
			include  uwsgi_params ;
 			uwsgi_pass 127.0.0.1:8000;			//必须和uwsgi中的设置一致
 			uwsgi_param UWSGI_SCRIPT MyDjProj.wsgi;	//入口文件,即wsgi.py相对于Django项目根目录的位置,“.”相当于一层目
 			uwsgi_param UWSGI_CHDIR /home/MyDjProj;	//Django项目根目录
 			index index.html index.htm;
 			client_max_body_size 35m;
 		}
 

8、测试Django + uwsgi + nginx

uwsgi

ini
/
etc
/
uwsgi8000
.
ini
&

/usr/
local
/
nginx-1.8
/
sbin
/ nginx

在浏览器输入:http://ip/,你就可以看到django的”It work>”了。http://ip/hello,可以打开Django项目中,通过urlconf配置的hello子页面的view视图

三、遇到的问题。

1、在连接Django与uwsgi时(










uwsgi –http :8000 –wsgi-file /home/MyDjProj/MyDjProj/wsgi.py
),报出“ImportError: Could not import settings ‘MyDjProj.settings’ (Is it on sys.path? Is there an import error in the settings file?): No module named MyDjProj.settings”

可以看出执行时,在sys.path中无法找到MyDjProj.settings,需要所/home/MyDjProj加入到sys.path中即可,加入方法有很多,在此我使用的是export PYTHONPATH=$PYTHONPATH:/home/MyDjProj,加入后,再访问即可。
>

在连接Django、uwsgi和nginx时,sys.path不受环境变量PYTHONPATH的影响,也会自动将nginx配置中的项目根目录加入到sys.path中,因此在后续步骤中此问题不影响三者连接。

2、在连接Django、uwsgi和nginx时,报出File “./MyDjProj/wsgi.py>”, line 17, in from django.core.wsgi import get_wsgi_application ImportError: No module named django.core.wsgi

可以看出在

3、遇到其它问题时,先判断端口是否正常打开,使用netstat -plnt查看。

4、修改后配置后,最好关闭uwsgi及nginx后,重新连接。关闭方法:fuser -k 端口/tcp。如:fuser -k 80/tcp; fuser -k 8000/tcp
>

5、多查看日志文件,文件中详细的报错信息,对于nginx的日志,可以通过在nginx.conf中配置error_log  /var/log/nginx_error.log info;将出错信息打印到该文件中便于定位。

原文:http://www.cnblogs.com/fangyuan1004/p/4546567.html

Python: 深入 Python 3

当前位置:

深入 Python 3

《深入 Python 3》
的内容涵盖了 Python 3 及其与 Python 2 的区别。相对 《深入 Python》
而言,它 20% 的内容进行了修订,80% 的内容是全新的。这本书现在已经完成了,但随时欢迎反馈意见。

目录 (展开)

  1. 《深入 Python 3》中有何新内容
  2. 安装 Python
  3. 第一份 Python 程序
  4. 内置数据类型
  5. 理解
  6. 字符串
  7. 正则表达式

  8. 闭合
    生成器

  9. &
    迭代器
  10. 高级迭代器
  11. 单元测试
  12. 重构
  13. 文件
  14. XML
  15. Python 对象序列化
  16. HTTP Web 服务

  17. 案例研究:将 chardet移植到 Python 3
  18. Python 类库打包

  19. 使用 2to3将代码移植到 Python 3
  20. 特殊方法名称
  21. 接下来阅读什么?

本书遵循Creative Commons Attribution Share-Alike协议自由授权。您可选择下载
HTML
或是
PDF
版本。尤伯爱好者还可从水银仓库(Mercurial repository)进行克隆:

<samp class="p">you@localhost:~$ </samp><kbd>hg clone <a href="http://hg.diveintopython3.org"></a>http://hg.diveintopython3.org/ diveintopython3</kbd> 

本书为 Lynx 优化仅仅是因为你 *** 。我被告知它在图形化浏览器中看起来也很美观。

© 2001–9Mark Pilgrim

译文: 西班牙语意大利语

漏洞目录,漏洞,Discuz,nginx,DedeCms,phpcms,Ranking, toazamac

原文:http://sebug.net/paper/books/dive-into-python3/index.html

Python: 一个python爬虫小程序

起因

深夜忽然想下载一点电子书来扩充一下kindle,就想起来python学得太浅,什么“装饰器”啊、“多线程”啊都没有学到。

想到廖雪峰大神的python教程很经典、很著名。就想找找有木有pdf版的下载,结果居然没找到!!CSDN有个不完整的还骗走了我一个积分!!尼玛!!

怒了,准备写个程序直接去爬廖雪峰的教程,然后再html转成电子书。

过程

过程很有趣呢,用浅薄的python知识,写python程序,去爬python教程,来学习python。想想有点小激动……

果然python很是方便,50行左右就OK了。直接贴代码:

#  coding:utf-8
import  urllib
domain  = ' http://www.liaoxuefeng.com '  # 廖雪峰的域名
path = r' C:Userscyhhao2013Desktoptemp\ '  # html要保存的路径
#  一个html的头文件
input = open(r' C:Userscyhhao2013Desktop.html ' , ' r ' )
head  = input.read()
 #  打开python教程主界面
f = urllib.urlopen(" http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000 >" )
home  = f.read()
f.close()
 #  替换所有空格回车(这样容易好获取url)
geturl = home.replace(" n >" , ">" )
geturl  = geturl.replace("  >" , ">" )
 #  得到包含url的字符串
list = geturl.split(r' em;"><ahref=>" ' )[1:]
 #  强迫症犯了,一定要把第一个页面也加进去才完美
list.insert(0, ' /wiki/001374738125095c955c1e6d8bb493182103fac9270762a000"> ' )
 #  开始遍历url List
for  li in  list:
	url  = li.split(r' >"> ' )[0]
	url  = domain + url			  # 拼凑url
print  url
	f  = urllib.urlopen(url)
	html  = f.read()
	 #  获得title为了写文件名
	title = html.split(" <title> >" )[1]
	title  = title.split("  - 廖雪峰的官方网站</title> >" )[0]
	 #  要转一下码,不然加到路径里就悲剧了
	title = title.decode(' utf-8 ' ).replace(" / >" , "  >" )
	 #  截取正文
	html = html.split(r' <!-- block main --> ' )[1]
	html  = html.split(r' <h4>您的支持是作者写作最大的动力!</h4> ' )[0]
	html  = html.replace(r' src=" ' , ' src=>" '  + domain)
	 #  加上头和尾组成完整的html
	html = head + html+" </body></html> >"
#  输出文件
	output = open(path + " %d >"  % list.index(li) + title + ' .html ' , ' w ' )
	output.write(html)
	output.close()
 

简直,人生苦短我用python啊!

最后

附上HTML转epub电子书格式在线链接: html.toepub.com

以及廖雪峰的教程: 链接廖雪峰的Git教程也非常非常的不错哦~

顺便扩充一下自己的→_→ GitHub(爬下来的html也在github上哦~)

以及个人博客: http://blog.zhusun.in/cyhhao

原文来自: 一个python爬虫小程序

by:cyhhao http://blog.zhusun.in/cyhhao/

原文:http://www.cnblogs.com/cyhhao/p/4501022.html

Python: python实现influxdb的orm对象关系映射模型

对于数据库操作的时候,我个人特别的倾向于用ORM这种对象映射模型, 可以让你最舒服的操作数据库,另外也可以最简单的实现数据库…    比如我写后端服务的时候,如果用mysqldb,那么想当的蛋疼…    来来回回的折腾的,在大量的参数下,很有可能会出各种各样的低级的问题…   如果你用python的peewee这种基于mysqldb的orm模型,那么会想当干练的操作mysql数据库。 

最近被几个网站爬了,真特么郁闷….   标注下,文章的原文链接是  

http://xiaorui.cc     http://xiaorui.cc/?p=1427

在github上,看到一个帅哥老外分享的一个关于python influxdb orm的数据操作模型 , 代码虽然写的还很是精简干练 ,  但是具体的功能也算是实现了。   其实这orm底层调用的也是python的influxdb接口,期初以为他的实现应该是语法树ast那种。  下面是他的项目,有兴趣的朋友也看下他的实现,还是有些灵巧的。 

https://github.com/unaizalakain/qinfluxdb

qinfluxdb的安装配置 ~

Python

pip install git+https://github.com/unaizalakain/qinfluxdb.git

下面是qinfluxdb的一个操作的例子 

Python

from qinfluxdb import Client
# The client is just a wrapper around InfluxDB's python client
client = Client(database='analytics', timeout=60)
query = client.q.from_series('temperature')
# Iterate over the results
for result in query:
    print(result)
# List them all
query.all()
# Continue with the query and filter
query.where('value &gt; 20').limit(20)
# Only select some of the values
query.values('time', 'mean(value)').group_by('time(1d)')
# Advanced filters
from qinfluxdb import Q
hot = Q('value &gt; 30')
cold = Q('value &lt; 0')
extreme = hot | cold
query.where(extreme) 

原文:http://xiaorui.cc/2015/05/13/python实现influxdb的orm对象关系映射模型/

Python: django中定期执行任务

最近需要考虑如何在django环境中跑定时任务. 这个在 stackoverflow也有对应的 讨论, 方法也有不少, 这边简单尝试和总结下.

假设我们现在的定期任务就是睡眠 n秒, 然后往数据库里面写一条记录, 记录这个任务的起始以及结束时间, 并且我们 不关心该任务的返回结果. 项目名称为 mmtest, 应用名称为 mma_cron(说实话我也不知道自己怎么取这样的名称….), 数据库使用 sqlite, model代码如下:

mma_cron/models.py
from  django.db  import  models
 from  django.utils  import  timezone
 # Create your models here.
 class  SimpleTask ( models . Model ):
  task_name  =  models . CharField ( max_length = 200 )
  start_time  =  models . DateTimeField ( 'task begin time' ,  default = timezone . now )
  finish_time  =  models . DateTimeField ( 'task end time' ,  blank = True ,  null = True )
  

最朴素的方法

考虑一个最最朴素的实现: 起一个简单的daemon程序, 每隔一定时间进行任务处理; 或者是写一个简单的程序, 利用 cron来定期执行该脚本. 一个好处是足够简单. 但很多时候写这样的程序需要花不少时间.

简单的改进

自己重新写一个程序有时候代价还是挺大的, 尤其是业务逻辑十分复杂的时候, 所以可以考虑复用已有的代码. 如果考虑 cron定期执行的策略, 我们可以在 django中实现对应逻辑, 方法也有几个:

  1. 实现一个api, 定期请求
  2. 扩展manage.py

方法一没什么好说的, 但是需要考虑访问控制; 方法二的话也很简单, 可以参考 自定义commands. 无论用哪种方式, 我们可以先实现对应的任务处理逻辑:

mma_cron/models.py
def  run_simple_task ( task_name ):
  task  =  SimpleTask ( task_name  =  task_name )
  task . save ()
  ## do a lot lot of stuff......
  seconds  =  random . randint ( 5 ,  15 )
  time . sleep ( seconds )
  task . finish_time  =  timezone . now ()
  task . save ()
  return  seconds
  

针对方法一, 实现对应的view:

mma_cron/views.py
from  django.http  import  HttpResponse
 from  .models  import  run_simple_task
 def  do_task ( request ,  task_name ):
  seconds  =  run_simple_task ( task_name )
  return  HttpResponse ( "I have done task in  %d  sec:  %s >"  %  ( seconds ,  task_name ))
  

添加对应的route:

mma_cron/urls.py
urlpatterns  =  [
  ## add one
  url ( r'^task/(?P<task_name>w+)' ,  views . do_task ,  name = 'do_task' ),
 ]
  

我们手动访问试一下: curl 127.0.0.1:8000/mma_cron/task/ddddd, 可以看到在经过一段时间后数据库中有结果了. 可行~

针对方法二, 扩展 manage.py, 实现对应的command:

mma_cron/management/commands/yy.py
from  django.core.management.base  import  BaseCommand ,  CommandError
 from  mma_cron.models  import  run_simple_task
 class  Command ( BaseCommand ):
  help  =  'Run the simple command'
  def  add_arguments ( self ,  parser ):
  pass
  def  handle ( self ,  * args ,  ** options ):
  seconds  =  run_simple_task ( 'run from manage.py' )
  self . stdout . write ( "task done>" )
  

再手动试一下: python manage.py yy, 发现也有对应的结果, 可行~

至于定期可以通过设定cron来实现.

插件

上面的实现比较简便, 也很有效. django的插件也有对应的实现, 这里着重介绍一下 django-cron. 它类似使用了上面提到的方法二, 在此之上增加了 任务执行检查, 日志记录等功能. 我们也来看一下;)

安装的话推荐直接把源码下的 django_cron(相当于一个django的应用)目录放到当前工程目录. 使用可以参考 这里. 接下来需要执行下它的迁移操作(migration):

python manage.py migrate django_cron
  

该操作是创建对应的数据库, 之后执行定时任务时会把 时间和 相关结果保存到数据库中. 接下来我们需要在 mma_cron中定义一个对应的定时任务:

mma_cron/cron.rb
from  django.utils  import  timezone
 from  django_cron  import  CronJobBase ,  Schedule
 from  .models  import  run_simple_task
 class  SimpleTaskCronJob ( CronJobBase ):
  RUN_EVERY_MINS  =  1
  schedule  =  Schedule ( run_every_mins = RUN_EVERY_MINS )
  code  =  'mma_cron.cron.simple_task_cron_job'
  def  do ( self ):
  seconds  =  run_simple_task ( 'task from django-cron' )
  msg  =  "I have done task in  %s  sec:  %s >"
  return  ( "I have done task in  %s  sec:  %s >"  %  ( seconds ,  task_name ))
  

可以看到里面定义了该定时任务的 处理间隔与相应动作. 最后我们还需要在 settings.py注册一下我们的定时任务:

mmtest/settings.py
CRON_CLASSES  =  [
  "mma_cron.cron.SimpleTaskCronJob>" ,
 ]
  

大功告成, 接下来我们只需在执行 python manage.py runcrons即可跑我们的任务了. 运行时 django_cron会根据任务的执行时间与数据库中记录的时间做对比, 如果没到对应时间会直接退出. 每次执行完都会在 django_cron_cronjoblog这张表中记录对应的时间以及返回的结果(原来python不是默认把最后一个语句的结果当成返回值的, 好吧). 同样的, 为了让其定时跑, 我们也需要在crontab中添加对应的命令.

值得一提的是如果注册了多个任务, 这些任务默认是串行执行的(考虑到安全性). 如果想要并行执行需要改一些设置, 详见文档.

Celery

上述几种方法都比较简单, 但是我们还有其他的方式;) 比如很多人都提到的
Celery
. 给我的感觉它很像 gearmansidekiq, 类似一个任务分发和处理框架. 利用它的 Periodic Tasks, 可以实现定期发布任务让worker取执行任务. 我们也来简单看看.

简单尝试

我们先不管django, 先感性的了解下Celery. Celery的 任务分发和 结果存储需要依赖外部组件, 可选的有 RabbitMQ, Redis, 数据库等等. 简单起见, 这里选择使用 redis( RabbitMQ部署起来还是稍微复杂了点).

首先根据官方的 教程, 创建个分发 加法和 乘法任务的系统. 先来看看 worker的代码:

proj/tasks.py
from  __future__  import  absolute_import
 from  proj.celery  import  app
 @app.task
 def  add ( x ,  y ):
  return  x  +  y
 @app.task
 def  mul ( x ,  y ):
  return  x  *  y
 @app.task
 def  xsum ( numbers ):
  return  sum ( numbers )
  

再来看看 celery的设置代码:

proj/celery.py
from  __future__  import  absolute_import
 from  celery  import  Celery
 from  datetime  import  timedelta
 app  =  Celery ( 'proj' ,
  broker = 'redis://localhost' ,
  backend = 'redis://localhost' ,
  include = [ 'proj.tasks' ])
 ## 这段代码可以先忽略;)
 app . conf . update (
  CELERY_TASK_RESULT_EXPIRES  =  3600 ,
  CELERYBEAT_SCHEDULE  =  {
  'add-every-30-seconds' :  {
  'task' :  'proj.tasks.add' ,
  'schedule' :  timedelta ( seconds = 30 ),
  'args' :  ( 16 ,  32 ),
  },
  },
 )
 if  __name__  ==  '__main__' :
  app . start ()
  

我们先启动 redis, 然后通过执行 celery -A proj worker -l info来启动一个 worker. 接下来我们手动来创建任务, 然后丢给worker:

python
>>> import proj.tasks
 >>> result  =  proj.tasks.add.delay( 2,2)
 >>> result.get()
 4
  

这样就创建一个任务, 我们在celery的控制台(worker进程)可以看到这样的输出:

celery
Received task: proj.tasks.add[ a24a9792-a7c6-4f64-994d-ca6903b3182c]
 Task proj.tasks.add[ a24a9792-a7c6-4f64-994d-ca6903b3182c]  succeeded in 0.0018904690005s: 4
  

很直观~ 我们同时也可以看看它在redis里面是什么个样子:

redis-cli
127.0.0.1:6379> keys *
 1)  "celery-task-meta-a24a9792-a7c6-4f64-994d-ca6903b3182c>"
 2)  "_kombu.binding.celery.pidbox>"
 3)  "_kombu.binding.celery>"
 4)  "_kombu.binding.celeryev>"
 127.0.0.1:6379> TYPE _kombu.binding.celery
 set
  

现在我们是手动来创建任务, 我们可以启动一个定时生产任务的生产者 celery -A proj beat -l info. 它会定期创建我们在 proj/celery.py代码中指定的 CELERYBEAT_SCHEDULE中的任务.

结合django

理解了celery, 再结合django就相对比较简单了. 推荐阅读一下官方的 文档. 结合我们的SimpleTask的例子, 先设定下celery的任务:

mmtest/celery.py
from  __future__  import  absolute_import
 import  os
 from  celery  import  Celery
 from  datetime  import  timedelta
 os . environ . setdefault ( 'DJANGO_SETTINGS_MODULE' ,  'mmtest.settings' )
 from  django.conf  import  settings
 app  =  Celery ( 'mmtest' ,  broker = 'redis://localhost' )
 app . config_from_object ( 'django.conf:settings' )
 ## 自动发现任务: APP/tasks.py
 app . autodiscover_tasks ( lambda :  settings . INSTALLED_APPS )
 ## 设置定时任务参数
 app . conf . update (
  CELERYBEAT_SCHEDULE  =  {
  'do-task-every-30-seconds' :  {
  'task' :  'mma_cron.tasks.do_task' ,
  'schedule' :  timedelta ( seconds = 30 ),
  },
  },
 )
 @app.task ( bind = True )
 def  debug_task ( self ):
  print ( 'Request: {0!r}' . format ( self . request ))
  

接下来我们需要实现一下我们的worker:

mma_cron/tasks.py
from  __future__  import  absolute_import
 from  celery  import  shared_task
 from  .cron  import  run_simple_task
 @shared_task
 def  do_task ():
  run_simple_task ( 'run by celery' )
  

不需要其他的工作, 我们就完成了我们的目的. 接下来就是分别启动 worker和 beat了. 这也实现了我们的定时任务的目的(就我们这个例子有点大材小用了).

选择

就我个人观点, 我比较倾向于改进后的朴素方法. 原因就是业务比较简单, 比较轻量级.

整个过程还是学到了不少东西. 继续学习python~

原文:http://blog.aka-cool.net/blog/2015/05/14/cron-job-in-django/

Python: 如何成为Python高手

这篇文章主要是对我收集的一些文章的摘要。因为已经有很多比我有才华的人写出了大量关于如何成为优秀Python程序员的好文章。

我的总结主要集中在四个基本题目上:函数式编程,性能,测试,编码规范。如果一个程序员能将这四个方面的内容知识都吸收消化,那他/她不管怎样都会有巨大的收获。

函数式编程

命令式的编程风格已经成为事实上的标准。命令式编程的程序是由一些描述状态转变的语句组成。虽然有时候这种编程方式十分的有效,但有时也不尽如此(比如复杂性) —— 而且,相对于声明式编程方式,它可能会显得不是很直观。

如果你不明白我究竟是在说什么,这很正常。这里有一些文章能让你脑袋开窍。但你要注意,这些文章有点像《骇客帝国》里的红色药丸 —— 一旦你尝试过了函数式编程,你就永远不会回头了。

性能

你会看到有如此多的讨论都在批评这些“脚本语言”(Python,Ruby)是如何的性能低下,可是你却经常的容易忽略这样的事实:是程序员使用的算法导致了程序这样拙劣的表现。

这里有一些非常好的文章,能让你知道Python的运行时性能表现的细节详情,你会发现,通过这些精炼而且有趣的语言,你也能写出高性能的应用程序。而且,当你的老板质疑Python的性能时,你别忘了告诉他,这世界上第二大的搜索引擎就是用Python写成的 —— 它叫做Youtube(参考 Python摘录)

测试

如今在计算机科学界,测试可能是一个最让人不知所措的主题了。有些程序员能真正的理解它,十分重视TDD(测试驱动开发)和它的后继者BDD(行为驱动开发)。而另外一些根本不接受,认为这是浪费时间。那么,我现在将告诉你:如果你不曾开始使用TDD/BDD,那你错过了很多最好的东西!

这并不只是说引入了一种技术,可以替换你的公司里那种通过愚蠢的手工点击测试应用程序的原始发布管理制度,更重要的是,它是一种能够让你深入理解你自己的业务领域的工具 —— 真正的你需要的、你想要的攻克问题、处理问题的方式。如果你还没有这样做,请试一下。下面的这些文章将会给你一些提示:

编码规范

并非所有的代码生来平等。有些代码可以被另外的任何一个好的程序员读懂和修改。但有些却只能被读,而且只能被代码的原始作者修改 —— 而且这也只是在他或她写出了这代码的几小时内可以。为什么会这样?因为没有经过代码测试(上面说的)和缺乏正确的编程规范。

下面的文章给你描述了一个最小的应该遵守的规范合集。如果按照这些指导原则,你将能编写出更简洁和漂亮的代码。作为附加效应,你的程序会变得可读性更好,更容易的被你和任何其他人修改。

那就去传阅这这些资料吧。从坐在你身边的人开始。也许在下一次程序员沙龙或编程大会的时候,也已经成为一名Python编程高手了!

祝你学习旅途顺利。

如果你喜欢这些文章,请在微博上顶一下,让其他人也知道。

原文:http://www.vaikan.com/how-to-become-a-proficient-python-programmer/?rel=http://geek.csdn.net

Python: 纯Python综合图像处理小工具(3)10种滤镜算法

<背景> 

滤镜处理是图像处理中一种非常常见的方法。比如photoshop中的滤镜效果,除了自带的滤镜,还扩展了很多第三方的滤镜效果插件,可以对图像做丰富多样的变换;很多手机app实现了实时滤镜功能,最有名的当属Instagram。

滤镜的原理,常见的是针对数字图像的像素矩阵,使用一个nxn的方形矩阵做滤波器(即kernel,常见的如3×3,5×5等),对该像素矩阵进行遍历,遍历后的图像就是输出图像,如果算法经过优化,遍历的速度足够快,那就是实时滤镜(live filter),可以实时预览图像过滤后的效果。

ImageFilter是Python PIL的滤镜模块,当前版本支持10种加强滤镜,通过这些预定义的滤镜,可以方便的对图片进行一些过滤操作,从而去掉图片中的噪音(部分的消除),这样可以降低图像处理算法的复杂度(如模式识别等),更方便的实现和预览一些算法的效果。

本文脚本包含以下全部滤镜, 实现了九种图像处理滤镜的效果预览和JPEG文件保存。

ImageFilter.BLUR

模糊滤镜
ImageFilter.CONTOUR
ImageFilter.DETAIL 细节滤镜
ImageFilter.EDGE_ENHANCE 边界加强
ImageFilter.EDGE_ENHANCE_MORE 边界加强(阀值更 大)
ImageFilter.EMBOSS 浮雕滤镜
ImageFilter.FIND_EDGES 边界滤镜
ImageFilter.SMOOTH 平滑滤镜
ImageFilter.SMOOTH_MORE 平滑滤镜(阀值更大)
ImageFilter.SHARPEN 锐化滤镜

<效果>

原图:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

模糊滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

锐度增强滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

细节滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

轮廓滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

边界提取滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

边界增强滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

边界增强滤镜-加强版:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

平滑滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

平滑滤镜-加强版:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

浮雕滤镜:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法

<源码分析>

PIL库的滤镜算法可以在 PythonLibsite-packagesPIL路径下找到,如下所示:

Python: 纯Python综合图像处理小工具(3)10种滤镜算法
Python: 纯Python综合图像处理小工具(3)10种滤镜算法
 

在PIL路径下,我们看到了三个同名但后缀不同的文件:ImageFilter.py ImageFilter.pyc ImageFilter.pyo 。

.pyc文件:是同名的.py编译后的字节码文件,用来供解释器解释执行;

.pyo文件:是同名的.pyc文件经过优化后的字节码文件,通常体积更小,运行更快。

滤镜算法在ImageFilter.py文件中。

如前文所述,每一个滤镜通常对应着一个滤波器(即kernel),PIL中的kernel均为常见的3×3和5×5方形矩阵,下面是PIL中9种滤镜对应的矩阵:

模糊滤镜:

class BLUR(BuiltinFilter):

name =  Blur >”

filterargs = (5, 5), 16, 0, (

1,  1,  1,  1,  1,

1,  0,  0,  0,  1,

1,  0,  0,  0,  1,

1,  0,  0,  0,  1,

1,  1,  1,  1,  1

)

轮廓滤镜:

class CONTOUR(BuiltinFilter):

name =  Contour >”

filterargs = (3, 3), 1, 255, (

-1, -1, -1,

-1,  8, -1,

-1, -1, -1

)

细节滤镜:

class DETAIL(BuiltinFilter):

name =  Detail >”

filterargs = (3, 3), 6, 0, (

0, -1,  0,

-1, 10, -1,

0, -1,  0

)

边缘增强滤镜:

class EDGE_ENHANCE(BuiltinFilter):

name =  Edge-enhance >”

filterargs = (3, 3), 2, 0, (

-1, -1, -1,

-1, 10, -1,

-1, -1, -1

)

边缘增强滤镜-增强版:

该增强版和原滤镜仅仅是矩阵2行2列的一个参数大小不同,实际是修改了中心像素的权重。这个数值可以任意修改以自定义边缘增强的幅度。

class EDGE_ENHANCE_MORE(BuiltinFilter):

name =  Edge-enhance More >”

filterargs = (3, 3), 1, 0, (

-1, -1, -1,

-1,  9, -1,

-1, -1, -1

)

浮雕滤镜

class EMBOSS(BuiltinFilter):

name =  Emboss >”

filterargs = (3, 3), 1, 128, (

-1,  0,  0,

0,  1,  0,

0,  0,  0

)

边缘提取滤镜

class FIND_EDGES(BuiltinFilter):

name =  Find Edges >”

filterargs = (3, 3), 1, 0, (

-1, -1, -1,

-1,  8, -1,

-1, -1, -1

)

平滑滤镜:

class SMOOTH(BuiltinFilter):

name =  Smooth >”

filterargs = (3, 3), 13, 0, (

1,  1,  1,

1,  5,  1,

1,  1,  1

)

平滑滤镜-加强版:

平滑滤镜的加强是增加了滤镜窗口的尺寸,有3×3扩展到5×5, 这样每一个新像素的产生会包含25个周围原始像素的加权贡献(离得越近,贡献越大),这样的结果会更加平滑自然,代价是处理速度会明显的变慢。

class SMOOTH_MORE(BuiltinFilter):

name =  Smooth More >”

filterargs = (5, 5), 100, 0, (

1,  1,  1,  1,  1,

1,  5,  5,  5,  1,

1,  5, 44,  5,  1,

1,  5,  5,  5,  1,

1,  1,  1,  1,  1

)

锐化滤镜:

class SHARPEN(BuiltinFilter):

name =  Sharpen >”

filterargs = (3, 3), 16, 0, (

-2, -2, -2,

-2, 32, -2,

-2, -2, -2

)

<脚本源码> 

#  -*- coding: cp936 -*-
import Image,ImageDraw

import ImageFilter,random,sys

img = Image.open( 1.jpg >” )

# #图像处理##

# 转换为RGB图像
img = img.convert( RGB >” )              

# 经过PIL自带filter处理
imgfilted_b = img.filter(ImageFilter.BLUR)

imgfilted_c = img.filter(ImageFilter.CONTOUR)

imgfilted_ee = img.filter(ImageFilter.EDGE_ENHANCE)

imgfilted_ee_m = img.filter(ImageFilter.EDGE_ENHANCE_MORE)

imgfilted_em = img.filter(ImageFilter.EMBOSS)                    

imgfilted_fe = img.filter(ImageFilter.FIND_EDGES)                                                

imgfilted_sm = img.filter(ImageFilter.SMOOTH)

imgfilted_sm_m = img.filter(ImageFilter.SMOOTH_MORE)

imgfilted_sh = img.filter(ImageFilter.SHARPEN)

# 经过自定义filter处理

# #图像保存##

imgfilted_b.save( 1b.jpg >” )

imgfilted_c.save( 1c.jpg >” )

imgfilted_ee.save( 1ee.jpg >” )

imgfilted_ee_m.save( 1eem.jpg >” )

imgfilted_em.save( 1em.jpg >” )

imgfilted_fe.save( 1fe.jpg >” )                                

imgfilted_sm.save( 1sm.jpg >” )

imgfilted_sm_m.save( 1smm.jpg >” )

imgfilted_sh.save( 1sh.jpg >” )

# #图像显示##

imgfilted_b.show()

imgfilted_c.show()

imgfilted_ee.show()

imgfilted_ee_m.show()

imgfilted_em.show()

imgfilted_fe.show()                                

imgfilted_sm.show()

imgfilted_sm_m.show()

imgfilted_sh.show()

原文:http://www.cnblogs.com/sopic/p/4538052.html

Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存

一、去xampp官网下载最新版本的安装包,安装一般软件的安装步骤,一直下一步,不过如果你想安装到指定目录中的话,在选择安装位置的时候设置想要安装的位置。

二、我们在工作中经常遇到同时调试多个网站的情况,那么如何配置呢?就像平时访问网站一样,网站 a.com 与网站 b.com 截然不同。这都是常见现象,如果在局域网中要访问另外一台电脑上的多个网站,就需要使用 http://192.168.1.10/ 形式访问,而不是 http://localhost/,http 协议默认端口号是 80,如果我们可以设定不同的端口号,让服务器“监听器”去寻找不同的服务,岂不是更好?

Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存
Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存

最新的访问形式,可能像这样(其中的端口号建议不使用系统所保留(即 1024 以下)的):

http://192.168.1.10:8080/

http://192.168.1.10:8081/

http://192.168.1.10:8082/

我们本机采用 XAMPP 搭建,底端采用的 APACHE,本文配置方法不仅仅适用于 XAMPP,还适用于任意已安装 APACHE 的机子。我们一起来动手配置下:

XAMPP 安装路径:D:xampp

*网站根目录:D:xampphtdocs

*APACHE 所在位置:D:xamppapache

配置方法

1、创建 2 个以上不同的网站目录,存放不同的网站程序,小明创建后如下:

(1)D:xampphtdocsdedecms_test(存放yii程序)

(2)D:xampphtdocsdiscuz_test(存放 magento程序)

2、配置 2 个域名(可以任意):www.a.com、www.b.com,他们都指向了 127.0.0.1(本机)

(1)记事本打开 C:WindowsSystem32driversetchosts *火狐安装一个Hostadmin的插件进行设置更加方便。

(2)在该文件底部添加以下代码并保存:

127.0.0.1 www.a.com

127.0.0.1 www.b.com

3、记事本编辑 D:xamppapacheconfhttpd.conf,在顶部添加需要被监听的端口:8080、8081,保留默认监听的 80 端口

Listen 80

Listen 8080

Listen 8081

4、如果你想实现不同端口(http://localhost:8080/、http://localhost:8081/)访问不同网站,就需要在该文件最底部添加:

# 多端口虚拟主机配置 #

ServerName localhost

DocumentRoot D:xampphtdocsyii

# dedecms_test #

ServerName localhost

DocumentRoot D:xampphtdocsyii

如果你想采用不同域名访问不同网站,就需要在底部添加:

# 多域名虚拟主机配置 #

ServerName www.a.com

DocumentRoot D:xampphtdocsyii

# dedecms_test #

ServerName www.b.com

DocumentRoot D:xampphtdocsmagento

5、最重要的一步,重启 apache 服务。浏览器输入:http://localhost:8080/、http://localhost:8081/、http://www.a.com/、http://www.b.com 试试哇~

6、不过如果你需要安装python环境的话,可能会有冲突,因为vmware的443端口被apche占用了,所以我们不妨将apache的443端口更改为其他的,比如442

Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存
Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存
Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存
Python: windows环境下XAMPP安装、多域名多端口配置、与python环境并存

原文:http://www.cnblogs.com/c-and-unity/p/4539348.html

Python: Django笔记 —— MySQL安装

最近在学习Django,打算玩玩网页后台方面的东西,因为一直很好奇但却没怎么接触过。Django对我来说是一个全新的内容,思路想来也是全新的,或许并不能写得很明白,所以大家就凑合着看吧~

本篇笔记(其实我的所有笔记都是),并不会过于详细的讲解。因此如果有大家看不明白的地方,欢迎在我正版博客下留言,有时间的时候我很愿意来这里与大家探讨问题。(当然,不能是简简单单就可以百度到的问题-.-)

我所选用的教材是《The Django Book 2.0》,本节是我自己插入的数据库安装步骤,针对不大了解数据库安装的同学。

————————————————————————————————————————————————

0、说明

为了在Django中使用数据库,需要先安装并设置好,在《The Django Book 2.0》书中,默认大家已经安装好了自己想要使用的数据库,但实际上,并不是所有人都已经了解如何安装的,甚至还很困扰,并且很难查到适合自己的教程(我就是-.-)。

这里我来说明一下,在Django中使用数据库所需的准备工作。

首先是安装。我使用的数据库是MySQL,那么,就需要在机器上已经安装好MySQL,并安装好其服务器和客户端。然后,把MySQL-python这个库安装好,才能在python代码中使用MySQL。

而后是设置,先要在MySQL中有一个供你使用的用户和数据库(如果没有现成的,就得创建一个)。然后,需要在你的Django工程的settings.py中设置好关于数据库的全部设置,以定位到你所要使用的数据库以及用来使用它的用户。

最后是使用,只要数据库的服务器在运行,你就可以在Django中按照你之前的设置使用这个数据库了。

再啰嗦一句,下面的各种命令都是要在终端中输入的,不再赘述。

1、安装MySQL

我的MySQL版本是5.6.24。(我的全部工作环境配置信息,例如操作系统,已经在 Django笔记 —— 入门简介中提到过,这里不再赘述)

想要查看自己机器里有没有的话,就在命令行中输入mysql,有反应就说明有。

没有的话,也无所谓,下面安装server的时候会自动安装的。

2、安装MySQL服务器和客户端

sudo apt-get install mysql-server

sudo apt-get install mysql-client

如果你之前机器中没有MySQL的话,在你安装server的时候会自动帮你安装,还会让你设置MySQL中的root密码,这在以后的MySQL使用中常常会使用到。

关于root用户,基本就和Linux的root用户感觉一样,这里简单解释一下。

使用MySQL时要用某个用户登录进去,每个用户都有自己的权限;而root则是里面最大权限的用户,拥有任何权限,可以管理所有其它用户。实际上,我们使用MySQL时,除了root用户之外,往往还要有另一个普通用户。平时使用时,就用那个普通用户;权限不够时,再上root。这样,可以避免你手一抖删掉不该删的东西~

3、安装MySQL-python

sudo pip install MySQL-python

注意大小写别写错了。

4、在MySQL中创建用户及数据库

现在你的MySQL已经安装好了,需要在MySQL中创建一个用户和一个数据库供Django使用。

先教一下用root登录数据库:

输入mysql -u root -p,然后输入你MySQL的root密码。

看到 mysql> 就说明你登录进去了,退出命令是exit,MySQL会和你说“Bye”。。

然后是新建用户:

1. 用root登录

2. 创建用户:insert into mysql.user(Host, User, Password) values(“localhost>”, “qiqi>”, password(“nicai>”));

3. 刷新权限表:flush privileges;

这样就创建了一个名叫qiqi,密码是nicai的用户。这个用户的类型是localhost,即在本地登录的用户。具体内容不多说,学习Django这种用户足够了。

最后创建一个数据库:

1. 用root登录

2. 创建一个数据库:create database django;

这样就创建了一个名叫django的数据库。

还没完,最后还要给qiqi使用django这个数据库的权限:

1. 用root登录

2. 授予全部权利:grant all privileges on django.* to qiqi@localhost identified by ‘nicai’;

至此,你可以用qiqi这个用户直接登录MySQL并操作数据库django了,至于在Django中使用还需要下面的设置:

5、在Django中设置

打开你Django某个工程中的settings.py,找到 DATABASES 属性,把它设置成这样:

 1  #  Database
 2  #  https://docs.djangoproject.com/en/1.8/ref/settings/#databases
 3
 4  DATABASES = {
  5  ' default ' : {
  6  ' ENGINE ' : ' django.db.backends.mysql ' ,
  7  ' NAME ' : ' django ' ,
  8  ' USER ' : ' qiqi ' ,
  9  ' PASSWORD ' : 'nicai ' ,
 10  ' HOST ' : ' 127.0.0.1 ' ,
 11  ' PORT ' : ' 3306 ' ,
 12      }
 13  }  

其中,因为我是在本机上操作的,所以HOST是这个;至于PORT,我是在网上搜索到的,应该是MySQL的默认端口。

这里注一句,大家看到代码开头那个网址没有?这就是Django对这个参数的说明文档链接。遇到问题,大家一定要善用文档!

6、运行数据库服务器

你安装好之后,MySQL的服务器每次开机都会自动运行的。所以这点可以略去。

7、尝试使用

在你刚才改settings.py的工程的根目录下,运行:python manage.py shell

如果可以正常进入,就说明Django已经可以通过settings.py中的设置定位到你在MySQL中要使用的用户和数据库了。

————————————————————————————————————————————————

至此,我们应该可以继续Django的学习了。

关于MySQL的内容,如果以后有机会用到或者大家有需要的话,我或许会写的。现在嘛,继续回归Django的学习。

原文:http://www.cnblogs.com/icedream61/p/4538636.html

Python: 利用 mitmproxy 保存网页中的所有图片

有个需求,保存一个网页里的所有图片。

看上去是件简单的事情,拿 火狐DownThemAll扩展下载不就好了么。

然后发现那个网页仅限移动版访问。好吧,装个 UserAgent Switcher。然后发现它是通过 JavaScript 检测 UA 的,而 UserAgent Switcher 只改了 HTTP 头里的 UA。好吧,换个 muzuiget 的 User Agent Overrider。然后发现那些图片是动态加载的,DownThemAll 根本看不到地址。后来知道「查看网页信息」的「媒体」选项卡里也是可以保存图片的,不过那里显示的图片也不全……

于是我怒了,放弃继续尝试不同的工具,决定用 程序员的方式来解决问题。

我管你怎么加载的,你总归是要从网络上下载图片不是么?那我就拿个代理把你访问过的所有图片全部保存下来好了 🙂

打开 mitmproxy文档页,发现并没有现成的保存文件的功能。但是没关系,可以 写脚本。看看示例,迅速写了以下不到二十行代码:

#!/usr/bin/mitmdump -s
from __future__ import print_function
import os
from urlparse import urlsplit
from libmproxy.protocol.http import decoded
def response(context, flow):
  with decoded(flow.response):
    if flow.response.headers['Content-Type'][0].startswith('image/'):
      url = urlsplit(flow.request.url)
      name = os.path.basename(url.path)
      with open(name, 'wb') as f:
        f.write(flow.response.content)
      print(name, 'written') 

当然这是最终结果。不过和初版差别不大,毕竟就这么点儿代码。思路也很简单,凡是经过代理的图片都存起来。有点粗暴,但是好用。

代理脚本跑起来。然后启动一个全新的 Google Chrome,一个没有任何缓存存在的实例:

google-chrome-stable --proxy-server=http://localhost:8080 --user-data-dir=new 

访问目标页面,启用移动版模拟并刷新,就可以看到各种图片都被保存下来了~~

原文:http://lilydjwg.is-programmer.com/2015/5/30/save-images-with-mitmproxy.95114.html

Python: Rubicon —— Python 与其他语言的交互

#深圳# 6月10日 亚马逊AWSome Day云计算免费培训报名中

Rubicon 是连接 Python 和其他编程语言的工具集合。

Rubicon 库现在支持:

  • Objective C

  • Java

Objective C

Rubicon-ObjC是 Python 和 Objective-C 的桥梁,支持 iOS 和 OS X,允许你:

  • 使用 Python 来实例化 Objective-C 中定义的对象

  • 使用 Python 来调用 Objective-C 中定义的对象方法

  • 使用 Python 来扩展 Objective-C 类或者子类

同时也包括一些 Core Foundation 框架关键数据类型的封装,比如 NSString 和 NSObject。

Rubicon-Java是 Java 运行时环境和 Python 的桥梁,支持桌面环境和 Android 设备。允许:

  • 实例化 Java 定义的对象

  • 调用 Java 定义的对象方法

  • 访问和修改 Java 定义对象的静态和实例字段

  • 编写是使用 Python 实现 Java 定义的接口

原文:http://www.oschina.net/p/rubicon

Python: python实现地址分布可视化

当你知道某些详细地址信息,该如何利用。本文通过调用百度地图接口,实现用户可视化展示,便于更清楚地了解用户。

注册百度地图开放平台帐号

首先先到 http://developer.baidu.com/map/ 上注册一个开发者帐号,然后找到 Web服务API下的Geocoding API ,如下图所示:

Python: python实现地址分布可视化
Python: python实现地址分布可视化

Python调用

通过http调用接口格式如下:

http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=E4805d16520de693a3fe707cdc962045&callback=showLocation
 

利用python批量调用,先定义一个函数:

def getlnglat(address):
	url = 'http://api.map.baidu.com/geocoder/v2/'
	output = 'json'
	ak = '[*百度开发平台上申请的*]'
	uri = url + '?' + 'address=' + address + '&output=' + output + '&ak=' + ak
	temp = urllib.urlopen(uri)
	temp = json.loads(temp.read())
	return temp
 

接下来就可以通过调用该函数去批量处理地址数据,并将相应的结果存入到数据库中。

百度地图接口这点确实做的不错,返回的结果中包含两个相当有用的信息,一个是置信度(可以简单理解为计算结果的准确性),另一个是地址类型,即标识某个地址是商务大厦、村庄、道路、宾馆等一些语义化的标签。

Tableau数据可视化Tableau的可视化功能较为方便和强大,以下是基于刚才处理后的数据得到的相应的可视化图:

整体分布图

Python: python实现地址分布可视化
Python: python实现地址分布可视化

局部分布图

Python: python实现地址分布可视化
Python: python实现地址分布可视化

有了这样一幅图,大家就可以很清楚地了解用户:住哪 、那个小区,周边商业环境等相关信息。基于此,在移动互联网环境下,我们也可以发现其它的机会点,如果某个小区或者大厦有很多人使用应用,可以基于此部分用户做专门的分析,观察这部分用户的时间信息流,想像一下千万溪流汇聚成大海,大海就是我们观察到的小区或者厦,溪河就是可能的商业机会,大的溪河需要重点挖掘,小的溪河看潜力。

原文:http://segmentfault.com/a/1190000002811065

Python: Python中写一个乒乓球类的游戏

最近开始学Python,感觉挺好玩的,既有脚本语言的灵活性,又有丰富的类库与面向对象的特点,开发起来很方便。

Python: Python中写一个乒乓球类的游戏
Python: Python中写一个乒乓球类的游戏

游戏的规则和乒乓球一样,如果妙蛙种子掉地上了就算输,你可以用蓝色的跷跷板弹它,使他不落到地面上。

Game Over后可按任意键继续游戏或选择退出。

代码如下:

  1  import sys, pygame
   2  from  random import *
  3  from  pygame.locals import *
  4  from  pygame.font import *
  5  class  MyPlayer(pygame.sprite.Sprite):
   6      def __init__(self, image_file, location, speed):
   7          pygame.sprite.Sprite.__init__(self)
   8          self.image = pygame.image.load(image_file)
   9          self.rect = self.image.get_rect()
  10          self.rect.left, self.rect.top = location
  11          self.speed = speed
  12          self.status = True
  13      def move(self):
  14          self.rect = self.rect.move(self.speed)
  15  if  self.rect.left < 0  or self.rect.right > width:
  16              self.speed[0 ] = -self.speed[0 ]
  17  if  self.rect.top < 0 :
  18              self.speed&#91;1 &#93; = -self.speed&#91;1 &#93;
  19  if  self.rect.bottom > height:
  20              #Game over
  21              self.status = False
  22  class  Reflector(pygame.sprite.Sprite):
  23      def __init__(self, image_file, location, speed):
  24          pygame.sprite.Sprite.__init__(self)
  25          self.image = pygame.image.load(image_file)
  26          self.rect = self.image.get_rect()
  27          self.rect.left, self.rect.top = location
  28          self.speed = speed
  29      def move(self):
  30          self.rect = self.rect.move(self.speed)
  31  if  self.rect.left < 0  or self.rect.right > width:
  32              self.speed[0 ] = -self.speed[0 ]
  33  if  self.rect.top < 0  or self.rect.bottom > height:
  34              self.speed[1 ] = -self.speed[1 ]
  35  def animate(players):
  36      screen.fill([255 ,255 ,255 ])
  37  for  player in  players:
  38          player.move()
  39  for  player in  players:
  40          players.remove(player)
  41  if  pygame.sprite.spritecollide(player,players,False):
  42              player.speed[0 ] = -player.speed[0 ]
  43              player.speed[1 ] = -player.speed[1 ]
  44          players.add(player)
  45          player.move()
  46          screen.blit(player.image,player.rect)
  47      pygame.display.flip()
  48      pygame.time.delay(10 )
  49
 50  pygame.init()
  51  size = width,height = 640 ,480
 52  screen = pygame.display.set_mode(size)
  53  screen.fill([255 ,255 ,255 ])
  54  pygame.display.set_caption(" MiaoWa Game >" )
  55  def play():
  56      img_player = " C:UsersdswuDesktopplayer.png >"
 57      players = pygame.sprite.Group()
  58  for  row in  range(0 ,1 ):
  59  for  column in  range(0 ,1 ):
  60              playerLocation = [column*250 +10 ,row*250 +10 ]
  61              playerSpeed = [choice([-2 ,2 ]), choice([-2 ,2 ])]
  62              player = MyPlayer(img_player, playerLocation, playerSpeed)
  63              players.add(player)
  64      img_ref_path = " C:UsersdswuDesktopReflector.png >"
 65      ref_pos = [0 ,464 ]
  66      ref_speed = [0 ,0 ]
  67      reflector = Reflector(img_ref_path, ref_pos, ref_speed)
  68      players.add(reflector)
  69      running = True
  70  while  running:
  71          key_pressed = pygame.key.get_pressed()
  72  for  event  in  pygame.event .get ():
  73  if  event .type == pygame.QUIT:
  74                  game.quit()
  75  if  event .type == KEYDOWN:
  76  if  event .key == K_LEFT:
  77                      ref_speed[0 ] = -2
 78                  elif event .key == K_RIGHT:
  79                      ref_speed[0 ] = +2
 80          animate(players)
  81  if  player.status == False:
  82              running = False
  83      final_text = " Game Over! >"
 84      ft_font = pygame.font.Font(None, 100 )
  85      ft_surf = ft_font.render(final_text, 1 , (0 ,0 ,0 ))
  86      screen.blit(ft_surf, [screen.get_width()/2  - ft_surf.get_width()/2 , 100 ])
  87      tip_text = " Type any key to continue >"
 88      tip_font = pygame.font.Font(None, 50 )
  89      tip_surf = tip_font.render(tip_text, 1 , (0 ,0 ,0 ))
  90      screen.blit(tip_surf, [screen.get_width()/2  - tip_surf.get_width()/2 , 200 ])
  91      pygame.display.flip()
  92      keepOn = True
  93  while  keepOn:
  94          key_pressed = pygame.key.get_pressed()
  95  for  event  in  pygame.event .get ():
  96  if  event .type == pygame.QUIT:
  97                  pygame.quit()
  98  if  event .type == KEYDOWN:
  99                  play()
 100  play() 

主要是通过pygame.sprite.Sprite类实现碰撞的监控,通过事件的捕捉及判断实现这种弹力球类的游戏,其中涉及到文字在界面上的显示,游戏中的循环控制,以及重新开始游戏等。

把上面这段代码贴到你的IDLE中,找到下面这两行替换成你机器中的图片路径,按F5就可以运行了。

img_player = " C:UsersdswuDesktopplayer.png >"
img_ref_path  = " C:UsersdswuDesktopReflector.png >"  

由于比较简单,看看代码运行一下应该就差不多明白了,如果有不明白的地方请给我留言,方便一起学习与进步。

平时都在线,欢迎交流。

原文:http://www.cnblogs.com/LanTianYou/p/4544614.html

Python: Python MySQL 官方包:mysql-connector-python

Python 操作mysql包有MySQLdb、SQLAlchemy等等、还有一个是mysql.connector,mysql官方包,详见( MySQL Connector/Python Developer Guide

)。

用法官方有示例: Chapter 5 Connector/Python Coding Examples


5.1 Connecting to MySQL Using Connector/Python

5.2 Creating Tables Using Connector/Python

5.3 Inserting Data Using Connector/Python

5.4 Querying Data Using Connector/Python

安装方法: easy_install mysql-connector-python

用法和MySQLdb基本类似,这应该是类似一种协议的东西吧?

查询的时候是支持查询字典的!

connor.connect(*args, **kwargs)

cursor = conn.cursor(dictionary=True)

附加是我自己写的mysql_helper.py

———–


 1
# -*- coding: utf8 -*-

2
# @author: ‘zhangzhipeng’

3
# @date: ‘2015-04-10’

4

5
import
logging

6

7
import
mysql.connector as
connor

8

9

10connor.connect()

11
12

13
class
MysqlHelper
(object):

14
“>”” host=>”localhost”, db=>””, user=>”root”, passwd=>””, port=3306, pool_sizer=30, pool_name=>”mysql”, commit_size=1
>””>”

15commit_count = 0

16

17
def
__init__
(self, *args, **kwargs):

18
commit_size = kwargs.get(” commit_size
>”, -1)

19
if
commit_size > -1:

20self._commit_size = commit_size

21
del
kwargs[” commit_size
>”]

22
else
:

23self._commit_size = 1

24self._last_row_id = None

25self._conn = connor.connect(*args, **kwargs)

26

27
def
insert
(self, sql, params=None):

28cursor = self._create_cursor()

29
try
:

30cursor.execute(sql, params)

31
except
Exception, e:

32
try
:

33
logging.error(” Mysql Call error. SQL = %s, params = %s, Error.msg=%s
>” % (sql, str(params).encode(” utf8
>”), e))

34
except
:

35
print
sql, params, e

36self._last_row_id = cursor.lastrowid

37self._commit()

38
return
cursor.rowcount

39

40
def
update
(self, sql, params=None):

41
return
self.insert(sql, params)

42

43
def
delete
(self, sql, params=None):

44
return
self.insert(sql, params)

45

46
def
select
(self, sql, params=None):

47cursor = self._create_cursor()

48cursor.execute(sql, params)

49
return
cursor.fetchall()

50

51
def
commit
(self):

52
try
:

53self._conn.commit()

54
except
connor.Error, msg:

55
logging.error(” Mysql commit error. message:%s.
>” % msg)

56

57
@
property

58
def
last_row_id
(self):

59
return
self._last_row_id

60

61
def
_create_cursor
(self):

62
# cursor = conn.cursor(cursor_class=conner.cursor.MySQLCursorDict)

63cursor = self._conn.cursor(dictionary=True)

64
return
cursor

65

66
def
_commit
(self):

67self.__class__.commit_count += 1

68
if
self.__class__.commit_count == self._commit_size:

69self.commit()

70self.__class__.commit_count = 0

71

72
def
__del__
(self):

73
print
mysql close …
>”

74self.commit()

75self._conn.close()

76
77

78
if
__name__ == ” __main__
>”:

79
mysql_helper = MysqlHelper(host=” localhost
>”, db=” zentao
>”, user=” root
>”, passwd=” kaimen
>”, port=3306, pool_size=2,

80
pool_name=” mysql
>”, commit_size=2)

81
print
1, mysql_helper.select(” show tables;
>”)

82
print
2, mysql_helper.select(” show tables;
>”)

83
print
3, mysql_helper.select(” show tables;
>”)

84
print
4, mysql_helper.select(” show tables;
>”)

85
print
5, mysql_helper.select(” select * from task;
>”)

select 结果是list[dict{}, dict{}] 

查询的时候,参数可以是列表、字典

user = {“uid>”: 20, “name>”:”zhipeng>”, “titles>”:”python, spider>”}

sql = ‘INSERT INTO users(uid, name, titles) VALUES (%s, %s, %s);’

mysql_helper
.insert(sql, ( user
[“uid>”], user
[“name>”], user
[“titles>”], ))

或者:

sql = ‘INSERT INTO users(uid, name, titles) VALUES (%(uid)s, %(name)s, %(titles)s);’

mysql_helper.
insert(sql, user
)

增、删、改,返回的结果是几行受影响。

mysql_helper.last_row_id 获取最后添加的自增长列id

commit_size 是设置主动commit方式,插入多少次数据后执行commit方法。

在__del__中添加主动commit,确保数据提交更改。

原文:http://blog.sina.com.cn/s/blog_83dc494d0102voun.html

Python: 十位发明了全球最红 10 种程序语言的工程师在此

Python: 十位发明了全球最红 10 种程序语言的工程师在此
Python: 十位发明了全球最红 10 种程序语言的工程师在此

《TO》导读:以第一人称编译。

其实世界上有很多种程序语言,但能够熬出头被众人採用的却很少。程序语言可以说是软体产业的基石,也是所有工程师每天都会用到的工具。

每一种语言都经过多次修改,才能够顺应潮流,让软体业有更丰富的面貌。虽如此,这些语言背后的推手却鲜为人知,大家大概都知道 Java 之父是 James Gosling,但却没人知道 Perl、Pascal、Lisp 或 Erlang 的创造者是谁。以下是我为大家蒐集的资料,希望他们的贡献能够被更多人知道。

由于我个人是主攻 Java 的工程师,所以我将它放在十大语言之首。不过其实以下顺序没有什么意义,或许有些人会说 C 语言才是最长寿的语言,但......我只是想跟大分享一些资讯而已,无关乎排名。好的,就让我们来认识这些改变世界的人吧!

  • Java – James Gosling

Java 是由任职于昇阳电脑的 James Gosling 等人开发,是目前最受欢迎且广泛使用的语言之一。原本由昇阳电脑负责开发和更新,但在 2010 年昇阳被甲骨文併购之后,就改由甲骨文负责。

Java 的宗旨是"Write Once Run Anywhere( 一次编写,到处运行)",强调跨平台的特性,也是这语言成功的重要因素。

  •  C – Dennis Ritchie

Dennis MacAlistair Ritchie是一位美国工程师,1967-1973 年之间,在 AT&T 的 贝尔实验室开发。虽然开发时间较早,但至今仍保有竞争优势。

顺带一提,UNIX 作业系统也是他的作品之一。虽然多数人可能没听过他的名字,但在软体界他的名气可不输给比尔盖兹或贾伯斯。

  • C++ – Bjarne Stroustrup

Bjarne Stroustrup是一位丹麦工程师,后来也在贝尔实验室工作。C++ 是 C 的下一代的概念。起初是以物件导向为主,后来加入许多模板和功能。由于接近 C 语言,速度又快,所以广泛的被大家接受。

  • Python – Guido van Rossum

Python 的设计宗旨就是希望程序码可以被人类阅读,不像一般语言难以理解,由荷兰程序设计师 Guido van Rossum所开发。

在美国,多数的学生都学 Java,但是近几年,大家都改以 Python 为入门程序。常用在网页应用工具,Google、Yahoo 和 Spotify 也都大量使用这种语言。如果你还在犹豫要学 Java 或是 Python 可以看看 这篇文章

  • PHP – Rasmus Lerdorf

不管你有多讨厌 PHP,都无法忽视全世界有半数网页都是使用这种语言。PHP 原本只是 Rasmus Lerdorf为了快速修编自己的网路履历而开发的,PHP 原本的全名也就是 Personal Home Page。

当时它的竞争对手是微软的 Active Server Pages (ASP)和 Java Server Pages(JSP),显然它赢了,并且佔领超过 2 千万个网站和一百万个网站伺服器。它很适合用在动态网页上面,以及网页伺服器的开发上面,Facebook、Wikipedia、Wordpress 和 Joomla 也都是使用这个语言。

  • Perl – Larry Wall

Perl 是一种高阶、通用、直译、动态的程序语言。1980 年代中由 Larry Wall开发,特别的是它不仅是个工程师,还是个语言学家,这项特质在 Perl 中也可以发现,也是它最大的优势。

Perl 被广泛的应用在编写 CGI( 通用网关接口)、资料库应用、网路/图形设计上。IMDB、Amazon 和 Priceline 就是以此为基础。对 Java 程序设计师来说,能够在履历加上 Perl 或 Python 是很加分的,因为他们会需要 脚本语言来完成维修、支援等特殊任务。

  • JavaScript – Brendan Eich

如果你问我过去 5-10 年之间谁是冠军,我会回答"JavaScript"。过去他主攻在客户端的程序撰写,还建立了函示库 jQuery,近几年往伺服器开发走,推出了 Node.js

它是一种基于原型、动态型别、弱型别的语言。1995 年由网景的 Brendan Eich所开发。主要在浏览器上运行,不需要伺服器支援。代表成果有 Gmail、Mozila Firefox。

  • Ruby – Yukihiro Matsumoto

1990 年中,由 松本行弘开发。Ruby 是一种有趣的语言,如果你学过大概就会懂我的意思,它受到 Perl、Ada、Lisp 和 Smalltalk 影响,设计的宗旨就是希望能减少编程的时间,强调人性化的介面。

多半用在网页应用程序,像是 Twitter、Hulu 和 Groupon。

  • Lisp – John McCarthy

第二年长的高阶语言,原名是 List Processor(清单处理器),由 John McCarthy发明,此生致力于人工智慧研究。( 一个时代的结束:人工智能之父、LISP 语言发明人 John McCarthy 过世

  • Pascal – Niklaus Wirth

1968 年由 Niklaus Wirth发明,是一个小型、高校的语言,鼓励结构化编成和资料结构的实践。

不管你是使用哪种语言,都希望你们知道这些东西不是凭空出现的,没有他们,我们不会有今天的成就。上述很多人已经离开我们去了另一个世界,但请不要忘记他们对科技的贡献,并继续发扬光大吧!

下图是这十种语言和开发者的统整,也加入了一些上面未提及的语言,像是 FORTRAN 和 Ada。

Python: 十位发明了全球最红 10 种程序语言的工程师在此
Python: 十位发明了全球最红 10 种程序语言的工程师在此

本文永久更新链接地址 : http://www.linuxidc.com/Linux/2015-05/117538.htm

原文:http://www.linuxidc.com/Linux/2015-05/117538.htm

Python: 作为一名数据科学家Python需要掌握到什么程度?

之前一直用R,最近正在学python,因为没有什么工作经验,也只能谈谈自己的感悟。

数据科学家算是统计师和程序员的结合体,来源也主要是这两个专业的毕业生。不过这两个群体的思维方式还真的是不一样。可以认为,统计的人更加偏爱R,程序员更偏爱python。

其实python有了pandas才能使数据分析变的像R那样简单。数据科学家能把python用的像R一样我觉得就好了。不过如果除了数据分析,公司要求代码的重用性,或者直接嵌入到产品中(比如网站推荐系统),那么对编程的要求就更高了。

其实数据科学家在做数据分析的时候,起码80%的时间是在做数据整理和清洗,同意 @唐学伟说的熟练使用pandas就好,这意味着能熟练的清理掉不必要数据,读取主要的数据格式文件,数据的合并汇总归类和切片等等。数据整理好比学编程要最起码能控制if-else和for循环,命令简单但是实用。

数据整理好了,对于各种算法包里的函数,其实就是input output的问题了。

另外一个常用的就是数据可视化也就是绘图了(目前主要是matplotlib)。这个步骤对于input的数据就是数据探索化的过程,查看数据是否有不合理性,数据的分布等等,对于output的数据就是结果呈现的过程,这样更有助于分析。

总而言之,数据科学家熟悉python的基本语法,熟练pandas(基于numpy),能利用python熟练的获取数据,整理数据,并会使用matplotlib展现数据是一个基本的要求。对于要做科学计算或者机器学习来说,数据整理好了,编程不是问题,数学才是。

说到这里看工作需求了,如果你所在的部门/实验室都用R/SAS/java/c++之类的,会用py进行预处理基本就可以了;如果主要用py来进行挖掘,需要掌握的就多一些,比如:numpy/scipy/mattplotlib/ipython/scikit-learn等。

DS需要统计+计算机。数据科学家这么高端的名词,不是只拿工具做上层的应用

业务分析做的好,这样只能说是好的分析师,程序编的溜,才可以说是好的工程师。

(来源:知乎问答)

美国对冲基金交易员传授股指期货(第二期)

继四月底成功举办第一期后,应未报上名的朋友们的要求,现安排第二期课程,请朋友们抓紧时间报名,前十名优惠1000元。

培养出来的学员在期货和外汇市场屡屡实现三个月翻十倍、四个月翻六倍、三周翻两倍的惊人交易绩效。并被华尔街交易学院及盈道金融研究院聘为指导老师和技术顾问。

(点击阅读原文查看详情)

原文:http://mp.weixin.qq.com/s?__biz=MzA3MDI3ODQxOA==&mid=205945644&idx=4&sn=4d25d382eb78454ba7b7305e16299e93&3rd=MzA3MDU4NTYzMw==&scene=6#rd

Python: ubuntu安装配置redis3.0的cluster集群模式

今天,天气不错….  出去逛了下,在咖啡店看了会美女….  休闲时,看到携程的一朋友在github关注了一个python redis cluster集群模块….  立马警醒,不能在看妹子了….  人家大周末也学习,我也要学习….   

标注下,关于redis cluster配置安装的文章是在  http://xiaorui.cc/?p=1443     http://xiaorui.cc

Python: ubuntu安装配置redis3.0的cluster集群模式
Python: ubuntu安装配置redis3.0的cluster集群模式

公司的业务大量的依靠redis做支撑,每个业务线的redis使用量都不小,像我们buzz业务就有好几个128G内存的redis服务器,在程序里面做的一致性hash。也尝试过用keepalived的ha方式来保证redis的高可用,但是keepalived也只能保证两个master的高可行,再就是用了keepalived之后,只能是一个读,一个做写,在某种程度上来说,在我们这种写入远比读业务要多的场景下,他是在是浪费….    单点问题一直是我们关注的,我自己也尝试过豌豆荚的codis,也听过codis作者的演讲…..    但现在redis3.0正式版也已经出来了,问了下周围的圈子里面的人,也是网易有道云在用,貌似在rc的版本,他们就在使用了….     当然不能 人云亦云 ,我自己也要测试下redis codis….

同事说,公司的针对redis cluster的机器已经分配下来了,今天就先在单机简单的测试下,后期可能在部署上采用docker redis的方式…..    现在同事们已经很享受用docker来快速的部署业务了。    我会在今天下午的时候,把redis cluster的dockerfile分享出来。   

我的测试机器是ubuntu14:10,本来是打算用centos的,结果起不来….  首先下载并安装redis3

Python

wget http://download.redis.io/releases/redis-3.0.1.tar.gz
tar zxvf redis-3.0.1.tar.gz
cd redis-3.0.1/
make
make install 

在单机测试的话,我们用redis-server分别启动多个文件就可以了,我这里采用的是6个端口,在redis cluster 里是三主、三从…. 当时也可以按照自己的情况设立主从….  需要注意的是redis.conf要开发cluster的选项。  我简单写了一个批量修改redis.conf的脚本.

Python

for i in `seq -w 0 5`;do
    cp redis.conf 700$i.conf
    sed -i "s/6379/700$i/g>" 700$i.conf
    sed -i 's/daemonize no/daemonize yes/g' 700$i.conf
    sed -i 's/# cluster-enabled yes/cluster-enabled yes/g' 700$i.conf
    sed -i 's/# cluster-node-timeout 15000/cluster-node-timeout 15000/g' 700$i.conf
    sed -i "s/# cluster-config-file nodes-700*/cluster-config-file nodes-700$i.conf/g>" 700$i.conf
    redis-server 700$i.conf
done 

如果你想自己手动修改的话,注意这么几个点.   端口一定不要重复,然后就是cluster-enabled yes  

Python

port xxxx
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000 

如果只是更改了端口,会造成一个无法创建集群的问题。 

Python

Installing RDoc documentation for redis-3.2.1...
root@ubuntu:~/redis-3.0.1# ./src/redis-trib.rb  create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
&gt;&gt;&gt; Creating cluster
Connecting to node 127.0.0.1:7000: OK
[ERR] Node 127.0.0.1:7000 is not configured as a cluster node.
root@ubuntu:~/redis-3.0.1# 

启动后,我们就可以在linux 进城管理里面看到redis的进程.   注意后面的端口是刚才咱们指定的。 

Python

root@ubuntu:~/redis-3.0.1/src# ps aux|grep redis
root      4974  0.1  0.9  40416  9388 ?        Ssl  12:11   0:03 redis-server *:7000 [cluster]
root      4983  0.1  0.9  40416  9452 ?        Ssl  12:11   0:04 redis-server *:7001 [cluster]
root      4992  0.1  0.9  40416  9440 ?        Ssl  12:11   0:03 redis-server *:7002 [cluster]
root      5001  0.1  0.9  40416  9420 ?        Ssl  12:11   0:04 redis-server *:7003 [cluster]
root      5010  0.1  0.7  40416  7392 ?        Ssl  12:11   0:04 redis-server *:7004 [cluster]
root      5019  0.1  0.9  40416  9424 ?        Ssl  12:11   0:04 redis-server *:7005 [cluster] 

redis cluster的配置是用的ruby脚本写得,那么就需要你最少安装了ruby (apt-get install ruby )和gem。更主要的是你还要用安装ruby所需要的redis模块。 

Python

root@ubuntu:~/redis-3.0.1# ./src/redis-trib.rb  create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- redis (LoadError)
    from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
    from ./src/redis-trib.rb:25:in `<main>'
root@ubuntu:~/redis-3.0.1# 

安装下ruby的redis驱动。

Python

root@ubuntu:~/redis-3.0.1# gem install redis
Fetching: redis-3.2.1.gem (100%)
Successfully installed redis-3.2.1
1 gem installed
Installing ri documentation for redis-3.2.1...
Installing RDoc documentation for redis-3.2.1...
root@ubuntu:~/redis-3.0.1# 

然后我们用redis-trib.rb来创建redis cluster集群,下面是成功的提示。

Python

root@ubuntu:~/redis-3.0.1# cd src
root@ubuntu:~/redis-3.0.1/src# ./redis-trib.rb  create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
&gt;&gt;&gt; Creating cluster
Connecting to node 127.0.0.1:7000: OK
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
&gt;&gt;&gt; Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7000
127.0.0.1:7001
127.0.0.1:7002
Adding replica 127.0.0.1:7003 to 127.0.0.1:7000
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
M: bde32811cbc7a55886413c52b8444d3353b9da86 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: d8815ad0a69436196908ae458f94704ff7325a53 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: ee05942ee38a56421a07eea01bc6072fe5e23bfd 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
S: 25f13acb0707a29cd2952dd0c6bdffa13721b001 127.0.0.1:7003
   replicates bde32811cbc7a55886413c52b8444d3353b9da86
S: d6dd1200fe377dc3aee2fd7d11a57504a6bd7529 127.0.0.1:7004
   replicates d8815ad0a69436196908ae458f94704ff7325a53
S: 2282e7f24bacf1b6b316382eb8f6448bc41bd89d 127.0.0.1:7005
   replicates ee05942ee38a56421a07eea01bc6072fe5e23bfd
Can I set the above configuration? (type 'yes' to accept): yes
&gt;&gt;&gt; Nodes configuration updated
&gt;&gt;&gt; Assign a different config epoch to each node
&gt;&gt;&gt; Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
&gt;&gt;&gt; Performing Cluster Check (using node 127.0.0.1:7000)
M: bde32811cbc7a55886413c52b8444d3353b9da86 127.0.0.1:7000
   slots:0-5460 (5461 slots) master
M: d8815ad0a69436196908ae458f94704ff7325a53 127.0.0.1:7001
   slots:5461-10922 (5462 slots) master
M: ee05942ee38a56421a07eea01bc6072fe5e23bfd 127.0.0.1:7002
   slots:10923-16383 (5461 slots) master
M: 25f13acb0707a29cd2952dd0c6bdffa13721b001 127.0.0.1:7003
   slots: (0 slots) master
   replicates bde32811cbc7a55886413c52b8444d3353b9da86
M: d6dd1200fe377dc3aee2fd7d11a57504a6bd7529 127.0.0.1:7004
   slots: (0 slots) master
   replicates d8815ad0a69436196908ae458f94704ff7325a53
M: 2282e7f24bacf1b6b316382eb8f6448bc41bd89d 127.0.0.1:7005
   slots: (0 slots) master
   replicates ee05942ee38a56421a07eea01bc6072fe5e23bfd
[OK] All nodes agree about slots configuration.
&gt;&gt;&gt; Check for open slots...
&gt;&gt;&gt; Check slots coverage...
[OK] All 16384 slots covered.
root@ubuntu:~/redis-3.0.1/src# 

这就说明,集群已经OK了, redis-cli客户端默认是不支持集群模式的….    如果像以前那么用redis-cli的话,会出现下面的情况…..   各种moved… error

Python

root@ubuntu:~/redis-3.0.1/src# redis-cli -p 7000
127.0.0.1:7000&gt;
127.0.0.1:7000&gt;
127.0.0.1:7000&gt; set a 11
(error) MOVED 15495 127.0.0.1:7002
127.0.0.1:7000&gt; set b 22
OK
127.0.0.1:7000&gt; set c 33
(error) MOVED 7365 127.0.0.1:7001
127.0.0.1:7000&gt; set d 33
(error) MOVED 11298 127.0.0.1:7002
127.0.0.1:7000&gt; set e 33
(error) MOVED 15363 127.0.0.1:7002
127.0.0.1:7000&gt; set f 33
OK
127.0.0.1:7000&gt; set g 33
(error) MOVED 7233 127.0.0.1:7001
127.0.0.1:7000&gt; get g
(error) MOVED 7233 127.0.0.1:7001 

只有加了-c参数,才能开启redis cluster 模式….   所以一定要好好看文档,就是因为这没有加-c 参数,导致了花费些时间来我排除问题 。

Python

root@ubuntu:~/redis-3.0.1/src# redis-cli -h
redis-cli 3.0.1
Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
  -a <password>      Password to use when connecting to the server.
  -r <repeat>        Execute specified command N times.
  -i <interval>      When -r is used, waits <interval> seconds per command.
                     It is possible to specify sub-second times like -i 0.1.
  -n <db>            Database number.
  -x                 Read last argument from STDIN.
  -d <delimiter>     Multi-bulk delimiter in for raw formatting (default: n).
  -c                 Enable cluster mode (follow -ASK and -MOVED redirections). 

我们最后来测试下….

Python

root@ubuntu:~/redis-3.0.1/src# redis-cli -c -p 7000
127.0.0.1:7002&gt; set blog xiaorui.cc
-&gt; Redirected to slot [7653] located at 127.0.0.1:7001
OK
127.0.0.1:7001&gt; set news xiaorui.cc
-&gt; Redirected to slot [5161] located at 127.0.0.1:7000
OK
127.0.0.1:7000&gt; set nima xiaorui.cc
-&gt; Redirected to slot [16259] located at 127.0.0.1:7002
OK
127.0.0.1:7002&gt; set ganni xiaorui.cc
-&gt; Redirected to slot [1198] located at 127.0.0.1:7000
OK
127.0.0.1:7000&gt; set love xiaorui.cc
-&gt; Redirected to slot [16198] located at 127.0.0.1:7002
OK
127.0.0.1:7002&gt; set satlstack xiaorui.cc
-&gt; Redirected to slot [2455] located at 127.0.0.1:7000
OK 

看来用以前的python redis模块也是不能直接用集群模式了,需要替换成支持redis cluster的python模块….

原文:http://xiaorui.cc/2015/05/16/ubuntu安装测试redis3-0的cluster集群模式/

Python: python使用redis-py-cluster操作redis cluster集群

redis3.0的集群已经搭建完了,那么开始用python来操作redis cluster集群试试,但是默认的redis模块已经是不能在使用了。  会提示下面的错误…..

Python: python使用redis-py-cluster操作redis cluster集群
Python: python使用redis-py-cluster操作redis cluster集群

In [1]: import redis

In [2]: r = redis.StrictRedis(host=’localhost’, port=7000)

In [3]: r.set(‘a’,’a’)

—————————————————————————

ResponseError                             Traceback (most recent call last)

in ()

—-> 1 r.set(‘a’,’a’)

/usr/local/lib/python2.7/dist-packages/redis/client.pyc in set(self, name, value, ex, px, nx, xx)

1053         if xx:

1054             pieces.append(‘XX’)

-> 1055         return self.execute_command(‘SET’, *pieces)

1056

1057     def __setitem__(self, name, value):

/usr/local/lib/python2.7/dist-packages/redis/client.pyc in execute_command(self, *args, **options)

563         try:

564             connection.send_command(*args)

–> 565             return self.parse_response(connection, command_name, **options)

566         except (ConnectionError, TimeoutError) as e:

567             connection.disconnect()

/usr/local/lib/python2.7/dist-packages/redis/client.pyc in parse_response(self, connection, command_name, **options)

575     def parse_response(self, connection, command_name, **options):

576         “Parses a response from the Redis server”

–> 577         response = connection.read_response()

578         if command_name in self.response_callbacks:

579             return self.response_callbacks[command_name](response, **options)

/usr/local/lib/python2.7/dist-packages/redis/connection.pyc in read_response(self)

572             raise

573         if isinstance(response, ResponseError):

–> 574             raise response

575         return response

576

ResponseError: MOVED 15495 127.0.0.1:7002

妈蛋的, pip install redis-py-cluster    作者貌似pypi的版本有些旧,不能用….  提示StrictRedisCluster 无法找到….  github上的代码和pypi确实不太一样…..    可以把源码git clone下来,然后python setup.py install 安装最近的代码.

Python

In [1]: from rediscluster import StrictRedisCluster
In [2]: startup_nodes = [{"host>": "127.0.0.1>", "port>": "7000>"}]
In [3]: rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)
In [4]: rc.set("foo>", "xiaorui.cc>")
Out[4]: True
In [5]: rc.set("foo1>", "blog.xiaorui.cc>")
Out[5]: True
In [6]: rc.set("foo2>", "bar>")
Out[6]: True
In [7]: rc.set("foo3>", "bar>")
Out[7]: True 

这么看来   ASK/MOVE 是没有问题的,不像原版的redis python那样,出现move error的问题…   

貌似redis-py-cluster 不支持事务(watch multi exec) , 有些蛋疼。 

In [10]: pipe = rc.pipeline()

In [11]: pipe.watch(‘xiaorui.cc’)

—————————————————————————

RedisClusterException                     Traceback (most recent call last)

in ()

—-> 1 pipe.watch(‘xiaorui.cc’)

/root/redis-py-cluster/rediscluster/pipeline.pyc in watch(self, *names)

266

267     def watch(self, *names):

–> 268         raise RedisClusterException(“method watch() is not implemented”)

269

270     def unwatch(self):

RedisClusterException: method watch() is not implemented

就这样吧….

原文:http://xiaorui.cc/2015/05/16/python使用redis-py-cluster操作redis-cluster集群/

Python: 我为什么从python转向go

应puppet大拿刘宇的邀请,我去西山居运维团队做了一个简短分享,谈谈为什么我要将我们的项目从python转向go。

坦白的讲,在一帮python用户面前讲为什么放弃python转而用go其实是一件压力蛮大的事情,语言之争就跟vim和emacs之争一样,是一个永恒的无解话题,稍微不注意就可能导致粉丝强烈地反击。所以我只会从我们项目实际情况出发,来讲讲为什么我最终选择了go。

为什么放弃python

首先,我其实得说说为什么我们会选择python。在我加入企业快盘团队之前,整个项目包括更早的金山快盘都是采用python进行开发的。至于为什么这么选择,当时的架构师葱头告诉我,主要是因为python上手简单,开发迅速。对于团队里面大部分完全没服务端开发经验的同学来说,python真的是一个很好的选择。

python的简单高效,我是深有体会的。当时私有云项目也就几个程序员,但是我们要服务多家大型企业,进行定制化的开发,多亏了python,我们才能快速出活。后来企业快盘挂掉之后,我们启动轻办公项目,自然也使用python进行了原始版本的构建。

python虽然很强大,但我们在使用的时候也碰到了一些问题,主要由如下几个方面:

  • 动态语言

    python是一门动态语言,不是强类型系统。对于一个变量,我们有时候压根不知道它是什么类型,然后就可能出现int + string这样的运行时错误。

    在python里面,可以允许同名函数的出现,后一个函数会覆盖前一个函数,有一次我们系统一个很严重的错误就是因为这个导致的。

    上面说到的这些,静态语言在编译的时候就能帮我们检测出来,而不需要等到运行时出问题才知道。虽然我们有很完善的测试用例,但总有case遗漏的情况。所以每次出现运行时错误,我心里都想着如果能在编译的时候就发现该多好。

  • 性能

    其实这个一直是很多人吐槽python的地方,不过想想,python最开始是为了解决啥问题而被开发出来的?我们硬是要将他用到高性能服务器开发上面,其实也是有点难为它。

    python的GIL导致导致无法真正的多线程,大家可能会说我用多进程不就完了。但如果一些计算需要涉及到多进程交互,进程之间的通讯开销也是不得不考虑的。

    无状态的分布式处理使用多进程很方便,譬如处理http请求,我们就是在nginx后面挂载了200多个django server来处理http的,但这么多个进程自然导致整体机器负载偏高。

    但即使我们使用了多个django进程来处理http请求,对于一些超大量请求,python仍然处理不过来。所以我们使用openresty,将高频次的http请求使用lua来实现。可这样又导致使用两种开发语言,而且一些逻辑还得写两份不同的代码。

  • 同步网络模型

    django的网络是同步阻塞的,也就是说,如果我们需要访问外部的一个服务,在等待结果返回这段时间,django不能处理任何其他的逻辑(当然,多线程的除外)。如果访问外部服务需要很长时间,那就意味着我们的整个服务几乎在很长一段时间完全不可用。

    为了解决这个问题,我们只能不断的多开django进程,同时需要保证所有服务都能快速的处理响应,但想想这其实是一件很不靠谱的事情。

  • 异步网络模型

    tornado的网络模型是异步的,这意味着它不会出现django那样因为外部服务不可用导致这个服务无法响应的问题。话说,比起django,我可是非常喜欢tornado的,小巧简单,以前还写过几篇深入剖析tornado的文章了。

    虽然tornado是异步的,但是python的mysql库都不支持异步,这也就意味着如果我们在tornado里面访问数据库,我们仍然可能面临因为数据库问题造成的整个服务不可用。

    其实异步模型最大的问题在于代码逻辑的割裂,因为是事件触发的,所以我们都是通过callback进行相关处理,于是代码里面就经常出现干一件事情,传一个callback,然后callback里面又传callback的情况,这样的结果就是整个代码逻辑非常混乱。

    python没有原生的协程支持,虽然可以通过gevent,greenlet这种的上patch方式来支持协程,但毕竟更改了python源码。另外,python的yield也可以进行简单的协程模拟,但毕竟不能跨堆栈,局限性很大,不知道3.x的版本有没有改进。

  • 开发运维部署

    当我第一次使用python开发项目,我是没成功安装上项目需要的包的,光安装成功mysql库就弄了很久。后来,是一位同事将他整个python目录打包给我用,我才能正常的将项目跑起来。话说,现在有了docker,是多么让人幸福的一件事情。

    而部署python服务的时候,我们需要在服务器上面安装一堆的包,光是这一点就让人很麻烦,虽然可以通过puppet,salt这些自动化工具解决部署问题,但相比而言,静态编译语言只用扔一个二进制文件,可就方便太多了。

  • 代码失控

    python非常灵活简单,写c几十行代码才能搞定的功能,python一行代码没准就能解决。但是太简单,反而导致很多同学无法对代码进行深层次的思考,对整个架构进行细致的考量。来了一个需求,啪啪啪,键盘敲完开速实现,结果就是代码越来越混乱,最终导致了整个项目代码失控。

    虽然这也有我们自身的原因,譬如没好的代码review机制,没有好的项目规范,但个人感觉,如果一个程序员没经过良好的编码训练,用python很容易就写出烂的代码,因为太自由了。

    当然,我这里并不是说用python无法进行大型项目的开发,豆瓣,dropbox都是很好的例子,只是在我们项目中,我们的python代码失控了。

上面提到的都是我们在实际项目中使用python遇到的问题,虽然最终都解决了,但是让我愈发的觉得,随着项目复杂度的增大,流量性能压力的增大,python并不是一个很好的选择。

为什么选择go

说完了python,现在来说说为什么我们选择go。其实除了python,我们也有其他的选择,java,php,lua(openresty),但最终我们选择了go。

虽然java和php都是最好的编程语言(大家都这么争的),但我更倾向一门更简单的语言。而openresty,虽然性能强悍,但lua仍然是动态语言,也会碰到前面说的动态语言一些问题。最后,前金山许式伟用的go,前快盘架构师葱头也用的go,所以我们很自然地选择了go。

go并不是完美,一堆值得我们吐槽的地方。

  • error,好吧,如果有语言洁癖的同学可能真的受不了go的语法,尤其是约定的最后一个返回值是error。项目里面经常会充斥这样的代码:

      if err := doA(); err != nil {
          if _, err := doB(); err != nil {
          }
      }
     

    难怪有个梗是对于一个需求,java的程序员在写配置的时候,go程序员已经写了大部分代码,但是当java的程序员写完的时候,go程序员还在写
    err != nil

  • 包管理,go的包管理太弱了,只有一个go get,也就是如果不小心更新了一个外部库,很有可能就导致现有的代码编译不过了。虽然已经有很多开源方案,譬如godep以及现在才出来的gb等,但毕竟不是官方的。貌似google也是通过vendor机制来管理第三方库的。希望go 1.5或者之后的版本能好好处理下这个问题。

  • GC,java的GC发展20年了,go才这么点时间,gc铁定不完善。所以我们仍然不能随心所欲的写代码,不然在大请求量下面gc可能会卡顿整个服务。所以有时候,该用对象池,内存池的一定要用,虽然代码丑了点,但好歹性能上去了。

  • 泛型,虽然go有inteface,但泛型的缺失会让我们在实现一个功能的时候写大量的重复代码,譬如int32和int64类型的sort,我们得为分别写两套代码,好冗余。go 1.4之后有了go generate的支持,但这种的仍然需要自己根据go的AST库来手动写相关的parser,难度也挺大的。虽然也有很多开源的generate实现,但毕竟不是官方的。

当然还有很多值得吐槽的地方,就不一一列举了,但是go仍旧有它的优势。

  • 静态语言,强类型。静态编译能帮我们检查出来大量的错误,go的强类型甚至变态到不支持隐式的类型转换。虽然写代码感觉很别扭,但减少了犯错的可能。
  • gofmt,应该这是我知道的第一个官方提供统一格式化代码工具的语言了。有了gofmt,大家的代码长一个样了,也就没有花括号到底放到结尾还是新开一行这种蛋疼的代码风格讨论了。因为大家的代码风格一样,所以看go的代码很容易。
  • 天生的并行支持,因为goroutine以及channel,用go写分布式应用,写并发程序异常的容易。没有了蛋疼的callback导致的代码逻辑割裂,代码逻辑都是顺序的。
  • 性能,go的性能可能赶不上c,c++以及openresty,但真的也挺强悍的。在我们的项目中,现在单机就部署了一个go的进程,就完全能够胜任以前200个python进程干的事情,而且CPU和MEM占用更低。
  • 运维部署,直接编译成二进制,扔到服务器上面就成,比python需要安装一堆的环境那是简单的太多了。当然,如果有cgo,我们也需要将对应的动态库给扔过去。
  • 开发效率,虽然go是静态语言,但我个人感觉开发效率真的挺高,直觉上面跟python不相上下。对于我个人来说,最好的例子就是我用go快速开发了非常多的开源组件,譬如ledisdb,go-mysql等,而这些最开始的版本都是在很短的时间里面完成的。对于我们项目来说,我们也是用go在一个月就重构完成了第一个版本,并发布。

实际项目中一些Go Tips

到现在为止,我们几乎所有的服务端项目都已经转向go,当然在使用的时候也遇到了一些问题,列出来算是经验分享吧。

  • godep,我们使用godep进行第三方库管理,但是godep我碰到的最大的坑就是build tag问题,如果一个文件有build tag,godep很有可能就会忽略这个文件。
  • IO deadline,如果能自己在应用层处理的都自己处理,go的deadline内部是timer来控制,但timer内部采用一个array来实现的heap,全局共用一个锁,如果大并发量,并且timer数量过多,timeout变动太频繁,很容易就引起性能问题。
  • GC,这个前面也说了,多用内存池,对象池,另外,我还发现,如果对象的生命周期跟goroutine一致,对性能的提升也不错,也在go的group问过相关问题,大家猜测可能是因为一些对象其实是在goroutine的8k栈上面分配的,所以一起回收没有额外GC了。
  • Go gob,如果要做RPC服务,gob并不是一个很好的选择,首先就跟python的pickle不通用,然后为了做不同系统的数据传入,任何包都必须带上类型的详细信息,size太大。go里面现在还没一套官方的RPC方案,gRPC貌似有上位的可能。

总结

虽然我现在选择了go,但是并不表示我以后不会尝试其他的语言。语言没有好坏,能帮我解决问题的就是好语言。但至少在很长的一段时间,我都会用go来进行开发。Let’ go!!!

原文:http://siddontang.com/2015/05/16/why-python-to-go/

Python: 聚焦爬虫:定向抓取系统的实现方法

网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列直到满足系统的一定停止条件。聚焦爬虫的工作流程较为复杂,需要根据一定的网页分析算法过滤与主题无关的链接,保留有用的链接并将其放入等待抓取的URL队列。然后,它将根据一定的搜索策略从队列中选择下一步要抓取的网页URL,并重复上述过程,直到达到系统的某一条件时停止。另外,所有被爬虫抓取的网页将会被系统存贮,进行一定的分析、过滤,并建立索引,以便之后的查询和检索;对于聚焦爬虫来说,这一过程所得到的分析结果还可能对以后的抓取过程给出反馈和指导。

相对于通用网络爬虫,聚焦爬虫还需要解决三个主要问题:

  • 对抓取目标的描述或定义;
  • 对网页或数据的分析与过滤;
  • 对URL的搜索策略。
  • 抓取目标的描述和定义是决定网页分析算法与URL搜索策略如何制订的基础。而网页分析算法和候选URL排序算法是决定搜索引擎所提供的服务形式和爬虫网页抓取行为的关键所在。这两个部分的算法又是紧密相关的。

    以下内容来自淘宝搜索引擎博客,应该是 一淘网的具体实现方案 。系统主要用到linux+mysql+redis+django+scrapy+webkit,其中scrapy+webkit作为抓取端,redis作为链接库存储,mysql作为网页信息存储,django作为爬虫管理界面,快速实现分布式抓取系统的原型。

    名词解析:

  • 抓取环:抓取环指的是spider在存储中获取url,从互联网上下载网页,然后将网页存储到数据库里面,最后在从存储里面获取下一个URL的一个流程。
  • Linkbase:链接库的存储模块,包含一般的链接信息;是抓取系统的核心,使用redis存储。
  • XPATH:一门在 XML 文档中查找信息的语言,XPath 可用来在 XML 文档中对元素和属性进行遍历, 是 W3C XSLT 标准的主要元素。使用XPATH以及相关工具lib进行链接抽取和信息抽取。
  • XPathOnClick:一个chrome的插件,支持点击页面元素,获取XPATH路径,用于编辑配置模板。
  • Redis:一个开源的KV的内存数据库,具备很好的数据结构的特征和很高的存取性能。用于存储linkbase信息
  • Django:爬虫管理工具,用于模板配置,系统监控反馈。Django在这里主要是用来管理一个数据库,使用Admin功能。
  • Pagebase:页面库,主要是存储网页抓取的结果,以及页面抽取的结果,和dump交互,使用mysql实现。
  • Scrapy:一个开源的机遇twisted框架的python的单机爬虫,该爬虫实际上包含大多数网页抓取的工具包,用于爬虫下载端以及抽取端。
  • 列表页:指的商品页面之外的所有页面
  • 详情页:比如商品B2C的抓取中,特指商品页面,比如: http://item.tmall.com/item.htm?id=10321272374
  • 系统架构

    一:存储 redis+mysql

    链接库(linkbase)是抓取系统的核心,基于性能和效率的考虑,本文采用基于内存的redis和磁盘的mysql为主,对于linkbase主要是存储抓取必须的链接信息,比如url,anchor,等等;对于mysql,则是存放抓取的网页,便于后续的抽取和处理。

    a) PageBase:使用Mysql分库分表,存放网页,如下图:

    b)Linkbase:使用Redis集群,存储linkbase信息。

    几个基本的数据结构:

    抓取队列(candidate list)分为待抓取的url队列和更新的url队列;队列存放urlhash,使用redis的list数据结构,对于新提取的url,push到对应的列表里面,对于spider抓取模块,从list pop得到。对于一个站点而言,抓取队列有两种类型:列表页抓取队列和详情页抓取队列。

    链接库(linkbase)链接库实际上是存储链接信息的DB;Key是urlhash,Value是linkinfo,包含url,purl,anchor,xpath。。。;在redis使用hash存储,直接存放在redis的里面。KV链接库,不区分页面类型。

    已抓取集合(crawled_set)已抓取集合指的是当前已经下载的页面的urlhash,存放已经抓取的网页,使用redis的set实现,set的key是urlhash,score是时间戳,已抓取集合主要是用来记录哪一些页面已经抓取和抓取的时间,用于后续的更新页面调度以及抓取信息的统计。同抓取队列一样,每一个站点有两种类型的已抓取集合,详情页和列表页。

    二:调度模块:

    调度模块是抓取系统的关键,调度系统的好坏决定了抓取系统的效率;这块是主要是在redis linkbase之上的数据结构,主要有抓取队列、抓取集合、抓取优先级等等数据结构组成;对于一个抓取循环来说:获取URL,提交到抓取模块的待抓取队列,启动抓取,抓取完成之后对新链接进行抽取,最后进入等待抓取的队列里面。

    调度系统的基本配置:

  • 频率(间隔多少秒)
  • 各个抓取列表的选取比例:get_detail,mod_detail,get_list,mod_list
  • 链接抽取:抽取页面的链接,进行除重,对于新的链接,插入到待抓取列表里
  • 内容抽取:按照模块的配置XPATH,抽取页面信息,并写入到pagebase中。
  • 离线调度:按照更新的比例,从crawled_set里面,定期选取url进入Mod队列里面进行刷新。
  • 三:抓取模块:

    抓取模块是抓取的必要条件,抓取模块来说,重要的是应付互联网上各式的问题,以及如何实现对对方站点的ip平衡,当然,这块是和调度系统的紧密结合的,对于抓取模块而言,本文主要使用scrapy工具包里面的下载模块。

    首先,抓取模块从linkbase获取对应站点的抓取url,进行页面下载,然后将页面信息写回到pipeline中,并完成链接抽取和页面抽取,同时调用调度模块,插入到linkbase和pagebase中。

    下载端设计:

  • IP:每台机器需要配置多个物理公网IP,下载的时候,随机选择一个IP下载
  • 抓取频度调整:读取配置文件,按照配置文件的抓取频率进行选取url
  • 四:配置界面:

    配置界面主要是对抓取系统的管理和配置,包括:站点feed、页面模块抽取、报表系统的反馈等等。

    类似于通用的抓取架构,本文提到的抓取系统架构如下图:

    Python: 聚焦爬虫:定向抓取系统的实现方法
    Python: 聚焦爬虫:定向抓取系统的实现方法

    一个完整的抓取数据流:

  • 用户提供种子URL
  • 种子URL进入linkbase中新URL队列中
  • 调度模块选取url进入到抓取模块的待抓取队列中
  • 抓取模块读取站点的配置文件,按照执行的频率进行抓取
  • 抓取的结果返回到pipeline接口中,并完成连接的抽取
  • 新发现的连接在linkbase里面进行dedup,并push到linkbase的新URL模块里面
  • 调度模块选取url进入抓取模块的待抓取队列,goto 4
  • end
  • 五、系统扩展

    本文提到的抓取系统,核心是调度和存储模块;其中,抓取,存储,调度都是通过数据进行交互的,因此,模块之间可以任意平行扩展,对于系统规模来说,只需要平行扩展mysql和redis存储服务集群以及抓取集群即可。当然,简单的扩展会带来一些问题:比如垃圾列表页的泛滥,链接库的膨胀等等问题,这些问题后续在讨论吧。

    原文:http://blogread.cn/it/article/4624?f=hot1

    Python: python保留指定文件、删除目录其他文件的功能

    由于给客户的发布版本上客户改动了些代码和图片,我们这边给他们更新publish都是增量更新(开发提供更新指定的文件,我们提取出来给客户进行覆盖更新),但有时需要更新的文件较多导致不得不一个一个的进行查找、替换,工作量大而且容易出错。所以用python写个保留pulish后目录的指定文件、删除其他文件的功能。

    代码如下

     1  import  os
      2  import  os.path
      3
     4  def  DeleteFiles(path,fileList):
      5  for  parent,dirnames,filenames in  os.walk(path):
      6
     7          FullPathList = []
      8          DestPathList = []
      9
    10  for  x in  fileList:
     11              DestPath = path + x
     12              DestPathList.append(DestPath)
     13
    14
    15  for  filename in  filenames:
    16              FullPath = os.path.join(parent,filename)
     17              FullPathList.append(FullPath)
     18
    19
    20  for  xlist in  FullPathList:
     21  if  xlist not  in  DestPathList:
     22                  os.remove(xlist) 

    代码解释:

    1、for parent,dirnames,filenames in os.walk(path): 该for循环用于遍历指定path的父文件夹、文件夹名(不含目录)、文件名

    2、

    for  x in  fileList:
                DestPath  = path + x
                DestPathList.append(DestPath)  

    该方法两个参数分别是path,filelist。path用来指定publish文件的存放目录,例如:’D:publish’,filelist通过list存放你希望保留的文件及该文件路径,例如:

    [r’1.txt’,r’a1.txt’],然后将path和filelist拼接起来存放到另一个列表中就是你希望保存文件的完整路径存放在DestPathList中,既[‘D:\publish\1.txt’,’D:\publish\a\1.txt’]

    3、

    for  filename in  filenames:
                FullPath  = os.path.join(parent,filename)
                FullPathList.append(FullPath)  

    将目录下所有文件的绝对路径存放在列表FullPathList中

    4、

    for  xlist in  FullPathList:
                 if  xlist not  in  DestPathList:
                    os.remove(xlist)  

    遍历FullPathList中元素跟DestPathList中元素进行比对,如果不相同则删除文件

    功能虽然简单,但工作中还是比较实用的,故在此留下脚印。

    –Storage  QQ:258324960

    原文:http://www.cnblogs.com/chub/p/4509921.html

    Python: Docker Compose—简化复杂容器应用的利器

    Compose是用于定义和运行复杂Docker应用的工具。你可以在一个文件中定义一个多容器的应用,然后使用一条命令来启动你的应用,然后所有相关的操作都会被自动完成。

    1. 安装Docker和Compose

    # 当前最新的Docker是1.6.2,Compose为1.2.0
    curl -s https://get.docker.io/ubuntu/ | sudo sh
    sudo apt-get update
    sudo apt-get install lxc-docker
    # 参考http://docs.docker.com/compose/install/#install-compose
    curl -L https://github.com/docker/compose/releases/download/1.2.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
    chmod +x /usr/local/bin/docker-compose上面这个方法真的慢出翔,可以通过Python pip安装。
    apt-get install python-pip python-dev
    pip install -U docker-compose 

    这样compose就安装好了,查看一下compose的版本信息:

    chmod +x /usr/local/bin/docker-compose
    docker-compose -version
    docker-compose 1.2.0 

    2. 使用Compose

    使用Compose只需要简单的三个步骤:首先,使用Dockerfile来定义你的应用环境:

    FROM python:2.7
    ADD ./code
    WORKDIR /code
    RUN pip install -r requirements.txt 

    其中,requirements.txt中的内容包括:

    flask
    redis

    再用Python写一个简单的app.py

    from flask importFlaskfrom redis importRedisimport os
    app =Flask(__name__)
    redis =Redis(host='redis', port=6379)@app.route('/')def hello():
        redis.incr('hits')return'Hello World! I have been seen %s times.'% redis.get('hits')if __name__ =="__main__>":
        app.run(host="0.0.0.0>", debug=True) 

    第二步,用一个compose.yaml来定义你的应用,他们可以在下个互隔离的容器中组成你的应用。

    web:
      build:.
      command: python app.py
      ports:-"5000:5000>"
      volumes:-.:/code
      links:- redis
    redis:
      image: redis 

    第三步,执行docker-compose up来启动你的应用,它会根据compose.yaml的设置来pull/run这俩个容器。

    Creating myapp_redis_1...
    Creating myapp_web_1...
    Building web...
    Step 0 : FROM python:2.7
    2.7: Pulling from python
    ...
    Status: Downloaded newer image for python:2.7
     ---> d833e0b23482
    Step 1 : ADD . /code
     ---> 1c04b1b15808
    Removing intermediate container 9dab91b4410d
    Step 2 : WORKDIR /code
     ---> Running in f495a62feac9
     ---> ffea89a7b090
    Attaching to myapp_redis_1, myapp_web_1
    ......
    redis_1 | [1] 17 May 10:42:38.147 * The server is now ready to accept connections on port 6379
    web_1   |  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
    web_1   |  * Restarting with stat 

    3. Yaml文件参考

    在上面的yaml文件中,我们可以看到compose文件的基本结构。首先是定义一个服务名,下面是yaml服务中的一些选项条目:

    image:镜像的ID

    build:直接从pwd的Dockerfile来build,而非通过image选项来pull

    links:连接到那些容器。每个占一行,格式为SERVICE[:ALIAS],例如 – db[:database]

    external_links:连接到该compose.yaml文件之外的容器中,比如是提供共享或者通用服务的容器服务。格式同links

    command:替换默认的command命令

    ports: 导出端口。格式可以是:

    ports:-"3000>"-"8000:8000>"-"127.0.0.1:8001:8001>" 

    expose:导出端口,但不映射到宿主机的端口上。它仅对links的容器开放。格式直接指定端口号即可。

    volumes:加载路径作为卷,可以指定只读模式:

    volumes:-/var/lib/mysql
     - cache/:/tmp/cache
     -~/configs:/etc/configs/:ro 

    volumes_from:加载其他容器或者服务的所有卷

    environment:- RACK_ENV=development
      - SESSION_SECRET

    env_file:从一个文件中导入环境变量,文件的格式为RACK_ENV=development

    extends:扩展另一个服务,可以覆盖其中的一些选项。一个sample如下:

    common.yml
    webapp:
      build:./webapp
      environment:- DEBUG=false- SEND_EMAILS=false
    development.yml
    web:extends:
        file: common.yml
        service: webapp
      ports:-"8000:8000>"
      links:- db
      environment:- DEBUG=true
    db:
      image: postgres 

    net:容器的网络模式,可以为”bridge”, “none”, “container:[name or id]”, “host”中的一个。

    dns:可以设置一个或多个自定义的DNS地址。

    dns_search:可以设置一个或多个DNS的扫描域。

    其他的 working_dir, entrypoint, user, hostname, domainname, mem_limit, privileged, restart, stdin_open, tty, cpu_shares,和 docker run命令是一样的,这些命令都是单行的命令。例如:

    cpu_shares:73
    working_dir:/code
    entrypoint: /code/entrypoint.sh
    user: postgresql
    hostname: foo
    domainname: foo.com
    mem_limit:1000000000
    privileged:true
    restart: always
    stdin_open:true
    tty:true 

    4. docker-compose常用命令

    在第二节中的 docker-compose up,这两个容器都是在前台运行的。我们可以指定-d命令以daemon的方式启动容器。除此之外,docker-compose还支持下面参数:

    –verbose:输出详细信息

    -f制定一个非docker-compose.yml命名的yaml文件

    -p设置一个项目名称(默认是directory名)

    docker-compose的动作包括:

    build:构建服务

    kill -s SIGINT:给服务发送特定的信号。

    logs:输出日志

    port:输出绑定的端口

    ps:输出运行的容器

    pull:pull服务的image

    rm:删除停止的容器

    run: 运行某个服务,例如docker-compose run web python manage.py shell

    start:运行某个服务中存在的容器。

    stop:停止某个服务中存在的容器。

    up:create + run + attach容器到服务。

    scale:设置服务运行的容器数量。例如:docker-compose scale web=2 worker=3

    参考:

    Compose Document

    原文:http://debugo.com/docker-compose/

    Python: Python – 装饰器使用过程中的误区

    曾灵敏 — APRIL 27, 2015

    装饰器基本概念

    大家都知道装饰器是一个很著名的设计模式,经常被用于AOP(面向切面编程)的场景,较为经典的有插入日志,性能测试,事务处理, Web权限校验Cache等。

    Python语言本身提供了装饰器语法(@),典型的装饰器实现如下:

    	@function_wrapper
    	def function():
    	   pass
    @实际上是python2.4才提出的语法糖,针对python2.4以前的版本有另一种等价的实现:
    	def function():
    		pass
    	function = function_wrapper(function)
    ##装饰器的两种实现
    函数包装器 - 经典实现
    	def function_wrapper(wrapped):
    		def _wrapper(*args, **kwargs):
    			return wrapped(*args, **kwargs)
    		return _wrapper
    	@function_wrapper
    	def function():
    		pass
     

    类包装器 – 易于理解

    	class function_wrapper(object):
    		def __init__(self, wrapped):
    			self.wrapped = wrapped
    		def __call__(self, *args, **kwargs):
    			return self.wrapped(*args, **kwargs)
    	@function_wrapper
    	def function():
    		pass
     

    函数(function)自省

    当我们谈到一个函数时,通常希望这个函数的属性像其文档上描述的那样,是被明确定义的,例如 __name____doc__

    针对某个函数应用装饰器时,这个函数的属性就会发生变化,但这并不是我们所期望的。

    	def function_wrapper(wrapped):
    		def _wrapper(*args, **kwargs):
    			return wrapped(*args, **kwargs)
    		return _wrapper
    	@function_wrapper
    	def function():
    		pass
    	>>> print(function.__name__)
    	_wrapper
     

    python标准库提供了 functools.wraps(),来解决这个问题。

    	import functools
    	def function_wrapper(wrapped):
    		@functools.wraps(wrapped)
    		def _wrapper(*args, **kwargs):
    			return wrapped(*args, **kwargs)
    		return _wrapper
    	@function_wrapper
    	def function():
    		pass
    	>>> print(function.__name__)
    	function
     

    然而,当我们想要获取被包装函数的参数( argument)或源代码( source code)时,同样不能得到我们想要的结果。

    	import inspect
    	def function_wrapper(wrapped): ...
    	@function_wrapper
       def function(arg1, arg2): pass
    	>>> print(inspect.getargspec(function))
    	ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)
    	>>> print(inspect.getsource(function))
    		@functools.wraps(wrapped)
    		def _wrapper(*args, **kwargs):
    			return wrapped(*args, **kwargs)
     

    包装类方法(@classmethod)

    当包装器( @function_wrapper)被应用于 @classmethod时,将会抛出如下异常:

        class Class(object):
            @function_wrapper
            @classmethod
            def cmethod(cls):
                pass
        Traceback (most recent call last):
          File "<stdin>>", line 1, in <module>
          File "<stdin>>", line 3, in Class
          File "<stdin>>", line 2, in wrapper
          File ".../functools.py>", line 33, in update_wrapper
            setattr(wrapper, attr, getattr(wrapped, attr))
        AttributeError: 'classmethod' object has no attribute '__module__'
     

    因为 @classmethod在实现时,缺少 functools.update_wrapper需要的某些属性。这是 functools.update_wrapper在python2中的bug,3.2版本已被修复,参考http://bugs.python.org/issue3445。

    然而,在python3下执行,另一个问题出现了:

        class Class(object):
    	@function_wrapper
    	@classmethod
    	def cmethod(cls):
    	    pass
        >>> Class.cmethod()
        Traceback (most recent call last):
          File "classmethod.py>", line 15, in <module>
    	Class.cmethod()
          File "classmethod.py>", line 6, in _wrapper
    	return wrapped(*args, **kwargs)
        TypeError: 'classmethod' object is not callable
     

    这是因为包装器认定被包装的函数( @classmethod)是可以直接被调用的,但事实并不一定是这样的。被包装的函数实际上可能是描述符( descriptor),意味着为了使其可调用,该函数(描述符)必须被正确地绑定到某个实例上。关于描述符的定义,可以参考https://docs.python.org/2/howto/descriptor.html。

    总结 – 简单并不意味着正确

    尽管大家实现装饰器所用的方法通常都很简单,但这并不意味着它们一定是正确的并且始终能正常工作。

    如同上面我们所看到的, functools.wraps()可以帮我们解决 __name____doc__的问题,但对于获取函数的参数(argument)或源代码( source code)则束手无策。

    以上问题, wrapt都可以帮忙解决,详细用法可参考其官方文档:http://wrapt.readthedocs.org

    本文作者系 OneAPM工程师曾灵敏 ,想阅读更多好的 技术文章,请访问OneAPM官方技术博客。

    原文:http://www.ituring.com.cn/article/198266

    Python: 从多说迁移博客评论至 Disqus

    按理来说,应该是一个很简单的过程。从多说导出标准的备份文件,导入 Disqus,就完事了。但是我就整整的折腾了几天,评论是导入进去了,但是在博文页面始终没有把原来的评论显示出来。今天下午,甚至向 Disqus 官方发送了求救邮件。

    就在刚才,才发现原来 Disqus 是根据文章的 URL 作为 Primary Key 的,而我新的博客系统的文章 URL 结尾比原来的少了个 /。擦,就是这一个字符,导致没有把原先的评论显示出来

    Old:  http: //example.com/article
    New:  http: //example.com/article/
     

    导入的具体过程

    首先,在多说的后台将评论(包括文章)导出为一个 export.json文件。这个文件格式是不被 Disqus 认的,所以我们得把它转换成 wordpress 导出的文件格式

    轮子已经有人造了,我们就不再重复造轮子。使用这个轮子 JamesPan/duoshuo-migratorexport.json进行转换

    pip install lxml
    python duoshuo-migrator.py  -i  ~/Desktop/export.json   -o disqus.xml
     

    将文件转换为 disqus.xml

    最后把 disqus.xml通过 Disqus 后台的 Discussions -> Import 进行导入。官方写着24小时会处理完队列,实际上,如果评论少的话,马上评论就被成功导入进去了

    反正,就得坑在 Disqus 是根据文章的 URL 作为 Primary Key ,这个是文章的唯一重点

    写在最后

    其实,这篇博客没有在表达多说比 Disqus 差。在国内的话,多说加载比 Disqus 快,默认的社交分享也比较符合中国的国情。但是,有一颗折腾的心,没事多折腾折腾,其实也是挺好的啦!

    原文:http://dearb.me/archive/2015-05-17/transfer-comments-from-duoshuo-to-disqus/

    Python: 解决python操作redis cluster集群时遇到的问题

    今天在测试redis-py-cluster的时候,遇到一个奇怪的问题…   一开始以为是python的redis cluster遇到的bug … …   在作者的issue里也看到了别人也同样遇到我这样的问题… …    提示的错误是这样的…

    原文链接是在  http://xiaorui.cc/?p=1478 http://xiaorui.cc

    Python: 解决python操作redis cluster集群时遇到的问题
    Python: 解决python操作redis cluster集群时遇到的问题

    Python

    root@ubuntu:~# python test.py
    [{'host': '127.0.0.1', 'port': '7000'}]
    Traceback (most recent call last):
      File "test.py>", line 24, in <module>
        main()
      File "test.py>", line 21, in main
        r.set('nima', 'a')
      File "/usr/local/lib/python2.7/dist-packages/redis/client.py>", line 1055, in set
        return self.execute_command('SET', *pieces)
      File "build/bdist.linux-x86_64/egg/rediscluster/utils.py>", line 82, in inner
      File "build/bdist.linux-x86_64/egg/rediscluster/client.py>", line 308, in execute_command
    rediscluster.exceptions.RedisClusterException: Too many Cluster redirections 

    这个是我测试的代码, 代码的逻辑本身是没有问题的,但是奇怪的是会遇到 rediscluster.exceptions.RedisClusterException: Too many Cluster redirections 的问题…

    Python

    # -*- coding: utf-8 -*
    import os,sys,time,traceback
    import redis
    from rediscluster import StrictRedisCluster
    def main():
        serverip='127.0.0.1'
        #startup_nodes=[{"host>": serverip,"port>": str(i)} for i in xrange(7000, 7007)]
        startup_nodes=[{"host>": serverip,"port>": i} for i in xrange(7000, 7007)]
        print startup_nodes
        try:
            r = StrictRedisCluster(startup_nodes=startup_nodes)
        except Exception, err:
            print err
            print 'failed to connect cluster'
            sys.exit(0)
        #for i in xrange(1000):
        r.set('nima', 'a')
    if __name__=='__main__':
        main() 

    既然代码没有问题,那应该是redis cluster出现了问题… 

    root@ubuntu:~# redis-cli -c -p 7000

    127.0.0.1:7000> set nima nia

    -> Redirected to slot [16259] located at :0

    Could not connect to Redis at :0: Name or service not known

    Could not connect to Redis at :0: Name or service not known

    not connected>

    使用  /redis-3.0.1/src/redis-trib.rb check 127.0.0.1:7000 的时候,发现以前是4个master,结果现在成三个master了,还有就是多个slave节点被剔除  这时候把这些down的reids都启动就OK了… 

    Python

    root@ubuntu:~# ./redis-3.0.1/src/redis-trib.rb check 127.0.0.1:7000|more
    Connecting to node 127.0.0.1:7000: OK
    Connecting to node 127.0.0.1:7007: OK
    Connecting to node 127.0.0.1:7004: OK
    Connecting to node 127.0.0.1:7003: OK
    Connecting to node 127.0.0.1:7002: OK
    Connecting to node 127.0.0.1:7006: OK
    Connecting to node 127.0.0.1:7001: OK
    Connecting to node 127.0.0.1:7005: OK
    &gt;&gt;&gt; Performing Cluster Check (using node 127.0.0.1:7000)
    M: b4f0e1fde9abbcef6cfaea86232afb07cc19eb77 127.0.0.1:7000
       slots:0-4095 (4096 slots) master
       1 additional replica(s)
    S: d75e766de5f82734ffb3ff8ef944d353b78db740 127.0.0.1:7007
       slots: (0 slots) slave
       replicates 82b7b92878dc1af4a6f9a0e7f20535f86771a61f
    S: 95272ed07fa70058c8167a93936f6e7093152a90 127.0.0.1:7004
       slots: (0 slots) slave
       replicates b4f0e1fde9abbcef6cfaea86232afb07cc19eb77
    M: 82b7b92878dc1af4a6f9a0e7f20535f86771a61f 127.0.0.1:7003
       slots:12288-16383 (4096 slots) master
       1 additional replica(s)
    M: ee2e48c90a4ac6fa9128c4f06600234eb9a05d4b 127.0.0.1:7002
       slots:8192-12287 (4096 slots) master
       1 additional replica(s)
    S: e83464a6948147193be25cf8bb8aea66ce3616a6 127.0.0.1:7006
       slots: (0 slots) slave
       replicates ee2e48c90a4ac6fa9128c4f06600234eb9a05d4b
    M: 5bd0681b67d775ec0a67b84481c5bbe802216f49 127.0.0.1:7001
       slots:4096-8191 (4096 slots) master
       1 additional replica(s)
    S: 39ef91564db8a85ca4caa03f65b03ed24cc79cd7 127.0.0.1:7005
       slots: (0 slots) slave
       replicates 5bd0681b67d775ec0a67b84481c5bbe802216f49
    [OK] All nodes agree about slots configuration.
    ... Check for open slots...
    ... Check slots coverage...
    [OK] All 16384 slots covered. 

    因为redis的日志配置有问题,所有刚才的问题的原因找不到了…   这样咱们特意的干掉一组redis主从…  貌似根前面的问题不太一样..  先前是 Too many Cluster redirections ,   但是cluster info的状态是OK的…. 这次是 cluster info > cluster_state:fail

    >>> Check for open slots…
    >>> Check slots coverage…
    [ERR] Not all 16384 slots are covered by nodes.
    oot@ubuntu:~# redis-cli -c -p 7000
    127.0.0.1:7000> set a a
    (error) CLUSTERDOWN The cluster is down

    我们可以用redis-trib.rb fix 来修复集群…. ….   /redis-3.0.1/src/redis-trib.rb fix 127.0.0.1:7000  ,如果还是启动不了的话,可以把相关的cluster-config-file节点同步信息删掉。

    另外这里转载下redis cluster的命令集,操作redis集群是个很蛋疼的事情,大家可以用下面的命令多尝试下..

    集群  
    CLUSTER INFO 打印集群的信息 ,可以知道集群是否好坏
    CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。  
    节点  
    CLUSTER MEET 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。  
    CLUSTER FORGET 从集群中移除 node_id 指定的节点。  
    CLUSTER REPLICATE 将当前节点设置为 node_id 指定的节点的从节点。  
    CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。  
    槽(slot)  
    CLUSTER ADDSLOTS [slot …] 将一个或多个槽(slot)指派(assign)给当前节点。  
    CLUSTER DELSLOTS [slot …] 移除一个或多个槽对当前节点的指派。  
    CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。  
    CLUSTER SETSLOT NODE 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。  
    CLUSTER SETSLOT MIGRATING 将本节点的槽 slot 迁移到 node_id 指定的节点中。  
    CLUSTER SETSLOT IMPORTING 从 node_id 指定的节点中导入槽 slot 到本节点。  
    CLUSTER SETSLOT STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。  
    键  
    CLUSTER KEYSLOT 计算键 key 应该被放置在哪个槽上。  
    CLUSTER COUNTKEYSINSLOT 返回槽 slot 目前包含的键值对数量。  
    CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。  

    看来redis cluster一定要多尝试…. 别到了线上后,就傻逼了…

    原文:http://xiaorui.cc/2015/05/17/解决python操作redis-cluster集群时遇到的问题/