python第四天。今天感觉好懒。但是一番纠结之后我还是回来啦。为了惩罚自己有偷懒的想法。我决定今天多搞一点。而且今天我换了一种字体哦,哈哈。好的,今天我们主要搞一搞面向对象。如果有时间的话再搞一搞IO编程。
面向对象
类和实例:
面向对象最重要的概念就是类(class)和实例(instance)了:
#-*-coding:utf-8-*-
class Student(object): #class 为定义类的关键字,object为其继承的类
def __init__(self,name,score): #构造函数,第一个参数一定是self,表示创建的实例本身
self.name = name #构造函数里面有我们认为必须绑定的属性
self.score = score #我们也可以在以后自由的为实例添加其他的属性
def print_score(self):
print self.name, ':', self.score
def main():
zhangsan = Student('zhangsan',95)
zhangsan.print_score()
zhangsan.age=18 #为这个实例绑定一些其他的属性
print zhangsan.score #在外部访问实例的属性
zhangsan.score=96 #在外部修改实例的属性
zhangsan.print_score()
if __name__=="__main__":
main()</span>
从前面的例子来看,外部的代码可以自由的修改一个实例的属性。如果要让内部属性不被外部访问,可以在属性的名称前面加上两个下划线,这样这个变量就变成了一个私有变量(其实外部还是可以访问,但是强烈不建议,我也不告诉你怎么访问)。我们可以再添加一些成员方法来访问和修改这些私有变量:
#-*-coding:utf-8-*-
class Student(object):
def __init__(self,name,score):
self.__name = name #现在__name和__score都是私有属性,无法从外部直接访问
self.__score = score
def print_score(self): #内部方法的第一个参数也一定是self
print self.__name, ':', self.__score
def get_name(self): #定义两个方法来获取私有变量
return self.__name
def get_score(self):
return self.__score
def set_score(self,score): #定义一个方法来修改私有属性
self.__score = score
def main():
zhangsan = Student('zhangsan',95)
zhangsan.print_score()
print zhangsan.get_name()
print zhangsan.get_score()
zhangsan.set_score(96.5)
print zhangsan.get_score()
if __name__=="__main__":
main()
继承与多态:
在面向对象(OOP)程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类,父类,或者超类(Base class, Super class)。继承和多态的好处我就不多说了,大家都懂的
#-*-coding:utf-8-*-
class Animal(object):
def run(self):
print 'animal is running...'
def eat(self):
print 'animal is eating...'
class Dog(Animal):
def eat(self): #复写了eat()
print 'dog is eating'
class Cat(Animal):
def eat(self): #复写了eat()
print 'cat is eating'
def main():
dog = Dog()
cat = Cat()
dog.run() #调用父类的run()
cat.run() #调用父类的run()
dog.eat() #调用的是自己的eat()
cat.eat() #调用的是自己的eat()
if __name__=="__main__":
main()
基本类型的对象可以用type()来判断,而自定义的class可以用isinstance()来判断
dir():这个方法更狠,它可以返回一个对象的所有属性和方法!!!
############################################################################################################
神奇的分割线
############################################################################################################
OK,前面是面向对象编程的一些基本知识,下面来点面向对象高级编程。我们会讨论多重继承,定制类,元类等概念
使用__slots__
有些时候,如果我们想要限制class的属性,比如,只允许对Student实例添加name和age属性。
为了达到限制的目的,Python允许在定义class的时候定义一个特殊的__slots__变量,来限制该class能添加的属性。
class Student(object):
__slots_=('name','age') #用tuple定义允许绑定的属性名称,不在__slots__中的属性将不能被绑定。
#另外要注意的是__slots__定义的属性仅对当前类起作用,对继承的子类不起作用。除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__
使用@property
比如我们有一个学生类,这个类有一个成绩参数。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数
#-*-coding:utf-8-*-
class Student(object):
def get_score(self):
return self._score
def set_score(self,value):
if not isinstance(value,int): #检测一下参数
raise ValueError('score must be an integer!')
if value<0 or value>100:
raise ValueError('score must between 0~100!')
self._score = value
def main():
s = Student()
#s.set_score(101)
#s.set_score('hehe')
s.set_score(60)
print s.get_score()
if __name__=="__main__":
main()
但是,上面的调用方式略显复杂,没有直接用属性这么直接简单。
有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?
还记得装饰器(decorator)可以给函数动态加上功能呢?对于类的方法,装饰器一样起作用。python内置的@property装饰器就是负责把一个方法变成属性调用的:
#-*-coding:utf-8-*-
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 and value>100:
raise ValueError('score must between 0~100!')
self._score = value
def main():
s = Student()
s.score = 70 #实际转化为s.set_score(60)
print s.score #实际转换为s.get_score()
if __name__=="__main__":
main()
@property的实现比较复杂,我们先考虑如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就有一个可控的属性操作:
#-*-coding:utf-8-*-
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 and value>100:
raise ValueError('score must between 0~100!')
self._score = value
def main():
s = Student()
s.score = 70 #实际转化为s.set_score(60)
print s.score #实际转换为s.get_score()
if __name__=="__main__":
main()
注意到这个神奇的@property
,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2014 - self._birth
多重继承
通过多重继承,一个子类就可以同时获得多个父类的所有功能
#-*-coding:utf-8-*-
class Animal(object):
pass
#大类:
class Mammal(Animal):
pass
class Bird(Animal):
pass
class Runnable(object):
def run(self):
print('Running...')
class Flyable(object):
def fly(self):
print('Flying...')
#各种动物:
class Dog(Mammal,Runnable): #继承了两个类
pass
class Bat(Mammal,Flyable):
pass
class Parrot(Bird,Flyable):
pass
class Ostrich(Bird,Runnable):
pass
if __name__=="__main__":
main()
Mixin:在设计类的继承关系时,通常,主线是单一继承下来的,但是,如果需要“混入”额外的功能,通过多重继承就可以实现。这种设计通常称之为Mixin
Python自带的很多库也使用了Mixin。举个例子,Python自带了TCPServer
和UDPServer
这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixin
和ThreadingMixin
提供。通过组合,我们就可以创造出合适的服务来。
比如,编写一个多进程模式的TCP服务,定义如下:
class MyTCPServer(TCPServer, ForkingMixin):
pass
编写一个多线程模式的UDP服务,定义如下:
class MyUDPServer(UDPServer, ThreadingMixin):
pass
如果你打算搞一个更先进的协程模型,可以编写一个CoroutineMixin
:
class MyTCPServer(TCPServer, CoroutineMixin):
pass
这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。
定制类
__str__ , __iter__ , __getitem__ , __getattr__ , __call__
使用元类
除了使用type()
动态创建类以外,要控制类的创建行为,还可以使用metaclass。
metaclass,直译为元类,简单的解释就是:
当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。
但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。
连接起来就是:先定义metaclass,就可以创建类,最后创建实例。
所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。
metaclass是Python面向对象里最难理解,也是最难使用的魔术代码。正常情况下,你不会碰到需要使用metaclass的情况,所以,以下内容看不懂也没关系,因为基本上你不会用到。
我们先看一个简单的例子,这个metaclass可以给我们自定义的MyList增加一个add
方法:
定义ListMetaclass
,按照默认习惯,metaclass的类名总是以Metaclass结尾,以便清楚地表示这是一个metaclass:
# metaclass是创建类,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
class MyList(list):
__metaclass__ = ListMetaclass # 指示使用ListMetaclass来定制类
当我们写下__metaclass__ = ListMetaclass
语句时,魔术就生效了,它指示Python解释器在创建MyList
时,要通过ListMetaclass.__new__()
来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。
__new__()
方法接收到的参数依次是:
-
当前准备创建的类的对象;
-
类的名字;
-
类继承的父类集合;
-
类的方法集合。
测试一下MyList
是否可以调用add()
方法:
>>> L = MyList()
>>> L.add(1)
>>> L
[1]
而普通的list
没有add()
方法:
>>> l = list()
>>> l.add(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'add'
动态修改有什么意义?直接在MyList
定义中写上add()
方法不是更简单吗?正常情况下,确实应该直接写,通过metaclass修改纯属变态。
但是,总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。
ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
让我们来尝试编写一个ORM框架。
编写底层模块的第一步,就是先把调用接口写出来。比如,使用者如果使用这个ORM框架,想定义一个User
类来操作对应的数据库表User
,我们期待他写出这样的代码:
class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
# 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
# 保存到数据库:
u.save()
其中,父类Model
和属性类型StringField
、IntegerField
是由ORM框架提供的,剩下的魔术方法比如save()
全部由metaclass自动完成。虽然metaclass的编写会比较复杂,但ORM的使用者用起来却异常简单。
现在,我们就按上面的接口来实现该ORM。
首先来定义Field
类,它负责保存数据库表的字段名和字段类型:
class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name)
在Field
的基础上,进一步定义各种类型的Field
,比如StringField
,IntegerField
等等:
class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)')
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint')
下一步,就是编写最复杂的ModelMetaclass
了:
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name=='Model':
return type.__new__(cls, name, bases, attrs)
mappings = dict()
for k, v in attrs.iteritems():
if isinstance(v, Field):
print('Found mapping: %s==>%s' % (k, v))
mappings[k] = v
for k in mappings.iterkeys():
attrs.pop(k)
attrs['__table__'] = name # 假设表名和类名一致
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
return type.__new__(cls, name, bases, attrs)
以及基类Model
:
class Model(dict):
__metaclass__ = ModelMetaclass
def __init__(self, **kw):
super(Model, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key)
def __setattr__(self, key, value):
self[key] = value
def save(self):
fields = []
params = []
args = []
for k, v in self.__mappings__.iteritems():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))
当用户定义一个class User(Model)
时,Python解释器首先在当前类User
的定义中查找__metaclass__
,如果没有找到,就继续在父类Model
中查找__metaclass__
,找到了,就使用Model
中定义的__metaclass__
的ModelMetaclass
来创建User
类,也就是说,metaclass可以隐式地继承到子类,但子类自己却感觉不到。
在ModelMetaclass
中,一共做了几件事情:
-
排除掉对
Model
类的修改; -
在当前类(比如
User
)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__
的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误; -
把表名保存到
__table__
中,这里简化为表名默认为类名。
在Model
类中,就可以定义各种操作数据库的方法,比如save()
,delete()
,find()
,update
等等。
我们实现了save()
方法,把一个实例保存到数据库中。因为有表名,属性到字段的映射和属性值的集合,就可以构造出INSERT
语句。
编写代码试试:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()
输出如下:
Found model: User
Found mapping: email ==> <StringField:email>
Found mapping: password ==> <StringField:password>
Found mapping: id ==> <IntegerField:uid>
Found mapping: name ==> <StringField:username>
SQL: insert into User (password,email,username,uid) values (?,?,?,?)
ARGS: ['my-pwd', 'test@orm.org', 'Michael', 12345]
可以看到,save()
方法已经打印出了可执行的SQL语句,以及参数列表,只需要真正连接到数据库,执行该SQL语句,就可以完成真正的功能。
不到100行代码,我们就通过metaclass实现了一个精简的ORM框架,完整的代码从这里下载:
https://github.com/michaelliao/learn-python/blob/master/metaclass/simple_orm.py
最后解释一下类属性和实例属性。直接在class中定义的是类属性:
class Student(object):
name = 'Student'
实例属性必须通过实例来绑定,比如self.name = 'xxx'
。来测试一下:
>>> # 创建实例s:
>>> s = Student()
>>> # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性:
>>> print(s.name)
Student
>>> # 这和调用Student.name是一样的:
>>> print(Student.name)
Student
>>> # 给实例绑定name属性:
>>> s.name = 'Michael'
>>> # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性:
>>> print(s.name)
Michael
>>> # 但是类属性并未消失,用Student.name仍然可以访问:
>>> print(Student.name)
Student
>>> # 如果删除实例的name属性:
>>> del s.name
>>> # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了:
>>> print(s.name)
Student
因此,在编写程序的时候,千万不要把实例属性和类属性使用相同的名字。
在我们编写的ORM中,ModelMetaclass
会删除掉User类的所有类属性,目的就是避免造成混淆。
###########################################################################################################
神奇的分割线
################################################################################################################
好吧,今天再来学一下IO编程
文件读写:
读写文件是最常见的IO操作,python内置了读写文件的函数,用法和c是兼容的
<pre name="code" class="python">#-*-coding:utf-8-*-
def main():
f = open('H:/workspace/test.txt','r') #打开一个文件,'r'表示读
print f.read() #读这个文件
f.close() #关掉这个文件
#OK,文件使用完毕后必须关闭,,但是如果文件读写的过程中出现错误,f.close()就不会被调用。
#牛逼哄哄的python引入了with语句来自动帮我们调用close()方法
with open('H:/workspace/test.txt','r') as f:
print f.read()
#read()会一次性读取文件的全部内容,为了防止世界被破坏,我们需要小心超大文件一次性占爆内存。
#可以反复调用read(size),读取指定size的内容,或者调用readline()每次读取一行内容
#调用readlines()的话可以一次读取所有内容并按行返回list
with open('H:/workspace/test.txt','r') as f:
for line in f.readlines():
print(line.strip())
if __name__=="__main__":
main()
像open()函数返回的这种有个read()方法的对象,在python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行。
如果是读二进制文件,比如图片,视频等,用‘rb’模式打开,把'r'换成‘rb’
要读取非ASCII编码的文本文件,就必须以二进制默认('rb')打开,再解码。
python还提供了一个codecs模块帮我们在读文件的时候自动转换编码,直接读出unicode
说完了读文件,下面讲讲写文件:
#-*-coding:utf-8-*-
def main():
f = open('h:/workspace/test.txt','w')
f.write('hello,world!')
f.close
with open('h:/workspace/test.txt','w') as f:
f.write('你好,世界')
#我用两种方法写了一下,但是我发现第二次写的覆盖在了第一次的上面。
if __name__=="__main__":
main()
写文件的时候也可以引入codecs模块自动转换编码
操作文件和目录:
如果要在python中执行目录和文件的操作怎么办?其实Python内置的os模块可以直接调用操作系统提供的接口函数
<span style="font-size:18px;">#-*-coding:utf-8-*-
import os
def main():
print os.name #操作系统的名称
print os.environ #操作系统中定义的环境变量
print os.getenv('PATH') #获取某个环境变量的值
##操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中
#查看当前目录的绝对路径
print os.path.abspath('.')
#创建一个目录
os.mkdir('h:/workspace/testdir')
#删除一个目录
os.rmdir('h:/workspace/testdir')
##在python中如果要把两个路径合成一个,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符。
##同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样拆分的路径,后一部分是最后一级的目录或者文件名。
##os.path.splitext()会直接让你得到文件的扩展名,非常方便吧。
###这里我还要墙裂推荐一个模块。shutill.在这里你可以找到很多实用的函数,比如copyfile()
##下面我们看看如何利用python来过滤文件
print [x for x in os.listdir('h:/workspace') if os.path.isdir(os.path.join('h:/workspace',x))] #列出该目录下所有文件夹
print [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py']
#列出当前文件夹下所有.py文件
if __name__=="__main__":
main()</span>
序列化:这部分内容看起来超级牛逼啊。一定要好好学。
我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
Python提供两个模块来实现序列化:cPickle
和pickle
。这两个模块功能是一样的,区别在于cPickle
是C语言写的,速度快,pickle
是纯Python写的,速度慢,跟cStringIO
和StringIO
一个道理。用的时候,先尝试导入cPickle
,如果失败,再导入pickle
:
try:
import cPickle as pickle
except ImportError:
import pickle
#-*-coding:utf-8-*- try: import cPickle as pickle except ImportError: import pickle def main(): d = dict(name='bob',age=20,score=95) print d f = open('dump.txt','wb') pickle.dump(d,f) #把对象序列化后写入文件存起来 f.close() f = open('dump.txt','rb') d2 = pickle.load(f) #从文件中读出之前写入的对象 f.close() print d2 if __name__=="__main__": main()
JSON:
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:
JSON类型 | Python类型 |
{} | dict |
[] | list |
"string" | 'str'或u'unicode' |
1234.56 | int或float |
true/false | True/False |
null | None |
Python内置的json
模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON:
>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)
'{"age": 20, "score": 88, "name": "Bob"}'
dumps()
方法返回一个str
,内容就是标准的JSON。类似的,dump()
方法可以直接把JSON写入一个file-like Object
。
要把JSON反序列化为Python对象,用loads()
或者对应的load()
方法,前者把JSON的字符串反序列化,后者从file-like Object
中读取字符串并反序列化:
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> json.loads(json_str)
{u'age': 20, u'score': 88, u'name': u'Bob'}
有一点需要注意,就是反序列化得到的所有字符串对象默认都是unicode
而不是str
。由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的str
或unicode
与JSON的字符串之间转换。
<pre name="code" class="python">#-*-coding:utf-8-*-
import json
class Student(object): #定义一个Student类
def __init__(self,name,age,score):
self.name = name
self.age = age
self.score = score
def student2dict(std): #把student类中要存的东西转化成一个dict(这样才好dump成json)
return {'name':std.name,'age':std.age,'score':std.score}
def dict2student(d): #同样,在load这个json的时候,也要添加一个函数,把load到的dict转化为student
return Student(d['name'],d['age'],d['score'])
def main():
s = Student('zhangsan',20,95)
json_str = json.dumps(s,default=student2dict) #dumps!注意这边的default参数
print json_str
s2 = (json.loads(json_str,object_hook=dict2student)) #load!注意这边的object_hook参数
print s2.name,s2.age,s2.score
if __name__=="__main__":
main()
但是问题没有完全解决。如果我们重新定义一个类的话,就又要再写两个转化函数??不,我们可以偷个懒,把任意class的实例变为dict:
因为通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量。<span style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;">。也有少数例外,比如定义了</span><code style="padding: 2px 4px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; color: rgb(221, 17, 68); border-radius: 3px; border: 1px solid rgb(225, 225, 232); white-space: nowrap; line-height: 20px; background-color: rgb(247, 247, 249);">__slots__</code><span style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;">的class。</span>
<span style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;"></span><pre name="code" class="python">#-*-coding:utf-8-*-
import json
class Student(object): #定义一个Student类
def __init__(self,name,age,score):
self.name = name
self.age = age
self.score = score
def main():
s = Student('zhangsan',20,95)
print (json.dumps(s,default=lambda obj: obj.__dict__)) #dumps!注意这边的default参数
if __name__=="__main__":
main()
这部分很重要哦,做个小结:
<span style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;"></span><p style="margin-top: 0px; margin-bottom: 10px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;">Python语言特定的序列化模块是<code style="padding: 2px 4px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(221, 17, 68); border-radius: 3px; border: 1px solid rgb(225, 225, 232); white-space: nowrap; background-color: rgb(247, 247, 249);">pickle</code>,但如果要把序列化搞得更通用、更符合Web标准,就可以使用<code style="padding: 2px 4px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(221, 17, 68); border-radius: 3px; border: 1px solid rgb(225, 225, 232); white-space: nowrap; background-color: rgb(247, 247, 249);">json</code>模块。</p><p style="margin-top: 0px; margin-bottom: 10px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;"><code style="padding: 2px 4px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(221, 17, 68); border-radius: 3px; border: 1px solid rgb(225, 225, 232); white-space: nowrap; background-color: rgb(247, 247, 249);">json</code>模块的<code style="padding: 2px 4px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(221, 17, 68); border-radius: 3px; border: 1px solid rgb(225, 225, 232); white-space: nowrap; background-color: rgb(247, 247, 249);">dumps()</code>和<code style="padding: 2px 4px; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(221, 17, 68); border-radius: 3px; border: 1px solid rgb(225, 225, 232); white-space: nowrap; background-color: rgb(247, 247, 249);">loads()</code>函数是定义得非常好的接口的典范。当我们使用时,只需要传入一个必须的参数。但是,当默认的序列化或反序列机制不满足我们的要求时,我们又可以传入更多的参数来定制序列化或反序列化的规则,既做到了接口简单易用,又做到了充分的扩展性和灵活性。</p><p style="margin-top: 0px; margin-bottom: 10px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;">
</p><p style="margin-top: 0px; margin-bottom: 10px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px;">好的,北京时间2015年1月30日16点45分。今天的python学习到此为止。明天好想休息一天,出去玩玩哈哈哈</p>