Python list

序列

序列是python中基本的数据结构,序列中的每个元素被分配了一个序号即元素的位置,也即索引,下表从0开始。如下面是一个序列

user1 = ['robin',30]

这其中元素的类型并不像java那样严格的规定,甚至还可以保护多个序列

user2 = ['summer',27]
user = [user1, user2]#[['robin', 30], ['summer', 27]]

这实际上也是我们常说的二维数组了

序列通用操作

下面介绍序列的通用操作,主要包括索引(indexing),分片(sliceing),加(adding),乘(multiplying)

1、索引
这就是元素都有下标,从0开始,反转的时候从-1开始

name = 'hello'
name[0]
name[-1]
name[6]

需要注意,如果下标超过序列长度,那么将抛出错误,如:

Traceback (most recent call last):
  File "F:\git\pyl\pyl\src\com\python\learn\chap03\seq.py", line 15, in <module>
    name[6]
IndexError: string index out of range

2、分片
分片就是截取序列的部分元素,主要通过冒号相隔两个索引来实现

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
numbers[1:3] //-->[2,3]
numbers[-3:-1] //-->[8, 9]

与索引一样,下标从0开始,反转从-1开始,我们来看看上面最后一个,明明是-1为什么不是[8, 9,10],可能会想到这样

numbers[-3:0]

但事实上这样输出为[]因为分片最左边的索引比他右边的晚出现在序列中,那么结果就是一个空的序列。但如果分片需要包括序列结尾的元素,只需要将最后一个索引置空即可

numbers[-3:]

这是一个很酷的功能,比如

numbers[:3]//--->[1,2,3]
numbers[:]//--->[1,2,3,4,5,6,7,8,9,10]

其实上面的例子都包含了一个隐含的条件,那就是步长为1,当然你也可以设定需要的步长(但步长不能为0,否则将抛出ValueError)。可以参考如下几个例子的输出

numbers[0:10]
numbers[0:10:1]
numbers[::1]
numbers[0:10:2]

这里有一个很酷的应用

name = 'abcdefghi'
name[::-1]

看结果是什么?是的,这就是一个字符串反转的用法!

3、运算

  • add

    同一类型的序列可进行相加

      [1, 2, 3] + [4, 5, 6]
      [1, 2, 3] + 'hello'//TypeError
    
  • multiply

    乘法=重复次数

    在列表的运算中,乘法将使元素重复相应的次数

      [1, 2] * 5 //--->[1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
      python' * 2 //--->pythonpython
      [None] * 10 //长度为10的空列表
    
  • in

    in是用来检测是否包含指定元素的

      'h' in 'hello' //--->True
      [1, 2] in [[1, 2], [2, 1]] //--->True
    
  • max

    len,max,min分别是序列的长度、序列中元素的最大值、最小值

      len([1, 2, 3, 4])
      max([1, 2, 3, 4])
      max(12,23,45)
      min(12,-23,45)
    

    如果序列不是数字呢?

      min('b','a','c')
      min(u'爱','a','c')
    

    取元素的ASCII码

列表(list)

列表是序列中很常见的结构,他是可变的,有许多有用的方法

  • list

    他将字符串转换为列表

      list('123')
      list('abc')
    

    当然如果再转回来可以''.join(['a','b',c])

  • modify

      x = [1, 2, 3]
      x[1] = 1
    
  • delete

      x = [1, 2, 3]
      del x[1]
    
  • split

      a = [1, 2, 3, 4]
      a[2:]=list('hello') //[1, 2, 'h', 'e', 'l', 'l', 'o']
    

    或者一个更酷的

      numbers = [1, 5]
      numbers[1:1] = [2, 3, 4]//[1,2,3,4,5]
    

    当然也可以用来作为删除元素

      numbers[1:4] = [] //[1, 5]
    
  • append

    列表末尾追加新的对象,注意一下两个操作的结果

      numbers.append('a')
      numbers.append(['a'])
    
  • count

    统计某个元素在列表中出现的个数

      ['1','a','2','1'].count('1')
      ['1','a','2','1'].count('1c')
    
  • extend

    末尾最近新的序列

      a = [1, 2, 3]
      b = [4, 5, 6]
      a.extend(b)
    

    此时a=[1,2,3,4,5,6]b未变。注意区别+操作

      a = [1, 2, 3]
      b = [4, 5, 6]
      c = a+b
    

    此时c=[1,2,3,4,5,6]a,b未变

  • index

    指定元素在列表中索引的位置

      [1, 2, 3, 4].index(1)
    
  • insert

    在指定的位置插入元素,注意并不替换该位置原来值

      c = [1, 2, 3, 4]
      c.insert(2, 'a')
    

    如果指定位置超过实际长度,那么只是在最后追加

      c.insert(5, 'a')//[1,2,3,4,'a']
    
  • pop

    移除列表中的元素(默认最后一个),通过index来指定

      [1,2,3].pop();
      [1,2,3].pop(1);
      [1,2,3].pop(3);//IndexError
    
  • remove

    移除列表中某个元素第一个匹配的项,如果不存在将会抛出ValueError

      [1,2,1,2].remove(1)
      [1,2].remove(3)
    
  • reverse

    反转列表

      x=[1, 2, 3, 4]
      x.reverse();
    

    可以通过这个实现字符串的反转

      a = list('abcbd sad')
      a.reverse()
      ''.join(a)
    
  • sort

    该方法在原列表进行排序(不会返回副本)

      x=[1,2,4,6,3]
      x.sort()//--->x=[1,2,3,4,6]
    

    而如果采取这样

      x=[1,2,4,6,3]
      y=x.sort()//--->x=[1,2,3,4,6],y=None
    

    如果需要副本,可以用sorted

      x = [1, 2, 4, 6, 3]
      y = sorted(x)
    

    此时x保留原样,而y已经是排序后的输出。sort()有另外两个可选的参数:key排序函数,reverse指定是否倒序

      b=["aacs","aaa","tgdfs","f"]
      b.sort(key=len)
    
      c=[1,6,3,4,2]
      c.sort(reverse=True)
    

元组

是不可变的序列,即不能修改。通常用()来表示,如

(1,2,3)
('a','b','c')

如果只包含一个元素,则需要在后面加逗号(,)

(42,)

比较

3 * (10 + 2)
3 * (10 + 2,)

可以通过函数tuple来实现对元组的转换

tuple('1bs3')
tuple([1, 2, 3, 4])
tuple((1, 2, 3,))

Python 日期和时间

在python中处理日期和时间主要有三个模块: datetime,calendar,time针对了不同的使用场景

datetime

datetime模块提供了处理大部分情况下日期、时间的解决方案。比如日期、时间、时间间隔、时区等。主要包括下面的类

datetime.date提供基于Gregorian日历下year,month,day的处理方案
datetime.time时间理想化的处理(考虑一天是24*60*60的情况,没有闰秒),提供属性hour,minute,second,microsecond,和tzinfo
datetime.datetime日期和时间的集合(包括date和time)
datetime.timedelta时间间隔:date,time或datetime
datetime.tzinfo时区抽象类,用于datetime或time
datetime.timezonetzinfo的一个实现类,基于UTC

1. datetime.date

表示了一个日期对象,其构造函数为datetime.date(year, month, day)其中各个参数需要满足

  • MINYEAR <= year <= MAXYEAR
  • 1 <= month <= 12
  • 1 <= day <= number of days in the given month and year

下面这个例子展示了一些常用的用法

def datetime_date():
	one_day = date(2013, 10, 28)
	# 返回当前本地时间,与date.fromtimestamp(time.time())一样
	today = date.today()
	another_day = date.fromtimestamp(time.time())
	# 返回日期的ISO格式: ‘YYYY-MM-DD’
	print one_day.isoformat() == another_day.isoformat()
	print today == another_day
	# 返回日期的字符串格式: Mon Oct 28 00:00:00 2013
	print one_day.ctime()
	# 根据格式返回日期的字符串http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior
	print another_day.strftime('%Y-%m-%d')
	print another_day.strftime('%Y-%m-%d %H:%M:%S') #当然这句完全没有必要,需要显示时间信息应该用datetime
	
	# 返回time.struct_time((d.year, d.month, d.day, 0, 0, 0, d.weekday(), yday, -1))
	dt = today.timetuple()
	for i in dt:
		print i
		
	# 返回(ISO year, ISO week number, ISO weekday)
	dtt = today.isocalendar()
	for i in dtt:
		print i

2. datetime.time

表示了一个时间对象,与日期对应,这里表示小时、分、秒等信息。其构造函数为datetime.time([hour[, minute[, second[, microsecond[, tzinfo]]]]])

  • 0 <= hour < 24
  • 0 <= minute < 60
  • 0 <= second < 60
  • 0 <= microsecond < 1000000.

同样的,我们用例子来展示常见的用法

def datetime_datetime():
	#实例化time对象
	cur_time = time(20, 1, 2, 100)
	#常见属性
	print cur_time.hour, '-', cur_time.second, '-', cur_time.minute, '-', cur_time.microsecond, '-', cur_time.tzinfo
	#返回字符串,ISO格式:HH:MM:SS.mmmmmm 
	print cur_time.isoformat()
	#用给定的时间替换生成新的时间 
	new_time = cur_time.replace(13, 23) 
	#20:01:02.000100 --> 13:23:02.000100
	print new_time.isoformat()
	#根据格式返回日期的字符串
	print new_time.strftime('%H:%M:%S')

3. datetime.datetime

是date和time的结合,自然包括了两者的所有信息,其构造函数为datetime(year, month, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]) datetime中常用方法和属性

  • datetime.today() 返回表示当前本地时间的datetime对象,与datetime.fromtimestamp(time.time())相同
  • datetime.now([tz]) 返回表示当前指定时区的datetime对象,如果时区为None则与today()作用一样
  • datetime.utcnow() 返回当前UTC日期和时间
  • datetime.combine(date, time):根据date和time,创建一个datetime对象
  • datetime.strptime(date_string, format):将格式字符串转换为datetime对象
  • 包括date和time的方法

下面是基本的用法

def datetime_datetime():
	#返回当前本地实际
	cur_dt = datetime.today()
	dt_now = datetime.now()
	#返回当前UTC时间
	cur_utcdt = datetime.utcnow()
	#根据日期和时间组合成一个datetime对象
	com_dt = datetime.combine(date(2013, 10, 28), time(20, 1, 2, 100))
	#根据timestamp返回UTC
	utc_stamp = datetime.utcfromtimestamp(ctime.time())
	print 'today: %s, now: %s, comb: %s, utcnow: %s, utcs: %s' % (cur_dt, dt_now, com_dt, cur_utcdt, utc_stamp)
	#根据date_string返回datetime: 日期字符串不对时会抛出ValueError
	str_dt = datetime.strptime('2013-9-28 12:12:12', '%Y-%m-%d %H:%M:%S') 
	print str_dt
	#常见属性
	print 'Hour: %s, Minutes: %s, Seconds: %s, Year: %s, Month: %s' % (str_dt.hour, str_dt.minute, str_dt.second, str_dt.year, str_dt.month)
	#来自date和time的方法
	print 'date: %s, time: %s, weekday: %s' % (str_dt.date(), str_dt.time(), str_dt.weekday())

4. datetime.timedelta

表示两个日期、时间间隔的时间段。通常与其他对象(date,time,datetime)使用,支持(+,-,*)操作等。其构造函数为: datetime.timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]]])

def datetime_timedelta():
	#一天后
	print date(2013, 10, 31) + timedelta(days=1)
	#一小时后
	print datetime.now() - timedelta(hours=1)
	#100天前
	print (datetime.now() - timedelta(days=100)).strftime("%Y-%m-%d")

5. strftime()和strptime()

日期格式

%a 星期的简写。如 星期三为Web
%A星期的全写。如 星期三为Wednesday
%b 月份的简写。如4月份为Apr
%B 月份的全写。如4月份为April
%c 日期时间的字符串表示。(如: 04/07/10 10:43:39)
%d 日在这个月中的天数(是这个月的第几天)
%f 微秒(范围[0,999999])
%H小时(24小时制,[0, 23])
%I 小时(12小时制,[0, 11])
%j 日在年中的天数 [001,366](是当年的第几天)
%m 月份([01,12])
%M 分钟([00,59])
%p AM或者PM
%S 秒(范围为[00,61],为什么不是[00, 59],参考python手册~_~)
%U 周在当年的周数当年的第几周),星期天作为周的第一天
%w 今天在这周的天数,范围为[0, 6],6表示星期天
%W 周在当年的周数(是当年的第几周),星期一作为周的第一天
%x 日期字符串(如:04/07/10)
%X 时间字符串(如:10:43:39)
%y 2个数字表示的年份
%Y 4个数字表示的年份
%z 与utc时间的间隔 (如果是本地时间,返回空字符串)
%Z 时区名称(如果是本地时间,返回空字符串)
%% %% => %

Python mongodb

关于mongodb这里就不再介绍了,本文主要基于pymongo-2.6.3版本

  1. 下载安装
  1. 从一个例子开始

下面的例子展示了一个简单的使用:连接mongo,获取db和colletion并插入一条记录

from pymongo import Connection
from pymongo.errors import ConnectionFailure

def mongo_connection():
	try:
		# 创建一个连接
		con = Connection('localhost', 27017)
		# 获取一个数据库
		db = con.sa
		# 获取collection
		coll_user = db.user
		user = {'name':'python', 'version':'1.2.4'}
		# 新增一条记录
		coll_user.insert(user)
		# 关闭连接
		con.close()
	except TypeError , e:
		print e
	except ConnectionFailure , e:
		print e

上面的注释已经把各个功能做了介绍。这里连接数据库主要用到了Connection,我们可以从api中看到相关的参数 Connection([host='localhost'[, port=27017[, max_pool_size=10[, network_timeout=None[, document_class=dict[, tz_aware=False[, **kwargs]]]]]]])更详细的参数见上面api文档。同时我们也可以看到,这个方法在当前版本已经被过期了。推荐使用MongoClient。那么上面的例子可以变成:

from pymongo import MongoClient
from pymongo.errors import ConnectionFailure

def mongo_client():
	try:
		client = MongoClient('localhost', 27017)
		db = client.sa
		coll_user = db.user
		user = {'name':'pymongo', 'version':'2.6.3'}
		coll_user.insert(user)
		client.close()
	except TypeError , e:
		print e
	except ConnectionFailure , e:
		print e
  1. 模块介绍

pymongo主要涉及以下几个模块

connection表示了一个mongodb的连接,上面已经描述了构造方法,下面介绍一些 常用的属性和方法

c[db_name]||c.db_name获取一个数据库实例,如`con['sample']`或者`con.sample`
con.host,con.port,con.max_pool_size,con.nodes显示当前连接的常见属性
con.server_info()显示当前连接mongodb的基本信息
database_names(),con.get_default_database()当前连接的所有数据库名称
drop_database(name_or_database)删除一个数据库
con.copy_database(from_name, to_name[, from_host=None[, username=None[, password=None]]])拷贝一个数据库到另一个
con.write_concern()用于连接的一些设置,可设置replica的属性:`con.write_concern = {'w': 2, 'wtimeout': 1000,'j':True,'fsync':True}`

database:表示了当前连接的一个数据库。对数据库实例而言,最重要的是获取相应的文档对象并进行后续的操作。当然也提供了相关的方法:如用户管理、文档操作等

db[collection_name] || db.collection_name根据名字获取collection
add_user(name, password=None, read_only=None, **kwargs)对当前数据库新增用户
authenticate(name, password=None, source=None, mechanism='MONGODB-CR', **kwargs)对当前数据库进行授权
remove_user(name)删除用户
collection_names(include_system_collections=True)获取当前数据库所有的collections
create_collection(name, **kwargs)创建一个新的collection
drop_collection(name_or_collection)删除一个collection

collection这应该是我们操作mongodb中最常关注的对象,我们进行的一切增、删、改、查都在这个类体现。下面用几个例子来说明

def mongo_insert_save():
	try:
		client = MongoClient('localhost', 27017)
		db = client['sample']
		colle_book = db['book']
		book = {'name':'pymongo', 'version':'2.6.3'}
		#新增文档对象
		colle_book.insert(book)
		print book
		
		#更新文档
		book['price'] = 1.2
		colle_book.save(book)
		print book
		
		#此处会抛出`DuplicateKeyError`
		colle_book.insert(book)
		
		#批了插入的操作
		books = []
		for i in range(10):
			books.append({'name':'pymongo_' + str(i), 'version':'ver_' + str(i)})
		colle_book.insert(books)  

	except TypeError , e:
		print e
	except ConnectionFailure , e:
		print e 

这里用到了insert()save()。一个完整的函数参数为:insert(doc_or_docs[, manipulate=True[, safe=None[, check_keys=True[, continue_on_error=False[, **kwargs]]]]])这里两者的区别在于: 如果一个文档对象如果有_id在调用save时将更新而insert则会抛出错误


Python mysql

这里主要使用MySQLdb模块,可在https://pypi.python.org/pypi/MySQL-python/1.2.4进行下载并安装

下面是一个简单的例子,包括了一个mysql操作的常见步骤

import MySQLdb

try:
	##建立一个数据库连接
	conn = MySQLdb.connect(host='localhost', user='root', passwd='root', db='sa', port=3306, charset='utf8')
	##打开一个游标,是数据库操作的入口
	cur = conn.cursor()
	##执行一个查询操作返回操作受影响的记录数
	count = cur.execute('select * from user')
	##查询所有
	for data in cur.fetchall():
		print "User[id=%s, code=%s, name=%s, pwd=%s, type=%s, status=%s]" % (data)
		
except MySQLdb.Error, e:
	 print "Mysql Error %d: %s" % (e.args[0], e.args[1])
finally:
	##关闭游标和连接
	if cur:
		cur.close()
	if conn:
		conn.close()

这里对其中几个函数的使用做个说明

  1. MySQLdb.connect(*args, **kwargs) 这个构造函数创建了一个数据库连接的实例,是进行后续操作的关闭。构造函数中提供了常用的参数如 host,user,passwd,db,port,connect_timeout,charset,ssl如上面例子所示表达的意思清晰明了

  2. cursor游标反应了与数据库操作的结果。通常是作为一个元组(tuple)。对数据库的操作都在游标上进行,如上面的执行、查询所有结果等。游标提供了一系列的方法来完成工作。下面是一些常用的方法 - execute(query, args=None) 执行一个查询,返回受影响的记录数。其中query是待执行的sql语句,args是query可能需要的参数,可以是序列或mapping - fetchone(),fetchmany(size=None),fetchall():这三个函数从游标中返回查询的结果,如果有值将以序列的方式返回 - scroll(value, mode='relative'):设置游标的偏移量,可从相对和绝对位置设定。达到分页查询的效果

         def mysql_query_page():
             try:
                 conn = MySQLdb.connect(host='localhost', user='root', passwd='root', db='sa', port=3306, charset='utf8')
                 cur = conn.cursor()
                 count = cur.execute('select * from user')
                 print "total count: %d " % (count)
                 ##从第10条开始
                 cur.scroll(10)
                 ##查询10条
                 data = cur.fetchmany(10)
                 for u in data:
                     print "User[id=%s, name=%s]" % (u)
             except MySQLdb.Error, e:
                  conn.rollback()
                  print "Mysql Error %d: %s" % (e.args[0], e.args[1])
             finally:
                 if cur:
                     cur.close()
                 if conn:
                     conn.close()
    

    以上查询结果集是元组,当然也支持字典的格式返回,提供了如下的api: fetchoneDict(),fetchmanyDict(size=None),fetchallDict()

     def mysql_query_dict_page():
         try:
             conn = MySQLdb.connect(host='localhost', user='root', passwd='root', db='sa', port=3306, charset='utf8')
             cur = conn.cursor(MySQLdb.cursors.DictCursor)
             count = cur.execute('select * from user')
             print "total count: %d " % (count)
             cur.scroll(10)
             data = cur.fetchmanyDict(10)
             for u in data:
                 print u
         except MySQLdb.Error, e:
              conn.rollback()
              print "Mysql Error %d: %s" % (e.args[0], e.args[1])
         finally:
             if cur:
                 cur.close()
             if conn:
                 conn.close()
    

    与上面的相比,这里需要注意两点:1、游标的实例化需要指定游标的DictCursor实例,2、查询使用上面说的api

  3. 使用预编译的占位符(Preparedstatements)关于这个就不再多说,具体看下面的查询例子

     def mysql_insert():
         try:
             conn = MySQLdb.connect(host='localhost', user='root', passwd='root', db='sa', port=3306, charset='utf8')
             cur = conn.cursor()
             for i in range(20):
                 ##使用%s的通配占位
                 cur.execute('insert into user (name)values(%s)', ('name_' + str(i)))
             ##提交事务
             conn.commit()
         except MySQLdb.Error, e:
              conn.rollback()
              print "Mysql Error %d: %s" % (e.args[0], e.args[1])
         finally:
             if cur:
                 cur.close()
             if conn:
                 conn.close()
    

    当然,针对这种批量的操作更好的方案可以是:

     users = ('name_21', 'name_22', 'name_23',)
     cur.executemany('insert into user (name)values(%s)', users)
    
  4. 事务与关闭连接:上面在插入操作中我们用到了事务的提交与回滚

     conn.commit()
     conn.rollback()
    

    当然,任何时候不要忘记关闭连接

     cur.close()
     conn.close()
    

Python 模块与导入

模块与导入

最开始,我们使用python的解释器编写代码,但是如果一旦关闭,那么我们写的函数,变量都将丢失。后来我们将一定功能的内容用文本保存,并用*.py保存。这就是脚本,也达到了重复利用的目的。而这样的文件我们通常也称为模块(modules),用来组织不同功能的列表。这与java中的package,c++中的namespace作用类似。而在python中我们使用import关键字来处理。

  1. 首先我们写一个文件sample_module.py包括如下内容:

     def meth1(name):
         print(name)
    		
     def meth2(name):
         print('hello, ', name)
    

    如果在其他模块中需要用到这里面的函数,可以通过两种方式:
    - import sample_module

     这种方法引入新模块的内容存在于该模块的上下文空间中而不是当前执行模块的空间中,考虑:
    	
         meth1('python')
         sample_module.meth1('python')
    	
     前者将会抛出`NameError: name 'meth1' is not defined`,而后者能正常调用  - `from sample_module import *`
    
     与上面不同的是这里将引入的模块导入了新模块的上下文中,可以直接调用如`meth1('python')`。这里采用了通配的`*`来导入,将会导入所有的方法,当然也可以指定需要的方法
    
         from sample_module import meth1,meth2
    
     针对导入多个模块如果存在重名的方法,可以用`as`来通过别名来区分
    
         import sample_module as sm
         from sample_module import meth1 as m,meth2 as mm
    
  2. 接下来看看导入后当前默认上下文发生的变化,我们可以通过dir()查看:

     >>> dir()
     ['__builtins__', '__doc__', '__loader__', '__name__', '__package__']
     >>> import sys
     >>> dir()
     ['__builtins__', '__doc__', '__loader__', '__name__', '__package__', 'sys']
    	
     >>> import sys as SYS
     >>> dir()
     ['SYS', '__builtins__', '__doc__', '__loader__', '__name__', '__package__']
    
     >>> from sample_module import meth1 as m,meth2 as mm
     >>> dir()
     ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', 'm', 'mm']
    
  3. 插入与删除

    可以通过del对导入的模块进行删除

     >>> del SYS
     >>> dir()
     ['__builtins__', '__doc__', '__loader__', '__name__', '__package__']
    

    通过sys.path动态导入模块

     >>> import sys
     >>> sys.path.insert(0,'c:/sa')
     >>> sys.path
     ['c:/sa', '', 'C:\\Python33\\Lib\\idlelib', 'C:\\Windows\\system32\\python33.zip', 'C:\\Python33\\DLLs', 'C:\\Python33\\lib', 'C:\\Python33', 'C:\\Python33\\lib\\site-packages']
     >>> import sa
     >>> sa.meth1('aaa')
     aaa
    

    通过sys.path.insert(index, src_path)导入了目录c:/sa,这样该路径下的文件就作为模块导入了path中,通过import就导入了需要的模块,需要注意的是重名的问题。类似的还有

     >>sys.path.append("c:/sa")  	#加到路径最后
     >>sys.path.insert(0,"c:/sa")  	#加到路径最前
     >>sys.path.remove("c:/sa")  	#删除路径