Python类 - littleboy12580/learning_python GitHub Wiki
Python的类
运算符重载
在类中通过双下划线命名的方法(X)是特殊钩子,可以通过这种命名来对运算符进行重载
class ThirdClass(SecondClass): #继承了SecondClass
def __init__(self,value): #构造函数
self.data = value
def __add__(self,other): #重载了+运算符
return ThirdClass(self.data + other)
def __str__(self):
return '[ThirdClass: %s]' % self.data #重载了字符串显示
a = ThirdClass('abc')
print(a)
b = a + 'xyz'
print(b)
上面代码最后的结果为
[ThirdClass: abc]
[ThirdClass: abcxyz]
类的方法
类中的方法必须明确列出self参数,否则Python无法猜测简单函数是否最终会变成类的方法。
特殊类属性
Python中有两个常用的内省工具可以让我们访问对象实现的一些内部机制
instance.class
该属性提供了一个从实例到创建它的类的链接,有一个__name__和一个__bases__序列,name显示实例对应的类的名称,bases显示对应类的基类
bob = Person()
bob.__class__
bob.__class__.__name__
第一个返回的是类对象,第二个返回的是类对象的名称
object.dict
该属性提供一个字典,能够获取对象中的各种属性
list(bob.__dict__.keys)
返回的是bob实例里的各种属性名
对象持久化
Python通过3个标准的库模块来实现对象持久化
pickle
任意Python对象和字节串之间的序列化:使用pickle把对象存储为简单的普通文件,载入的时候使用unpickle来还原最初的对象
dbm
实现一个可通过键访问的文件系统,以存储字符串
shelve
使用另两个模块按照键把Python对象存储到一个文件中:shelve使用pickle把一个对象转换为其pickle化的字符串,并将其存储在一个dbm文件中的键之下;随后载入的时候shelve通过键获取pickle化的字符串,并用pickle在内存中重新创建最初的对象
bob = Person()
sue = Person()
tom = Person()
import shelve
db = shelve.open('filename') #创建dbm文件系统
for object in (bob,sue,tom):
db[object.name] = object #将实例名称作为键值
db.close()
json
一种轻量级数据交换格式,相对于XML而言更简单,也易于阅读和编写,机器也方便解析和生成,Json是JavaScript中的一个子集。
Python2.6开始加入了JSON模块,无需另外下载,Python的Json模块序列化与反序列化的过程分别是 encoding和 decoding
encoding:把一个Python对象编码转换成Json字符串
decoding:把Json格式字符串解码转换成Python对象
对于简单数据类型(string、unicode、int、float、list、tuple、dict),可以直接处理。
import json
obj = [[1,2,3],123,123.123,'abc',{'key1':(1,2,3),'key2':(4,5,6)}]
encodedjson = json.dumps(obj)
print repr(obj)
print encodedjson
运行结果为
[[1, 2, 3], 123, 123.123, 'abc', {'key2': (4, 5, 6), 'key1': (1, 2, 3)}]
[[1, 2, 3], 123, 123.123, "abc", {"key2": [4, 5, 6], "key1": [1, 2, 3]}]
在json的编码过程中,会存在从python原始类型向json类型的转化过程,具体的转化对照如下:
对于encode,我们使用dump()方法,对于decode,我们使用loads()方法
decodejson = json.loads(encodedjson)
print type(decodejson)
print decodejson[4]['key1']
print decodejson
输出为:
<type 'list'>
[1, 2, 3]
[[1, 2, 3], 123, 123.123, u'abc', {u'key2': [4, 5, 6], u'key1': [1, 2, 3]}]
loads方法返回了原始的对象,但是仍然发生了一些数据类型的转化。比如,上例中‘abc’转化为了unicode类型。从json到python的类型转化对照如下:
json.dumps方法提供了很多好用的参数可供选择,比较常用的有sort_keys(对dict对象进行排序,我们知道默认dict是无序存放的),separators,indent等参数。
排序功能使得存储的数据更加有利于观察,也使得对json输出的对象进行比较,例如:
data1 = {'b':789,'c':456,'a':123}
data2 = {'a':123,'b':789,'c':456}
d1 = json.dumps(data1,sort_keys=True)
d2 = json.dumps(data2)
d3 = json.dumps(data2,sort_keys=True)
print d1
print d2
print d3
print d1==d2
print d1==d3
输出:
{"a": 123, "b": 789, "c": 456}
{"a": 123, "c": 456, "b": 789}
{"a": 123, "b": 789, "c": 456}
False
True
indent参数是缩进的意思,它可以使得数据存储的格式变得更加优雅
data1 = {'b':789,'c':456,'a':123}
d1 = json.dumps(data1,sort_keys=True,indent=4)
print d1
输出:
{
"a": 123,
"b": 789,
"c": 456
}
输出的数据被格式化之后,变得可读性更强,但是却是通过增加一些冗余的空白格来进行填充的。json主要是作为一种数据通信的格式存在的,而网络通信是很在乎数据的大小的,无用的空格会占据很多通信带宽,所以适当时候也要对数据进行压缩。separator参数可以起到这样的作用,该参数传递是一个元组,包含分割对象的字符串
print 'DATA:', repr(data)
print 'repr(data) :', len(repr(data))
print 'dumps(data) :', len(json.dumps(data))
print 'dumps(data, indent=2) :', len(json.dumps(data, indent=4))
print 'dumps(data, separators):', len(json.dumps(data, separators=(',',':')))
# 输出:
DATA: {'a': 123, 'c': 456, 'b': 789}
repr(data) : 30
dumps(data) : 30
dumps(data, indent=2) : 46
dumps(data, separators): 25
处理自己的数据
json模块不仅可以处理普通的python内置类型,也可以处理我们自定义的数据类型,而往往处理自定义的对象是很常用的。
首先,我们定义一个类Person
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def __repr__(self):
return 'Person Object name : %s , age : %d' % (self.name,self.age)
if __name__ == '__main__':
p = Person('Peter',22)
print p
如果直接通过json.dumps方法对Person的实例进行处理的话,会报错,因为json无法支持这样的自动转化。通过上面所提到的json和python的类型转化对照表,可以发现,object类型是和dict相关联的,所以我们需要把我们自定义的类型转化为dict,然后再进行处理。这里,有两种方法可以使用
第一种方法:自己写转换函数
import Person
import json
p = Person.Person('Peter',22)
def object2dict(obj):
#convert object to a dict
d = {}
d['__class__'] = obj.__class__.__name__
d['__module__'] = obj.__module__
d.update(obj.__dict__)
return d
def dict2object(d):
#convert dict to object
if'__class__' in d:
class_name = d.pop('__class__')
module_name = d.pop('__module__')
module = __import__(module_name)
class_ = getattr(module,class_name)
args = dict((key.encode('ascii'), value) for key, value in d.items()) #get args
inst = class_(**args) #create new instance
else:
inst = d
return inst
d = object2dict(p)
print d
#{'age': 22, '__module__': 'Person', '__class__': 'Person', 'name': 'Peter'}
o = dict2object(d)
print type(o),o
#<class 'Person.Person'> Person Object name : Peter , age : 22
dump = json.dumps(p,default=object2dict)
print dump
#{"age": 22, "__module__": "Person", "__class__": "Person", "name": "Peter"}
load = json.loads(dump,object_hook = dict2object)
print load
#Person Object name : Peter , age : 22
第二种:继承JSONEncoder和JSONDecoder类,覆写相关方法
JSONEncoder类负责编码,主要是通过其default函数进行转化,我们可以override该方法。同理对于JSONDecoder。
import Person
import json
p = Person.Person('Peter',22)
class MyEncoder(json.JSONEncoder):
def default(self,obj):
#convert object to a dict
d = {}
d['__class__'] = obj.__class__.__name__
d['__module__'] = obj.__module__
d.update(obj.__dict__)
return d
class MyDecoder(json.JSONDecoder):
def __init__(self):
json.JSONDecoder.__init__(self,object_hook=self.dict2object)
def dict2object(self,d):
#convert dict to object
if'__class__' in d:
class_name = d.pop('__class__')
module_name = d.pop('__module__')
module = __import__(module_name)
class_ = getattr(module,class_name)
args = dict((key.encode('ascii'), value) for key, value in d.items()) #get args
inst = class_(**args) #create new instance
else:
inst = d
return inst
d = MyEncoder().encode(p)
o = MyDecoder().decode(d)
print d
print type(o), o
命名空间
变量名解析规则
- 无点号运算的变量名(eg:X)与作用域相对应
- 点号的属性名(eg:object.X)使用的是对象的命名空间
- 有些作用域会对对象的命名空间进行初始化(模块和类)
命名空间字典
- 模块的命名空间实际上是以字典的形式实现,类与实例对象也一样。
- 属性点号运算其实内部就是字典的索引运算,而属性继承其实就是搜索链接的字典
- 实例通过__class__属性链接到它对应的类,类则通过__bases__属性获得其父类的元组
- 当类为self属性赋值时,会填入实例对象。即属性最后会位于实例的属性命名空间字典内,而不是类的。
- 每个实例都有独立的命名空间字典
类与模块的关系
模块
- 是数据/逻辑包
- 通过编写Python文件或C扩展来创建
- 通过导入来使用
类
- 实现新的对象
- 由class语句创建
- 通过调用来使用
- 总是位于一个模块中
- 支持一些模块所不支持的额外功能,如运算符重载,多实例生成和继承