常用模块

urllib2 :用于发送网络请求,获取数据

(Pyhton2中的urllib2工具包,在Python3中分拆成了urllib.request和urllib.error两个包。)

json:用于解析获得的数据

模块安装

在cmd下执行:python -m  pip install 模块名

pip升级

升级命令: python -m pip install --upgrade pip


 urllib2 :用于发送网络请求,获取数据

import urllib2

web = urllib2.urlopen('http://www.baidu.com')

content = web.read()

print content


 json:解析json数据 

如:

{

"weatherinfo": {

"city": "南京",

"cityid": "101190101",

"temp1": "37℃",

"temp2": "28℃",

"weather": "多云",

"img1": "d1.gif",

"img2": "n1.gif",

"ptime": "11:00"

}

}

可以看出,它像是一个字典的结构,但是有两层。最外层只有一个key--“weatherinfo”,它的value是另一个字典,里面包含了好几项天气信息。

虽然看上去像字典,但它对于程序来说,仍然是一个字符串,只不过是一个满足json格式的字符串。用python中json模块提供的loads方法,把它转成一个真正的字典。

import json

data = json.loads(content)

data已经是一个字典,在控制台中输出它,看上去和content没什么区别,只是编码上有些不同:

{u'weatherinfo': {u'city': u'\u5357\u4eac', u'ptime': u'11:00', u'cityid': u'101190101', u'temp2': u'28\u2103', u'temp1': u'37\u2103', u'weather': u'\u591a\u4e91', u'img2': u'n1.gif', u'img1': u'd1.gif'}}


面向对象

类的属性:域(变量,包括类变量和属性变量)和方法

python是一种高度面向对象的语言,它其中的所有东西其实都是对象。比如,字符串即是一个对象

dir()方法可以查看一个类/变量的所有属性:s='a' ;dir(s);

关键字class用于创建一个类。pass语句表示一个空的代码块。类名()表示创建对象。

class MyClass:

pass

mc = MyClass()

print mc

调用类变量的方法是“对象.变量名”。

注意:类方法和函数的区别在于,类方法第一个参数必须为self。而在调用类方法的时候,通过“对象.方法名()”格式进行调用,而不需要额外提供self这个参数的值。self在类方法中的值,就是你调用的这个对象本身。

class MyClass:

name = 'Sam'

def sayHi(self):

print 'Hello %s' % self.name

mc = MyClass()

print mc.name

mc.name = 'Lily'

mc.sayHi()


类的继承

class Vehicle:  ----------基类

def __init__(self, speed): -----__init__是python内置方法(函数名前后有__),在类创建时会自动调用以初始化类,其参数要在创建类时提供。

self.speed = speed

def drive(self, distance):

print 'need %f hour(s)' % (distance / self.speed)

class Bike(Vehicle):-----------类名后的括号内参数代表父类(继承关系)

pass  ------不需要有额外的功能

class Car(Vehicle):

def __init__(self, speed, fuel):-----------扩展自己的初始化函数

Vehicle.__init__(self, speed)----------首先调用父类的初始化方法,注意此处要加上self

self.fuel = fuel

def drive(self, distance):

Vehicle.drive(self, distance)

print 'need %f fuels' % (distance * self.fuel)

b = Bike(15.0)--------初始化类时的参数是__init__的参数

c = Car(80.0, 0.012)

b.drive(100.0)

c.drive(100.0)


 and-or 技巧

看下面这段代码:

a = "heaven"

b = "hell"

c = True and a or b

print c

d = False and a or b

print d

输出:

heaven

hell

bool and a or b语句中,当bool条件为真时,结果是a;当bool条件为假时,结果是b。这和c/c++等语言的bool?a:b表达式很像。

因此,一个if-else语句表述的逻辑:

if a > 0:

print "big"

else:

print "small"

就可以直接写成:print (a > 0) and "big" or "small"

但是,和c语言中的?:表达式不同,这里的and or语句是利用了python中的逻辑运算实现的。当a本身是个假值(如0,"")时,结果就不同了:

a = ""

b = "hell"

c = True and a or b

print c

得到的结果不是""而是"hell"。因为""和"hell"做or的结果是"hell"。

所以,and-or真正的技巧在于,确保a的值不会为假。最常用的方式是使 a 成为 [a] 、 b 成为 [b],然后使用返回值列表的第一个元素

a = ""

b = "hell"

c = (True and [a] or [b])[0]

print c

由于[a]是一个非空列表,所以它决不会为假。即使a是0或者''或者其它假值,列表[a]也为真,因为它有一个元素。

在两个常量值进行选择时,and-or会让你的代码更简单。常用于lambda表达式。


python自带数学运算模块 math 

import math

math包里有两个常量:

1)math.pi  圆周率π:3.141592...

2)math.e  自然常数:2.718281...

数值运算:

math.ceil(x)  对x向上取整,比如x=1.2,返回2.0(py3返回2)

math.floor(x)  对x向下取整,比如x=1.2,返回1.0(py3返回1)

math.pow(x,y)  指数运算,得到x的y次方

math.log(x)  对数,默认基底为e。可以使用第二个参数,来改变对数的基底。比如math.log(100, 10)

math.sqrt(x)  平方根

math.fabs(x)  绝对值

三角函数: 

math.sin(x)

math.cos(x)

math.tan(x)

math.asin(x)

math.acos(x)

math.atan(x)

注意:这里的x是以弧度为单位,所以计算角度的话,需要先换算

角度和弧度互换: 

math.degrees(x)   弧度转角度

math.radians(x)  角度转弧度


  正则表达式

正则表达式就是记录文本规则的代码。python中的正则表达式库,所做的事情是利用正则表达式来搜索文本。或者用来判断输入的文本是否符合规范,或进行分类

示例:

import re

text = "Hi, I am Shirley Hilton. I am his wife."

m = re.findall(r"hi", text)

if m:

print m

else:

print 'not match'

re模块

re是python里的正则表达式模块。findall是其中一个方法,用来按照提供的正则表达式,去匹配文本中的所有符合条件的字符串。返回结果是一个包含所有匹配的list。

规则: 

\b

\b表示单词的开头或结尾,空格、标点、换行都算是单词的分割。“\b”自身又不会匹配任何字符,它代表的只是一个位置。所以单词前后的空格标点之类不会出现在结果里。

\B

\B - 匹配不是单词开头或结束的位置

[]

[]表示满足括号中任一字符,比如“[hi]”,它就不是匹配“hi”了,而是匹配“h”或者“i”。如果把正则表达式改为“[Hh]i”,就可以既匹配“Hi”,又匹配“hi”了。

r  

r,是raw的意思,它表示对字符串不进行转义。\\也表示不转义,但是如果有很多个\\会显得比较乱,这样直接在字符串前加个r就能解决。

>>> print "\bhi"

hi

>>> print r"\bhi"

\bhi

>>> print "\\bhi"

\bhi

.

“.”在正则表达式中表示除换行符以外的任意字符

\S

“\S”表示任意非空白字符。注意是大写字符S。

\s

\s - 匹配任意的空白符,小写s,与大写S相反

1)、^匹配字符串的开始位置。^1\d*x?表示以1开头的数字,结尾可能有x

2)、^与[]合用,表示非。[a]的反义是[^a],表示除a以外的任意字符。[^abcd]就是除abcd以外的任意字符。

$

$ - 匹配字符串的结束

?

“?”表示任意一个字符

*

“*”表示其前面字符重复任意次数(0个或多个)。“*”不是表示字符,而是表示数量:它表示前面的字符可以重复任意多次(包括0次),只要满足这样的条件,都会被表达式匹配上。

+

与*类似,+表示1个或多个

表示重复0次或1次

{n,}

重复n次或更多次

{n,m}

重复n到m次

\d

\d表示数字,即等价于【0-9】。表示任意长度的数字,可以用[0-9]*或者\d*。

\D

\D - 匹配任意非数字的字符

{}  {数字}

比如11位的数字:\d{11}

\w

\w - 匹配字母或数字或下划线或汉字(3.x版本可以匹配汉字,但2.x版本不可以)

 \W

\W - 匹配任意不是字母,数字,下划线,汉字的字符

“|”

“|”相当于python中“or”的作用,它连接的两个表达式,只要满足其中之一,就会被算作匹配成功。使用“|”时,要特别提醒注意的是不同条件之间的顺序。匹配时,会按照从左往右的顺序,一旦匹配成功就停止验证后面的规则。

正则表达式不只是用来从一大段文字中抓取信息,很多时候也被用来判断输入的文本是否符合规范,或进行分类。例子:

^\w{4,12}$

这个表示一段4到12位的字符,包括字母或数字或下划线或汉字,可以用来作为用户注册时检测用户名的规则。(但汉字在python2.x里面可能会有问题)

\d{15,18}

表示15到18位的数字,可以用来检测身份证号码

^1\d*x?

以1开头的一串数字,数字结尾有字母x,也可以没有。有的话就带上x。

转义字符\

如果我们确实要匹配.或者*字符本身,而不是要它们所代表的元字符,那就需要用\.或\*。\本身也需要用\\。

比如"\d+\.\d+"可以匹配出123.456这样的结果。


random模块

from random import randint

randint(1, 10)

随机数

random模块的作用是产生随机数。

random.randint(a, b)可以生成一个a到b间的随机整数,包括a和b。

a、b都必须是整数,且必须b≥a。当等于的时候,比如:random.randint(3, 3)的结果就永远是3

random.random()生成一个0到1之间的随机浮点数,包括0但不包括1,也就是[0.0, 1.0)。

random.uniform(a, b)生成a、b之间的随机浮点数。不过与randint不同的是,a、b无需是整数,也不用考虑大小。

random.uniform(1.5, 3),random.uniform(3, 1.5),这两种参数都是可行的。random.uniform(1.5, 1.5)永远得到1.5。

random.choice(seq)从序列中随机选取一个元素。seq需要是一个序列,比如list、元组、字符串。

random.choice([1, 2, 3, 5, 8, 13]) #list

random.choice('hello') #字符串

random.choice(['hello', 'world']) #字符串组成的list

random.choice((1, 2, 3)) #元组

random.randrange(start, stop, step)生成一个从start到stop(不包括stop),间隔为step的一个随机数。start、stop、step都要为整数,且start<stop。start和step都可以不提供参数,默认是从0开始,间隔为1。但如果需要指定step,则必须指定start。

比如:

random.randrange(1, 9, 2)

就是从[1, 3, 5, 7]中随机选取一个。

start和step都可以不提供参数,默认是从0开始,间隔为1。但如果需要指定step,则必须指定start。

random.randrange(4) #[0, 1, 2, 3]

random.randrange(1, 4) #[1, 2, 3]

random.randrange(start, stop, step)其实在效果上等同于random.choice(range(start, stop, step))

random.sample(population, k)从population序列中,随机获取k个元素,生成一个新序列。sample不改变原来序列。

random.shuffle(x)把序列x中的元素顺序打乱。shuffle直接改变原有的序列。

random.seed(x) 设置生成随机数用的整数起始值。调用任何其他random模块函数之前调用这个函数。

参数x 是下一个随机数的种子。如果省略,则需要系统时间,以产生下一个随机数。


time模块提供了一些与时间相关的方法。利用time,可以简单地计算出程序运行的时间。对于一些比较复杂、耗时较多的程序,可以通过这种方法了解程序中哪里是效率的瓶颈,从而有针对性地进行优化。

计时

在计算机领域有一个特殊的时间,叫做epoch,它表示的时间是1970-01-01 00:00:00 UTC。

time模块的一个方法time.time(),返回的就是从epoch到当前的秒数(不考虑闰秒)。这个值被称为unix时间戳。

用这个方法得到程序开始和结束所用的时间,进而算出运行的时间:

import time

starttime = time.time()

print 'start:%f' % starttime

for i in range(10):

print i

endtime = time.time()

print 'end:%f' % endtime

print 'total time:%f' % (endtime-starttime)

time.sleep(secs),可以让程序暂停secs秒。

在抓取网页的时候,适当让程序sleep一下,可以减少短时间内的请求,提高请求的成功率。


Python Shell

一般来说,有两种运行 python 代码的方法:

1. 使用交互式的带提示符的解释器

2. 使用源文件

第一种方法,所谓“交互式的带提示符的解释器”,也被称做 python shell。当你安装好 python,并正确配置系统变量 PATH 后(linux 和 mac 上通常都预装并配置好了 python),在命令行里输入 python,会看到诸如以下的提示:

$ python

Python 2.7.5 (default, Aug 25 2013, 00:04:04)

[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin

Type "help", "copyright", "credits" or "license" for more information.

>>>

python shell 里写好的代码也很难保存(至少我目前还不知道有什么可行的方法)。所以一般并不会用它来“真正地”写代码。当你需要写一个相对完整的 python 程序时,你需要写在一个“源文件”中。这就是运行 python 的第二种方法

用一个文本编辑器新建一个文件,在里面输入:print "hello world"

保存这个文件为 hello.py。注意,不要命名为 print.py。不要以任何 python 的内置方法或者你会使用到的模块名来命名你自己的代码文件。

然后在命令行中,进入到这个文件所在的文件夹,输入 python hello.py。你会看到:

$python hello.py

hello world

$

这时候不会进入 python shell,而是直接输出了程序的结果。换句话说,python 执行了写在源文件 hello.py 中的代码。

python 自带了一个叫做 IDLE 的编辑器。如果要编辑源文件,则需要在菜单栏中选择 File -> New File。这时打开的新窗口就是源文件窗口。在里面写好你的 python 代码后,点击菜单栏上的 Run -> Run Module,即可执行


对象的序列化与反序列化 :pickle模块

pickle可以把任何 Python 对象存储在文件中,再把它原样取出来。

例:

import pickle

test_data = ['Save me!', 123.456, True]

f = file('test.data', 'w')

pickle.dump(test_data, f)

f.close()

这样就把 test_data 这个 list 存储在了文件 test.data 中。你可以用文本编辑器打开 test.data 查看里面的内容:

(lp0

S'Save me!'

p1

aF123.456

aI01

a.

取对象:

import pickle

f = file('test.data')

test_data = pickle.load(f)

f.close()

print test_data

控制台的输出:['Save me!', 123.456, True],和存储前的数据是一致的。

如果要保存多个对象一种方法是把这些对象先全部放在一个序列中,在对这个序列进行存储

a = 123

b = "hello"

c = 0.618

data = (a, b, c)

...

pickle.dump(data, f)

另一种方法就是依次保存和提取:

...

pickle.dump(a, f)

pickle.dump(b, f)

pickle.dump(c, f)

...

x = pickle.load(f)

y = pickle.load(f)

z = pickle.load(f)

dump 方法可以增加一个可选的参数,来指定用二进制来存储:pickle.dump(data, f, True)

而 load 方法会自动检测数据是二进制还是文本格式,无需手动指定。

【特别说明】python3中,通过pickle对数据进行存储时,必须用二进制(b)模式读写文件。

Python 还提供了另一个模块 cPickle,它的功能及用法和 pickle 模块完全相同,只不过它是用C语言编写的,因此要快得多(比pickle快1000倍)。


列表表达式List Comprehension

所谓列表表达式(也有翻译成列表解析\列表综合),就是通过一个已有的列表生成一个新的列表。例:

假设有一个由数字组成的 list,现在需要把其中的偶数项取出来,组成一个新的 list。一种比较“正常”的方法是:

list_1 = [1, 2, 3, 5, 8, 13, 22]

list_2 = []

for i in list_1:

  if i % 2 == 0:

    list_2.append(i)

print list_2

输出:[2, 8, 22]

使用列表解析实现同样的效果:

list_1 = [1, 2, 3, 5, 8, 13, 22]

list_2 = [i for i in list_1 if i % 2 == 0]

print list_2

输出:[2, 8, 22]

[i for i in list_1] 会把 list_1 中的每一个元素都取出来,构成一个新的列表。

如果需要对其中的元素进行筛选,就在后面加上判断条件 if。所以 [i for i in list_1 if i % 2 == 0] 就是把 list_1 中满足 i % 2 == 0 的元素取出来组成新列表。

在构建新列表时,还可以对取出的元素做操作。比如,对于原列表中的偶数项,取出后要除以2,则可以通过 [i / 2 for i in list_1 if i % 2 == 0] 来实现。输出为 [1, 4, 11]。


lambda 表达式

lambda 表达可以被看做是一种匿名函数。可以快速定义一个极度简单的单行函数。

lambda 表达式的语法格式lambda 参数列表: 表达式

定义 lambda 表达式时,参数列表周围没有括号,返回值前没有 return 关键字,也没有函数名称。

它的写法比 def 更加简洁。但是,它的主体只能是一个表达式,不可以是代码块,甚至不能是命令(print 不能用在 lambda 表达式中)。所以 lambda 表达式能表达的逻辑很有限。

lambda 表达式创建了一个函数对象,可以把这个对象赋值给一个变量进行调用。

譬如这样一个实现三个数相加的函数:

def sum(a, b, c):

  return a + b + c

调用:

print sum(1, 2, 3)

print sum(4, 5, 6)

如果使用 lambda 表达式来实现:

sum = lambda a, b, c: a + b + c

调用:

print sum(1, 2, 3)

print sum(4, 5, 6)

看一个复杂一点的例子,把 lambda 表达式用在 def 函数定义中

def fn(x):

  return lambda y: x + y

调用:

a = fn(2)

print a(3)

输出:

5

fn 函数的返回值是一个 lambda 表达式,也就等于是一个函数对象。当以参数2来调用 fn 时,得到的结果就是:

lambda y: 2 + y

a = fn(2) 就相当于:a = lambda y: 2 + y

所以 a(3) 的结果就是5。

任何可以使用 lambda 表达式的地方,都可以通过普通的 def 函数定义来替代。在一些需要重复使用同一函数的地方,def 可以避免重复定义函数。而对于像 filter、sort 这种需要内嵌函数的方法,lambda 表达式就会显得比较合适。


变量的作用域

当函数内部定义了一个变量,无论是作为函数的形参,或是另外定义的变量,它都只在这个函数的内部起作用,这样在函数内部定义的变量被称为“局部变量”。这个函数体就是这个变量的作用域。函数外即使有和它名称相同的变量,也没有什么关联。

如:

def func(x):

  print 'X in the beginning of func(x): ', x

  x = 2

  print 'X in the end of func(x): ', x

调用:

x = 50

func(x)

print 'X after calling func(x): ', x

输出:

X in the beginning of func(x):  50

X in the end of func(x):  2

X after calling func(x):  50

如果期望在函数 内部改变外部变量的值,有两个方法:

1、在函数内部用return把改变后的变量值作为函数返回值传递出来,再赋值给变量。

return x

x = func(x)

2、使用全局变量global

在 Python 的函数定义中,可以给变量名前加上 global 关键字,这样其作用域就不再局限在函数块中,而是全局的作用域。

例:

def func():

  global x

  print 'X in the beginning of func(x): ', x

  x = 2

  print 'X in the end of func(x): ', x

调用:

x = 50

func()

print 'X after calling func(x): ', x

输出:

X in the beginning of func(x):  50

X in the end of func(x):  2

X after calling func(x):  2

建议在写代码的过程中,显式地通过 global 来使用全局变量,避免在函数中直接使用外部变量。

比如:

def func():

  print 'X in the beginning of func(x): ', x

  # x = 2

  print 'X in the end of func(x): ', x

调用:

x = 50

func()

print 'X after calling func(x): ', x

输出:

X in the beginning of func(x):  50

X in the end of func(x):  50

X after calling func(x):  50

程序可以正常运行。虽然没有指明 global,函数内部还是使用到了外部定义的变量。然而一旦加上x = 2这句,程序就会报错。因为这时候,x 成为一个局部变量,它的作用域从定义处开始,到函数体末尾结束。


map 函数

来看两个问题:

1. 假设有一个数列,如何把其中每一个元素都翻倍?

2. 假设有两个数列,如何求和?

第一个问题,普通程序员大概会这么写:

lst_1 = [1,2,3,4,5,6]

lst_2 = []

for item in lst_1:

  lst_2.append(item * 2)

print lst_2

Python 程序员大概会这么写:

lst_1 = [1,2,3,4,5,6]

lst_2 = [i * 2 for i in lst_1]

print lst_2

也可以用map来实现:

lst_1 = (1,2,3,4,5,6)    #数据改为了元组

lst_2 = map(lambda x: x * 2, lst_1)   #函数用 lambda 表达式替代

print lst_2

map 是 Python 自带的内置函数,它的作用是把一个函数应用在一个(或多个)序列上,把列表中的每一项作为函数输入进行计算,再把计算的结果以列表的形式返回。

map 的第一个参数是一个函数,之后的参数是序列,可以是 list、tuple。如:

lst_1 = [1,2,3,4,5,6]

def double_func(x):

  return x * 2

lst_2 = map(double_func, lst_1)

print lst_2

map 中的函数可以对多个序列进行操作。最开始提出的第二个问题,除了通常的 for 循环写法,如果用列表综合的方法比较难实现,但用 map 就比较方便:

lst_1 = [1,2,3,4,5,6]

lst_2 = [1,3,5,7,9,11]

lst_3 = map(lambda x, y: x + y, lst_1, lst_2)

print lst_3

map 中的函数会从对应的列表中依次取出元素,作为参数使用,同样将结果以列表的形式返回。所以要注意的是,函数的参数个数要与 map 中提供的序列组数相同,即函数有几个参数,就得有几组数据。

对于每组数据中的元素个数,如果有某组数据少于其他组,map 会以 None 来补全这组参数

此外,当 map 中的函数为 None 时,结果将会直接返回参数组成的列表。如果只有一组序列,会返回元素相同的列表,如果有多组数列,将会返回每组数列中,对应元素构成的元组所组成的列表。如:

lst_1 = [1,2,3,4,5,6]

lst_2 = [1,3,5,7,9,11]

lst_3 = map(None, lst_1)

print lst_3

lst_4 = map(None, lst_1, lst_2)

print lst_4

结果:

[1, 2, 3, 4, 5, 6]
[(1, 1), (2, 3), (3, 5), (4, 7), (5, 9), (6, 11)]


reduce 函数

map 可以看作是把一个序列根据某种规则,映射到另一个序列。reduce 做的事情就是把一个序列根据某种规则,归纳为一个输出。

例:求1累加到100的和,

寻常的做法大概是这样:

sum = 0

for i in xrange(1, 101):

  sum += i

print sum

如果用 reduce 函数,就可以写成:

lst = xrange(1, 101)

def add(x, y):

   return x + y

print reduce(add, lst)

函数:reduce(function, iterable[, initializer])

第一个参数是作用在序列上的方法,第二个参数是被作用的序列,这与 map 一致。另外有一个可选参数,是初始值。

function 需要是一个接收2个参数,并有返回值的函数。它会从序列 iterable 里从左到右依次取出元素,进行计算。每次计算的结果,会作为下次计算的第一个参数。

提供初始值 initializer 时,它会作为第一次计算的第一个参数。否则,就先计算序列中的前两个值。

如果把刚才的 lst 换成 [1,2,3,4,5],那 reduce(add, lst) 就相当于 ((((1+2)+3)+4)+5)。

同样,可以用 lambda 函数:reduce((lambda x, y: x + y), xrange(1, 101))

在对于一个序列进行某种统计操作的时候,比如求和,或者诸如统计序列中元素的出现个数等,可以选择使用 reduce 来实现。相对可以使代码更简洁。

Python3 里,reduce已经被移出内置函数,使用 reduce 需要先通过 from functools import reduce 引入。


多线程

python 里有一个 thread 模块,其中提供了一个函数:

start_new_thread(function, args[, kwargs])

function 是开发者定义的线程函数,args 是传递给线程函数的参数,必须是tuple类型,kwargs 是可选参数。

调用 start_new_thread 之后,会创建一个新的线程,来执行 function 函数。而代码原本的主线程将继续往下执行,不再等待 function 的返回。通常情况,线程在 function 执行完毕后结束。

例:用 python 编写“爬虫”程序,抓取网上的数据。通过豆瓣的 API 抓取 30 部影片的信息:

  单线程写法:

import urllib, time

time_start = time.time()

data = []

for i in range(30):

print 'request movie:', i

id = 1764796 + i

url = 'https://api.douban.com/v2/movie/subject/%d' % id

d = urllib.urlopen(url).read()

data.append(d)

print i, time.time() - time_start

print 'data:', len(data)

  参考输出结果:用了 time.time() 来计算抓取花费的时间。运行一遍,大约需要十几秒

> python test.py

request movie: 0

0 0.741228103638

request movie: 1

1 1.96586918831

...

request movie: 28

28 12.0225770473

request movie: 29

29 12.4063940048

data: 30

  

  多线程写法:

import urllib, time, thread

def get_content(i):

id = 1764796 + i

url = 'https://api.douban.com/v2/movie/subject/%d' % id

d = urllib.urlopen(url).read()

data.append(d)

print i, time.time() - time_start

print 'data:', len(data)

time_start = time.time()

data = []

for i in range(30):

print 'request movie:', i

thread.start_new_thread(get_content, (i,))

raw_input('press ENTER to exit...\n') #因为主线程不在等待函数返回结果,所以在代码最后,增加了 raw_input,避免程序提前退出。

  参考输出结果:

> python test.py

request movie: 0

request movie: 1

...

request movie: 28

request movie: 29

press ENTER to exit...

1 0.39500784874

data: 1

9 0.428859949112

data: 2

...

data: 28

21 1.03756284714

data: 29

8 2.66121602058

data: 30

  从输出结果可以看出:

  • 在程序刚开始运行时,已经发送所有请求

  • 收到的请求并不是按发送顺序,先收到就先显示

  • 总共用时两秒多

  • data 里同样记录了所有30条结果

对于这种耗时长,但又独立的任务,使用多线程可以大大提高运行效率。但在代码层面,可能额外需要做一些处理,保证结果正确。如上例中,如果需要电影信息按 id 排列,就要另行排序。

多线程通常会用在网络收发数据、文件读写、用户交互等待之类的操作上,以避免程序阻塞,提升用户体验或提高执行效率。

多线程的实现方法不止这一种。另外多线程也会带来一些单线程程序中不会出现的问题。这里只是简单地开个头。


Python:基础知识(二)的更多相关文章

  1. python基础知识(二)

    python基础知识(二) 字符串格式化 ​ 格式: % 类型 ---- > ' %类型 ' %(数据) %s 字符串 ​ print(' %s is boy'%('tom')) ----> ...

  2. python基础知识二

    对象 python把在程序中用到的任何东西都成为对象. 每一个东西包括数.字符串甚至函数都是对象. 使用变量时只需要给他们赋一个值.不需要声明或定义数据类型. 逻辑行与物理行 物理行是你在编写程序时所 ...

  3. python基础知识二 列表、元组、range

    3.6.2 列表 1.列表 -- list ​ 有序,可变,支持索引,用于存储数据(字符串,数字,bool,列表,字典,集合,元组,). list1 = [] list1 = ['alex',12,T ...

  4. python基础知识(二)

    以下内容,作为python基础知识的补充,主要涉及基础数据类型的创建及特性,以及新数据类型Bytes类型的引入介绍

  5. Python开发【第二篇】:Python基础知识

    Python基础知识 一.初识基本数据类型 类型: int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**31-2**31-1,即-2147483648-2147483647 在64位 ...

  6. python 基础知识(一)

    python 基础知识(一) 一.python发展介绍 Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本 ...

  7. python 爬虫与数据可视化--python基础知识

    摘要:偶然机会接触到python语音,感觉语法简单.功能强大,刚好朋友分享了一个网课<python 爬虫与数据可视化>,于是在工作与闲暇时间学习起来,并做如下课程笔记整理,整体大概分为4个 ...

  8. python基础知识3---字符编码

    阅读目录 一 了解字符编码的知识储备 二 字符编码介绍 三 字符编码应用之文件编辑器 3.1 文本编辑器之nodpad++ 3.2 文本编辑器之pycharm 3.3 文本编辑器之python解释器 ...

  9. Python基础知识(五)

    # -*- coding: utf-8 -*-# @Time : 2018-12-25 19:31# @Author : 三斤春药# @Email : zhou_wanchun@qq.com# @Fi ...

  10. python基础知识部分练习大全

    python基础知识部分练习大全   1.执行 Python 脚本的两种方式 答:1.>>python ../pyhton.py 2. >>python.py   #必须在首行 ...

随机推荐

  1. Spring是什么、spring容器、Spring三大核心思想DI(依赖注入)、IOC(控制反转)、AOP(面向切面编程)

    1.Spring (1)Spring是什么? 是一个轻量级的.用来简化企业级应用开发的开发框架. 注: a.简化开发: Spring对常用的api做了简化,比如,使用Spring jdbc来访问数据库 ...

  2. react生命周期获取异步数据

    当react组件需要获取异步数据的时候,建议在ComponentDidMount周期里执行获取动作, 如果非异步数据,可以在ComponentWillMount获取 因为ComponentWillMo ...

  3. Keras vs. PyTorch in Transfer Learning

    We perform image classification, one of the computer vision tasks deep learning shines at. As traini ...

  4. java boolean 值在内存中占几位?

      java boolean 值在内存中占几位?    <Java虚拟机规范>中这样描述:虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持.在Java虚拟机中没有任何供 ...

  5. js 中文长字符截短&关键字符隐藏 自定义过滤器

    两个非常简单的过滤器:隐藏关键字符和字符截短.同样也可以迁移到ng和原生js直接使用(去掉avalon.filters声明即可).后期还有不错的过滤器,还往这里面加 keyword:avalon,js ...

  6. SSL Certificates深入理解

    http://www.littlewhitedog.com/content-71.html https://www.verisign.com/en_US/website-presence/websit ...

  7. Windows自带强大的入侵检测工具——Netstat 命令 查询是否中木马

    Netstat命令可以帮助我们了解网络的整体使用情况.根据Netstat后面参数的不同,它可以显示不同的网络连接信息.Netstat的参数如图,下面对其中一些参数进行说明.如何检测本机是否有被中木马, ...

  8. [SQL Server]数据库的恢复

    数据库恢复是和数据库备份相对应的操作,它是将数据库备份重新加载到系统中的过程.数据库恢复可以创建备份完成时数据库中存在的相关文件,但是备份以后的所有数据库修改都将丢失. SQL Server进行数据库 ...

  9. MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

    MySQL InnoDB支持三种行锁定方式: l   行锁(Record Lock):锁直接加在索引记录上面,锁住的是key. l   间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙 ...

  10. iOS设计模式 - 责任链

    iOS设计模式 - 责任链 原理图 说明 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知道链 ...