python第四天

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()和isinstance()是两个很实用的函数,很简单,用一下你就懂了。

基本类型的对象可以用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自带了TCPServerUDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixinThreadingMixin提供。通过组合,我们就可以创造出合适的服务来。

比如,编写一个多进程模式的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__()方法接收到的参数依次是:

  1. 当前准备创建的类的对象;

  2. 类的名字;

  3. 类继承的父类集合;

  4. 类的方法集合。

测试一下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和属性类型StringFieldIntegerField是由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,比如StringFieldIntegerField等等:

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中,一共做了几件事情:

  1. 排除掉对Model类的修改;

  2. 在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mappings__的dict中,同时从类属性中删除该Field属性,否则,容易造成运行时错误;

  3. 把表名保存到__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提供两个模块来实现序列化:cPicklepickle。这两个模块功能是一样的,区别在于cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢,跟cStringIOStringIO一个道理。用的时候,先尝试导入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的strunicode与JSON的字符串之间转换。

OK,现在dict的对象可以直接序列化为JSON的{},但是如果是自定义的class呢

<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>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值