4.2.1 Codec基类

在codecs模块里定义了与codec对象进行交互的接口,也可以使用它作为其它编解码的基类。 在Python里要求codec对象需要有四个接口:无状态的encoder,无状态的decoder,StreamReader和StreamWriter。而StreamReader和StreamWriter通常是由无状态的encoder/decoder通过文件协议来实现。同时codec对象还需要处理在编码和解码里出现的错误。

4.2.1.1 错误处理

codecs模块通过errors字符串参数来实现不同的错误处理,同时为了简化和标准化错误处理,需要定义错误标准处理如下:



意义


‘strict’


抛出异常UnicodeError;默认的情况下选用这个方式,具体实现在函数strict_errors()里。


‘ignore’


忽略错误数据,并且不提示出错。具体实现在函数codecs.ignore_errors()。

下面是在文本编解码时的错误处理:



意义


‘replace’


不合法的字符使用指定字符替换。在解码出错时使用U+FFFD来替换,在编码时使用‘?’替换。具体实现在函数replace_errors()函数。


‘xmlcharrefreplace’


当在XML字符编码时,修改为合适的XML引用代替。具体实现在函数xmlcharrefreplace_errors()。


‘backslashreplace’


当在编码时,不认识字符可以使用反斜杠序列来代替。具体实现函数在backslashreplace_errors()。


‘surrogateescape’


当在解码和编码时使用替代字符,比如空字符在UTF8里可能是结束标记,但又需要对它进行编码,就需要使用替换字符来解决。具体情况请参考PEP 383。

在utf-8, utf-16, utf-32, utf-16-be, utf-16-le, utf-32-be, utf-32-le编码和解码里,可以采用surrogatepass的错误处理方式。

通过下面的函数可以设置新的错误处理方式:

codecs.register_error(name, error_handler)

注册一个以name名称的错误处理函数error_handler。当编码或者解码出错时,就会调用此函数进行处理。name是作为一个错误参数与解码或编码时传入参数进行比较。

例子:

#python 3.4.3

import codecs

codecs.register_error(‘test‘, codecs.strict_errors)

fun = codecs.lookup_error(‘test‘)

print(fun)

结果输出如下:

<built-in function strict_errors>

codecs.lookup_error(name)

通过名称查找错误处理函数返回,如果没有发现抛出异常LookupError。

例子:

#python 3.4.3

import codecs

codecs.register_error(‘test‘, codecs.strict_errors)

fun = codecs.lookup_error(‘test007‘)

print(fun)

结果输出如下:

Traceback (most recent call last):

File "E:\codecs1.py", line 5, in <module>

fun = codecs.lookup_error(‘test007‘)

LookupError: unknown error handler name ‘test007‘

codecs.strict_errors(exception)

实现‘strict’方式的错误处理函数,每次编码或解码出错时抛出异常UnicodeError。

codecs.replace_errors(exception)

实现‘replace’方式的错误处理函数。

codecs.ignore_errors(exception)

实现‘ignore’方式的错误处理函数。

codecs.xmlcharrefreplace_errors(exception)

实现‘xmlcharrefreplace’方式的错误处理函数。

codecs.backslashreplace_errors(exception)

实现‘backslashreplace’方式的错误处理函数。

例子:

#python 3.4.3

import codecs

import unittest

def test_badandgoodstrictexceptions(self):

# "strict" complains about a non-exception passed in

self.assertRaises(

TypeError,

codecs.strict_errors,

42

)

# "strict" complains about the wrong exception type

self.assertRaises(

Exception,

codecs.strict_errors,

Exception("ouch")

)

# If the correct exception is passed in, "strict" raises it

self.assertRaises(

UnicodeEncodeError,

codecs.strict_errors,

UnicodeEncodeError("ascii", u"\u3042", 0, 1, "ouch")

)

if __name__ == ‘__main__‘:

unittest.main()

结果输出如下:

----------------------------------------------------------------------

Ran 0 tests in 0.000s

OK

4.2.1.2 无状态的编码和解码处理

在Codec的基类里定义无状态的编码和解码处理,也就是encoder和decoder的相关接口函数。具体如下:

Codec.encode(input[, errors])

对输入对象input进行编码,然后返回元组对象(输出对象,数据长度)。例如,在文本编码里转换一个字符串对象到一个bytes对象。errors是定义错误处理方式,默认是strict处理方式。本基类不提供保存状态在Codec实例对象里,如果需要保存状态需要使用StreamCodec作为基类对象。enocde函数需要考虑0个字符的输入情况,并能返回空对象。

Codec.decode(input[, errors])

对输入对象input进行解码,然后返回元组对象(输出对象,数据长度)。例如,在文本编码里转换一个bytes对象到合适编码的字符串对象。对文本编码或者字节到字节的转换里,参数input要求是一个bytes对象,或者提供缓冲区访问协议的对象。errors是定义错误处理方式,默认是strict处理方式。本基类不提供保存状态在Codec实例对象里,如果需要保存状态需要使用StreamCodec作为基类对象。enocde函数需要考虑0个字符的输入情况,并能返回空对象。

例子:

#python 3.4.3

import codecs

# Stateless encoder/decoder

class TestCodec(codecs.Codec):

def encode(self, input, errors=‘strict‘):

return (‘abc‘, 3)

def decode(self, input, errors=‘strict‘):

return (‘abc‘, 3)

# Incremental forms

class TestCodecIncrementalEncoder(codecs.IncrementalEncoder):

def encode(self, input, final=False):

return ‘abc‘

class TestCodecIncrementalDecoder(codecs.IncrementalDecoder):

def decode(self, input, final=False):

return ‘abc‘

# Stream reader and writer

class TestCodecStreamReader(TestCodec, codecs.StreamReader):

pass

class TestCodecStreamWriter(TestCodec, codecs.StreamWriter):

pass

def find_TestCodec(encoding):

"""Return the codec for ‘testcodec‘.

"""

if encoding == ‘testcodec‘:

print(encoding)

return codecs.CodecInfo(

name=‘testcodec‘,

encode=TestCodec().encode,

decode=TestCodec().decode,

incrementalencoder=TestCodecIncrementalEncoder,

incrementaldecoder=TestCodecIncrementalDecoder,

streamreader=TestCodecStreamReader,

streamwriter=TestCodecStreamWriter,

)

return None

#注册新的编解码对象

codecs.register(find_TestCodec)

encoder = codecs.getencoder(‘testcodec‘)

text = ‘abc.DEF‘

encoded_text, consumed = encoder(text)

print(encoded_text, consumed)

结果输出如下:

testcodec

abc 3

在这个例里的注意点是编码器的名称一定要是全部小写字符命名,否则查找不到。

4.2.1.3 有状态的编码和解码处理

对有状态的编码和解码处理主要提供两个基类的接口,这两个基类分别是:IncrementalEncoder和IncrementalDecoder。前面两个基类encoder和decoder 是无状态的基类接口,只需要调用一次就处理完成,而后面两个基类提供的接口函数是可以多次调用,递增方式进行编码和解码,并且跟踪多次调用之间的状态。

4.2.1.3.1 IncrementalEncoder对象

基类IncrementalEncoder 主要用来对多步输入进行编码,主要定义下面的接口,以便可以符合Python注册Codec编解码器的标准。

class codecs.IncrementalEncoder(errors=‘strict‘)

构造一个递增式的编码实现对象。所有基于IncrementalEncoder类的派生类,必须实现此接口,这个接口的参数是可以自由定义的,不过必须有errors这个参数,以便给codec注册时使用。同时IncrementalEncoder也可以依据errors提供不同的错误处理,具体工作请参考前面介绍的错误处理方式。

encode(object[, final])

对输入对象object进行编码,如果最后一次调用需要设置final为True,返回编码后的对象。

reset()

复位编码对象为初始状态。

IncrementalEncoder.getstate()

获取当前编码对象的状态码,用整数表示。实现上要求通用的状态码为0表示。

IncrementalEncoder.setstate(state)

设置编码对象所处的状态。

4.2.1.3.2 IncrementalDecoder对象

基类IncrementalDecoder实现多步骤解码的接口。

class codecs.IncrementalDecoder(errors=‘strict‘)

构造一个递增式的解码实现对象。所有基于IncrementalDecoder类的派生类,必须实现此接口,这个接口的参数是可以自由定义的,不过必须有errors这个参数,以便给codec注册时使用。同时IncrementalDecoder也可以依据errors提供不同的错误处理,具体工作请参考前面介绍的错误处理方式。

decode(object[, final])

对输入对象object进行解码,如果最后一次调用需要设置final为True,返回解码后的对象。

reset()

复位解码对象为初始状态。

IncrementalDecoder.getstate()

获取当前解码对象的状态码,用整数表示。实现上要求通用的状态码为0表示。

IncrementalDecoder.setstate(state)

设置解码对象所处的状态。

4.2.1.4 流方式编码和解码处理

类StreamWriter和StreamReader是实现新的流编解码处理的基础,它提供了所有接口。

4.2.1.4.1 StreamWriter对象

类StreamWriter是Codec的子类,为了能在Codec里注册,需要所有继承类StreamWriter的派生类都实现下面的接口。

class codecs.StreamWriter(stream, errors=‘strict‘)

类StreamWriter的构造函数,用来构造StreamWriter的实例对象。所有继承的类都应实现此接口,参数的个数自由定义,但stream和errors参数必须定义。参数stream必须是文件类似的对象,用来打开文本或二进制的数据。参数errors可以定义不同的错误处理函数。

write(object)

把对象object的内容进行编码然后写到流里面。

writelines(list)

把列表list里的字符串连接起来写到流里面。注意字节到字节的编码不支持。

reset()

立即输出缓冲区里的内容,并复位所有用到的缓冲区。

4.2.1.4.2 StreamReader对象

类StreamReader是Codec的子类,为了能在Codec里注册,需要所有继承类StreamReader的派生类都实现下面的接口。

class codecs.StreamReader(stream, errors=‘strict‘)

构造一个StreamReader对象实例,所有继承此类的类都要实现此接口。至少定义两个参数,其它参数按需要添加。参数stream是文件类似的对象,用来打开读取文件或二进制数据。可以根据参数errors实现在解码处理过程中出错时不同的错误处理。

read([size[, chars[, firstline]]])

从流对象里读取数据并解码,返回数据对象。 参数chars是指明解码需要多少个字节。参数size是最大解码需要的字节数,或者需要读取多少字节来解码。如果设置为为-1表示尽可能多地读取出来解码。参数firstline是如果后面行解码失败,只需要返回第一行。调用这个函数要注意是返回的大小等于size或者小于size,不会超过size的大小。

readline([size[, keepends]])

从输入流里读取一行数据并解码返回。

如果有给出读取大小size,那么就按这个大小到文件流里读取。

如果keepends为false,那么最后一行的结束符号会删除掉。

readlines([sizehint[, keepends]])

从输入流里读取所有行数据,并解码写到列表里返回。

如果有给出读取大小sizehint,那么就按这个大小到文件流里读取。

如果keepends为false,那么最后一行的结束符号会删除掉。

reset()

复位所有缓冲区。

4.2.1.4.3 StreamReaderWriter对象

类StreamReaderWriter是StreamReader和StreamWriter的组合类,它合并了流文件的读取和写入的功能。这样设计可以很方便地通过工厂函数lookup()来构造一个流对象。

class codecs.StreamReaderWriter(stream, Reader, Writer, errors)

构造一个StreamReaderWriter对象。参数stream是像文件类似的流对象。参数Reader和Writer可以是工厂函数,也可以是StreamReader和StreamWriter对象。

4.2.1.4.4 StreamRecoder对象

类StreamRecoder是实现从一种编码到另一种编码的转换,当在不同编码之间进行转换时比较有用。同时可以通过工厂函数lookup()来构造实例对象。

class codecs.StreamRecoder(stream, encode, decode, Reader, Writer, errors)

构造一个StreamRecoder对象,它实现两种转换方式:encode和decode工作在前端,而Reader和Writer是工作在后端,主要调用read()和writer()实现。通过此函数可以实现从Latin-1编码到UTF-8的编码进行相互转换。

参数stream是文件类似的对象。参数encode和decode是Codec的接口。参数Reader和Writer是流对象StreamReader和StreamWriter的接口。

蔡军生  QQ:9073204  深圳

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-15 12:52:00

4.2.1 Codec基类的相关文章

4.2 codecs--Codec注册管理和基类

本模块定义了Python标准codecs(编码和解码)的基类,也提供了对Python内部codec的注册,管理和数据处理过程.大部分标准的codecs都是文本编解码器,主要是用来把文本怎么样编码成字节方式.不过也有一些codecs是用来从文本到文本的编码方式,或者从字节到字节的编码方式.当然也可以根据基类来定制codecs,可以任意间的数据类型进行转换,只要注意在某些codecs是限制在文本编解码,某些是限制在字节之间编解码的. 对于任何的编解码器codec都有下面的函数: codecs.enc

当this指针成为指向之类的基类指针时,也能形成多态

this指针: 1)对象中没有函数,只有成员变量 2)对象调用函数,通过this指针告诉函数是哪个对象自己谁. 1 #include<iostream> 2 using namespace std; 3 class Shape 4 { 5 public: 6 //void cal_display(Shape* this) 7 void cal_display(){ 8 display(); 9 this->display(); 10 } 11 private: 12 virtual vo

基于MVC4+EasyUI的Web开发框架形成之旅--基类控制器CRUD的操作

在上一篇随笔中,我对Web开发框架的总体界面进行了介绍,其中并提到了我的<Web开发框架>的控制器的设计关系,Web开发框架沿用了我的<Winform开发框架>的很多架构设计思路和特点,对Controller进行了封装.使得控制器能够获得很好的继承关系,并能以更少的代码,更高效的开发效率,实现Web项目的开发工作,整个控制器的设计思路如下所示. 从上图的设计里面可以看到,我把主要能通过抽象封装的CRUD方法都放到了BusinessController<B, T>类里面,

C++中虚基类

摘自<C++程序设计> 如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员. C++提供虚基类(virtual base class)的方法,使得在继承间接共同基类时只保留一份成员. 下面举例说明: 在如下的图中: Person类是Student和Teacher的基类,而Graduate类又继承自Student和Teacher类. 如果使用虚基类的话,Graduate将有两份age拷贝,两份gender拷贝,两份name

UI(UGUI)框架(二)-------------UIManager单例模式与开发BasePanel面板基类/UIManage统一管理UI面板的实例化/开发字典扩展类

UIManage单实例: 1 /// 单例模式的核心 2 /// 1,定义一个静态的对象 在外界访问 在内部构造 3 /// 2,构造方法私有化 4 5 private static UIManager _instance; 6 7 public static UIManager Instance 8 { 9 get 10 { 11 if (_instance == null) 12 { 13 _instance = new UIManager(); 14 } 15 return _instan

从设计基类及其派生类看继承关系

继承能够定义可重用.扩展或修改父类行为的子类.但基类的静态构造函数.实例构造函数和析构函数不能被派生类继承. 在下面实例中,定义一个基类Publication用于表示任何类型的出版物以及派生至Publication的其他类型Book类,由此也可以扩展为定义其他类型如:Magazine.Journal.Newspaper和Article. 在设计基类Publication时我们必须考虑到如下关系: 1.要在基类中添加哪些成员 2.基类是否用作派生类模板的抽象基类 3.类层次结构的扩展空间大小,要开

EF增删查改基类

/// <summary> /// EF DAL CURD基类 /// </summary> /// <typeparam name="T"></typeparam> public class BaseDAL<T> where T : class, new() { /// <summary> /// 上下文网关 /// </summary> protected SchoolEntities db = n

派生类和基类的转换

指针引用分四种情况: 1.直接用基类指针引用基类对象 2.直接用派生指针引用派生对象 3.由基类指针引用派生类对象,由于派生类也是基类对象(包含关系),所以这种引用是安全的.但是只能引用基类成员,若试图通过基类指针引用那些只在派生类中才有的成员,编译器会报告语法错误.(解决该问题的答案是虚函数和多态性) 4.用派生类指针引用基类对象,这种方式会导致编译器报错.必须先把派生类指针强制转换成基类指针. 如果基类和派生类都定义了同名函数,通过对象指针调用成员函数时,到底调用哪里的函数由指针的原始类型决

第六篇:为多态基类声明虚析构函数

前言 在很多类中,可以看到其析构函数都是声明为虚函数的. 那么,为何要将析构函数声明为虚函数?哪些情况要将析构函数声明为虚函数? 本文将为你解惑. 在使用 C++ 实现多态的时候,有一点一定要清楚:当派生类对象经由基类指针被删除,而此基类的析构函数没有被声明为虚函数的话,那么析构函数只会释放基类部分的成员而无视派生类成员. 如果不对这一点加以防范,那么很多时候,会带来内存泄露这样灾难性的后果. 问题描述 假设,有以下几个类,分别代表:钟,原子钟,水钟,腕表: 1 // 钟 2 class Tim