一,面向对象

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重载:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重载。
  • 实例变量:定义在方法中的变量,只作用于当前实例的类。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 方法:类中定义的函数。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

创建类

使用class语句来创建一个新类,class之后为类的名称并以冒号结尾,如下实例:

  1. class ClassName:
  2. 'Optional class documentation string'#类文档字符串
  3. class_suite #类体

类的帮助信息可以通过ClassName.__doc__查看。

class_suite 由类成员,方法,数据属性组成。

实例

以下是一个简单的Python类实例:

  1. class Employee:
  2. 'Common base class for all employees'
  3. empCount = 0
  4.  
  5. def __init__(self, name, salary):
  6. self.name = name
  7. self.salary = salary
  8. Employee.empCount += 1
  9.  
  10. def displayCount(self):
  11. print "Total Employee %d" % Employee.empCount
  12.  
  13. def displayEmployee(self):
  14. print "Name : ", self.name, ", Salary: ", self.salary
  • empCount变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用Employee.empCount访问。
  • 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法

创建实例对象

要创建一个类的实例,你可以使用类的名称,并通过__init__方法接受参数。

  1. "This would create first object of Employee class"
  2. emp1 = Employee("Zara", 2000)
  3. "This would create second object of Employee class"
  4. emp2 = Employee("Manni", 5000)

访问属性

您可以使用点(.)来访问对象的属性。使用如下类的名称访问类变量:

  1. emp1.displayEmployee()
  2. emp2.displayEmployee()
  3. print "Total Employee %d" % Employee.empCount

完整实例:

  1. #!/usr/bin/python
  2.  
  3. class Employee:
  4. 'Common base class for all employees'
  5. empCount = 0
  6.  
  7. def __init__(self, name, salary):
  8. self.name = name
  9. self.salary = salary
  10. Employee.empCount += 1
  11.  
  12. def displayCount(self):
  13. print "Total Employee %d" % Employee.empCount
  14.  
  15. def displayEmployee(self):
  16. print "Name : ", self.name, ", Salary: ", self.salary
  17.  
  18. "This would create first object of Employee class"
  19. emp1 = Employee("Zara", 2000)
  20. "This would create second object of Employee class"
  21. emp2 = Employee("Manni", 5000)
  22. emp1.displayEmployee()
  23. emp2.displayEmployee()
  24. print "Total Employee %d" % Employee.empCount

执行以上代码输出结果如下:

  1. Name : Zara ,Salary: 2000
  2. Name : Manni ,Salary: 5000
  3. Total Employee 2

你可以添加,删除,修改类的属性,如下所示:

  1. emp1.age = 7 # 添加一个 'age' 属性
  2. emp1.age = 8 # 修改 'age' 属性
  3. del emp1.age # 删除 'age' 属性

你也可以使用以下函数的方式来访问属性:

  • getattr(obj, name[, default]) : 访问对象的属性。
  • hasattr(obj,name) : 检查是否存在一个属性。
  • setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
  • delattr(obj, name) : 删除属性。
  1. hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。
  2. getattr(emp1, 'age') # 返回 'age' 属性的值
  3. setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8
  4. delattr(empl, 'age') # 删除属性 'age'

Python内置类属性

  • __dict__ : 类的属性(包含一个字典,由类的数据属性组成)
  • __doc__ :类的文档字符串
  • __name__: 类名
  • __module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
  • __bases__ : 类的所有父类构成元素(包含了以个由所有父类组成的元组)

Python内置类属性调用实例如下:

  1. #!/usr/bin/python
  2.  
  3. class Employee:
  4. 'Common base class for all employees'
  5. empCount = 0
  6.  
  7. def __init__(self, name, salary):
  8. self.name = name
  9. self.salary = salary
  10. Employee.empCount += 1
  11.  
  12. def displayCount(self):
  13. print "Total Employee %d" % Employee.empCount
  14.  
  15. def displayEmployee(self):
  16. print "Name : ", self.name, ", Salary: ", self.salary
  17.  
  18. print "Employee.__doc__:", Employee.__doc__
  19. print "Employee.__name__:", Employee.__name__
  20. print "Employee.__module__:", Employee.__module__
  21. print "Employee.__bases__:", Employee.__bases__
  22. print "Employee.__dict__:", Employee.__dict__

执行以上代码输出结果如下:

  1. Employee.__doc__: Common base class for all employees
  2. Employee.__name__: Employee
  3. Employee.__module__: __main__
  4. Employee.__bases__: ()
  5. Employee.__dict__: {'__module__': '__main__', 'displayCount':
  6. <function displayCount at 0xb7c84994>, 'empCount': 2,
  7. 'displayEmployee': <function displayEmployee at 0xb7c8441c>,
  8. '__doc__': 'Common base class for all employees',
  9. '__init__': <function __init__ at 0xb7c846bc>}

python对象销毁(垃圾回收)

同Java语言一样,Python使用了引用计数这一简单技术来追踪内存中的对象。

在Python内部记录着所有使用中的对象各有多少引用。

一个内部跟踪变量,称为一个引用计数器。

当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。

  1. a = 40 # 创建对象 <40>
  2. b = a # 增加引用, <40> 的计数
  3. c = [b] # 增加引用. <40> 的计数
  4.  
  5. del a # 减少引用 <40> 的计数
  6. b = 100 # 减少引用 <40> 的计数
  7. c[0] = -1 # 减少引用 <40> 的计数

垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用他们。这种情况下,仅使用引用计数是不够的。Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。

实例

析构函数 __del__ ,__del__在对象消逝的时候被调用,当对象不再被使用时,__del__方法运行:

  1. #!/usr/bin/python
  2.  
  3. class Point:
  4. def __init( self, x=0, y=0):
  5. self.x = x
  6. self.y = y
  7. def __del__(self):
  8. class_name = self.__class__.__name__
  9. print class_name, "destroyed"
  10.  
  11. pt1 = Point()
  12. pt2 = pt1
  13. pt3 = pt1
  14. print id(pt1), id(pt2), id(pt3) # 打印对象的id
  15. del pt1
  16. del pt2
  17. del pt3
  18. <pre>
  19. <p>以上实例运行结果如下:</p>
  20. <pre>
  21. 3083401324 3083401324 3083401324
  22. Point destroyed

注意:通常你需要在单独的文件中定义一个类,

类的继承

面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。

需要注意的地方:继承语法 class 派生类名(基类名)://... 基类名写作括号里,基本类是在类定义的时候,在元组之中指明的。

在python中继承中的一些特点:

  • 1:在继承中基类的构造(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
  • 2:在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
  • 3:Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。

如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。

语法:

派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:

  1. class SubClassName (ParentClass1[, ParentClass2, ...]):
  2. 'Optional class documentation string'
  3. class_suite

实例:

  1. #!/usr/bin/python
  2.  
  3. class Parent: # define parent class
  4. parentAttr = 100
  5. def __init__(self):
  6. print "Calling parent constructor"
  7.  
  8. def parentMethod(self):
  9. print 'Calling parent method'
  10.  
  11. def setAttr(self, attr):
  12. Parent.parentAttr = attr
  13.  
  14. def getAttr(self):
  15. print "Parent attribute :", Parent.parentAttr
  16.  
  17. class Child(Parent): # define child class
  18. def __init__(self):
  19. print "Calling child constructor"
  20.  
  21. def childMethod(self):
  22. print 'Calling child method'
  23.  
  24. c = Child() # 实例化子类
  25. c.childMethod() # 调用子类的方法
  26. c.parentMethod() # 调用父类方法
  27. c.setAttr(200) # 再次调用父类的方法
  28. c.getAttr() # 再次调用父类的方法

以上代码执行结果如下:

  1. Calling child constructor
  2. Calling child method
  3. Calling parent method
  4. Parent attribute : 200

你可以继承多个类

  1. class A: # define your class A
  2. .....
  3.  
  4. class B: # define your calss B
  5. .....
  6.  
  7. class C(A, B): # subclass of A and B
  8. .....

你可以使用issubclass()或者isinstance()方法来检测。

  • issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
  • isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。

重载方法

如果你的父类方法的功能不能满足你的需求,你可以在子类重载你父类的方法:

实例:

  1. #!/usr/bin/python
  2.  
  3. class Parent: # 定义父类
  4. def myMethod(self):
  5. print 'Calling parent method'
  6.  
  7. class Child(Parent): # 定义子类
  8. def myMethod(self):
  9. print 'Calling child method'
  10.  
  11. c = Child() # 子类实例
  12. c.myMethod() # 子类调用重载方法

执行以上代码输出结果如下:

  1. Calling child method

基础重载方法

下表列出了一些通用的功能,你可以在自己的类重写:

序号 方法, 描述 & 简单的调用
1 __init__ ( self [,args...] )

构造函数

简单的调用方法: obj = className(args)
2 __del__( self )

析构方法, 删除一个对象

简单的调用方法 : dell obj
3 __repr__( self )

转化为供解释器读取的形式

简单的调用方法 : repr(obj)
4 __str__( self )

用于将值转化为适于人阅读的形式

简单的调用方法 : str(obj)
5 __cmp__ ( self, x )

对象比较

简单的调用方法 : cmp(obj, x)

运算符重载

Python同样支持运算符重载,实例如下:

  1. #!/usr/bin/python
  2.  
  3. class Vector:
  4. def __init__(self, a, b):
  5. self.a = a
  6. self.b = b
  7.  
  8. def __str__(self):
  9. return 'Vector (%d, %d)' % (self.a, self.b)
  10.  
  11. def __add__(self,other):
  12. return Vector(self.a + other.a, self.b + other.b)
  13.  
  14. v1 = Vector(2,10)
  15. v2 = Vector(5,-2)
  16. print v1 + v2

以上代码执行结果如下所示:

  1. Vector(7,8)

隐藏数据

在python中实现数据隐藏很简单,不需要在前面加什么关键字,只要把类变量名或成员函数前面加两个下划线即可实现数据隐藏的功能,这样,对于类的实例来说,其变量名和成员函数是不能使用的,对于其类的继承类来说,也是隐藏的,这样,其继承类可以定义其一模一样的变量名或成员函数名,而不会引起命名冲突。 实例:

  1. #!/usr/bin/python
  2.  
  3. class JustCounter:
  4. __secretCount = 0
  5.  
  6. def count(self):
  7. self.__secretCount += 1
  8. print self.__secretCount
  9.  
  10. counter = JustCounter()
  11. counter.count()
  12. counter.count()
  13. print counter.__secretCount

Python 通过改变名称来包含类名:

  1. 1
  2. 2
  3. Traceback (most recent call last):
  4. File "test.py", line 12, in <module>
  5. print counter.__secretCount
  6. AttributeError: JustCounter instance has no attribute '__secretCount'

Python不允许实例化的类访问隐藏数据,但你可以使用object._className__attrName访问属性,将如下代码替换以上代码的最后一行代码:

  1. .........................
  2. print counter._JustCounter__secretCount

执行以上代码,执行结果如下:

  1. 1
  2. 2
  3. 2

二,多线程

Python线程

Python中使用线程有两种方式:函数或者用类来包装线程对象。

函数式:调用thread模块中的start_new_thread()函数来产生新线程。语法如下:

  1. thread.start_new_thread ( function, args[, kwargs] )

参数说明:

  • function - 线程函数。
  • args - 传递给线程函数的参数,他必须是个tuple类型。
  • kwargs - 可选参数。

实例:

  1. #!/usr/bin/python
  2.  
  3. import thread
  4. import time
  5.  
  6. # 为线程定义一个函数
  7. def print_time( threadName, delay):
  8. count = 0
  9. while count < 5:
  10. time.sleep(delay)
  11. count += 1
  12. print "%s: %s" % ( threadName, time.ctime(time.time()) )
  13.  
  14. # 创建两个线程
  15. try:
  16. thread.start_new_thread( print_time, ("Thread-1", 2, ) )
  17. thread.start_new_thread( print_time, ("Thread-2", 4, ) )
  18. except:
  19. print "Error: unable to start thread"
  20.  
  21. while 1:
  22. pass

执行以上程序输出结果如下:

  1. Thread-1: Thu Jan 22 15:42:17 2009
  2. Thread-1: Thu Jan 22 15:42:19 2009
  3. Thread-2: Thu Jan 22 15:42:19 2009
  4. Thread-1: Thu Jan 22 15:42:21 2009
  5. Thread-2: Thu Jan 22 15:42:23 2009
  6. Thread-1: Thu Jan 22 15:42:23 2009
  7. Thread-1: Thu Jan 22 15:42:25 2009
  8. Thread-2: Thu Jan 22 15:42:27 2009
  9. Thread-2: Thu Jan 22 15:42:31 2009
  10. Thread-2: Thu Jan 22 15:42:35 2009

线程的结束一般依靠线程函数的自然结束;也可以在线程函数中调用thread.exit(),他抛出SystemExit exception,达到退出线程的目的。


线程模块

Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。

thread 模块提供的其他方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

使用Threading模块创建线程

使用Threading模块创建线程,直接从threading.Thread继承,然后重写__init__方法和run方法:

  1. #!/usr/bin/python
  2.  
  3. import threading
  4. import time
  5.  
  6. exitFlag = 0
  7.  
  8. class myThread (threading.Thread): #继承父类threading.Thread
  9. def __init__(self, threadID, name, counter):
  10. threading.Thread.__init__(self)
  11. self.threadID = threadID
  12. self.name = name
  13. self.counter = counter
  14. def run(self): #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
  15. print "Starting " + self.name
  16. print_time(self.name, self.counter, 5)
  17. print "Exiting " + self.name
  18.  
  19. def print_time(threadName, delay, counter):
  20. while counter:
  21. if exitFlag:
  22. thread.exit()
  23. time.sleep(delay)
  24. print "%s: %s" % (threadName, time.ctime(time.time()))
  25. counter -= 1
  26.  
  27. # 创建新线程
  28. thread1 = myThread(1, "Thread-1", 1)
  29. thread2 = myThread(2, "Thread-2", 2)
  30.  
  31. # 开启线程
  32. thread1.start()
  33. thread2.start()
  34.  
  35. print "Exiting Main Thread"

以上程序执行结果如下;

  1. Starting Thread-1
  2. Starting Thread-2
  3. Exiting Main Thread
  4. Thread-1: Thu Mar 21 09:10:03 2013
  5. Thread-1: Thu Mar 21 09:10:04 2013
  6. Thread-2: Thu Mar 21 09:10:04 2013
  7. Thread-1: Thu Mar 21 09:10:05 2013
  8. Thread-1: Thu Mar 21 09:10:06 2013
  9. Thread-2: Thu Mar 21 09:10:06 2013
  10. Thread-1: Thu Mar 21 09:10:07 2013
  11. Exiting Thread-1
  12. Thread-2: Thu Mar 21 09:10:08 2013
  13. Thread-2: Thu Mar 21 09:10:10 2013
  14. Thread-2: Thu Mar 21 09:10:12 2013
  15. Exiting Thread-2

线程同步

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。

那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

实例:

  1. #!/usr/bin/python
  2.  
  3. import threading
  4. import time
  5.  
  6. class myThread (threading.Thread):
  7. def __init__(self, threadID, name, counter):
  8. threading.Thread.__init__(self)
  9. self.threadID = threadID
  10. self.name = name
  11. self.counter = counter
  12. def run(self):
  13. print "Starting " + self.name
  14. # 获得锁,成功获得锁定后返回True
  15. # 可选的timeout参数不填时将一直阻塞直到获得锁定
  16. # 否则超时后将返回False
  17. threadLock.acquire()
  18. print_time(self.name, self.counter, 3)
  19. # 释放锁
  20. threadLock.release()
  21.  
  22. def print_time(threadName, delay, counter):
  23. while counter:
  24. time.sleep(delay)
  25. print "%s: %s" % (threadName, time.ctime(time.time()))
  26. counter -= 1
  27.  
  28. threadLock = threading.Lock()
  29. threads = []
  30.  
  31. # 创建新线程
  32. thread1 = myThread(1, "Thread-1", 1)
  33. thread2 = myThread(2, "Thread-2", 2)
  34.  
  35. # 开启新线程
  36. thread1.start()
  37. thread2.start()
  38.  
  39. # 添加线程到线程列表
  40. threads.append(thread1)
  41. threads.append(thread2)
  42.  
  43. # 等待所有线程完成
  44. for t in threads:
  45. t.join()
  46. print "Exiting Main Thread"

线程优先级队列( Queue)

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

Queue模块中的常用方法:

  • Queue.qsize() 返回队列的大小
  • Queue.empty() 如果队列为空,返回True,反之False
  • Queue.full() 如果队列满了,返回True,反之False
  • Queue.full 与 maxsize 大小对应
  • Queue.get([block[, timeout]])获取队列,timeout等待时间
  • Queue.get_nowait() 相当Queue.get(False)
  • Queue.put(item) 写入队列,timeout等待时间
  • Queue.put_nowait(item) 相当Queue.put(item, False)
  • Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
  • Queue.join() 实际上意味着等到队列为空,再执行别的操作

实例:

  1. #!/usr/bin/python
  2.  
  3. import Queue
  4. import threading
  5. import time
  6.  
  7. exitFlag = 0
  8.  
  9. class myThread (threading.Thread):
  10. def __init__(self, threadID, name, q):
  11. threading.Thread.__init__(self)
  12. self.threadID = threadID
  13. self.name = name
  14. self.q = q
  15. def run(self):
  16. print "Starting " + self.name
  17. process_data(self.name, self.q)
  18. print "Exiting " + self.name
  19.  
  20. def process_data(threadName, q):
  21. while not exitFlag:
  22. queueLock.acquire()
  23. if not workQueue.empty():
  24. data = q.get()
  25. queueLock.release()
  26. print "%s processing %s" % (threadName, data)
  27. else:
  28. queueLock.release()
  29. time.sleep(1)
  30.  
  31. threadList = ["Thread-1", "Thread-2", "Thread-3"]
  32. nameList = ["One", "Two", "Three", "Four", "Five"]
  33. queueLock = threading.Lock()
  34. workQueue = Queue.Queue(10)
  35. threads = []
  36. threadID = 1
  37.  
  38. # 创建新线程
  39. for tName in threadList:
  40. thread = myThread(threadID, tName, workQueue)
  41. thread.start()
  42. threads.append(thread)
  43. threadID += 1
  44.  
  45. # 填充队列
  46. queueLock.acquire()
  47. for word in nameList:
  48. workQueue.put(word)
  49. queueLock.release()
  50.  
  51. # 等待队列清空
  52. while not workQueue.empty():
  53. pass
  54.  
  55. # 通知线程是时候退出
  56. exitFlag = 1
  57.  
  58. # 等待所有线程完成
  59. for t in threads:
  60. t.join()
  61. print "Exiting Main Thread"

以上程序执行结果:

  1. Starting Thread-1
  2. Starting Thread-2
  3. Starting Thread-3
  4. Thread-1 processing One
  5. Thread-2 processing Two
  6. Thread-3 processing Three
  7. Thread-1 processing Four
  8. Thread-2 processing Five
  9. Exiting Thread-3
  10. Exiting Thread-1
  11. Exiting Thread-2
  12. Exiting Main Thread

三,XML解析

python对XML的解析

常见的XML编程接口有DOM和SAX,这两种接口处理XML文件的方式不同,当然使用场合也不同。

python有三种方法解析XML,SAX,DOM,以及ElementTree:

1.SAX (simple API for XML )

pyhton 标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。

2.DOM(Document Object Model)

将XML数据在内存中解析成一个树,通过对树的操作来操作XML。

3.ElementTree(元素树)

ElementTree就像一个轻量级的DOM,具有方便友好的API。代码可用性好,速度快,消耗内存少。

注:因DOM需要将XML数据映射到内存中的树,一是比较慢,二是比较耗内存,而SAX流式读取XML文件,比较快,占用内存少,但需要用户实现回调函数(handler)。

本章节使用到的XML实例文件movies.xml内容如下:

  1. <collection shelf="New Arrivals">
  2. <movie title="Enemy Behind">
  3. <type>War, Thriller</type>
  4. <format>DVD</format>
  5. <year>2003</year>
  6. <rating>PG</rating>
  7. <stars>10</stars>
  8. <description>Talk about a US-Japan war</description>
  9. </movie>
  10. <movie title="Transformers">
  11. <type>Anime, Science Fiction</type>
  12. <format>DVD</format>
  13. <year>1989</year>
  14. <rating>R</rating>
  15. <stars>8</stars>
  16. <description>A schientific fiction</description>
  17. </movie>
  18. <movie title="Trigun">
  19. <type>Anime, Action</type>
  20. <format>DVD</format>
  21. <episodes>4</episodes>
  22. <rating>PG</rating>
  23. <stars>10</stars>
  24. <description>Vash the Stampede!</description>
  25. </movie>
  26. <movie title="Ishtar">
  27. <type>Comedy</type>
  28. <format>VHS</format>
  29. <rating>PG</rating>
  30. <stars>2</stars>
  31. <description>Viewable boredom</description>
  32. </movie>
  33. </collection>

python使用SAX解析xml

SAX是一种基于事件驱动的API。

利用SAX解析XML文档牵涉到两个部分:解析器和事件处理器。

解析器负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件;

而事件处理器则负责对事件作出相应,对传递的XML数据进行处理。

  • 1、对大型文件进行处理;
  • 2、只需要文件的部分内容,或者只需从文件中得到特定信息。
  • 3、想建立自己的对象模型的时候。

在python中使用sax方式处理xml要先引入xml.sax中的parse函数,还有xml.sax.handler中的ContentHandler。

ContentHandler类方法介绍

characters(content)方法

调用时机:

从行开始,遇到标签之前,存在字符,content的值为这些字符串。

从一个标签,遇到下一个标签之前, 存在字符,content的值为这些字符串。

从一个标签,遇到行结束符之前,存在字符,content的值为这些字符串。

标签可以是开始标签,也可以是结束标签。

startDocument()方法

文档启动的时候调用。

endDocument()方法

解析器到达文档结尾时调用。

startElement(name, attrs)方法

遇到XML开始标签时调用,name是标签的名字,attrs是标签的属性值字典。

endElement(name)方法

遇到XML结束标签时调用。


make_parser方法

以下方法创建一个新的解析器对象并返回。

  1. xml.sax.make_parser( [parser_list] )

参数说明:

  • parser_list - 可选参数,解析器列表

parser方法

以下方法创建一个 SAX 解析器并解析xml文档:

  1. xml.sax.parse( xmlfile, contenthandler[, errorhandler])

参数说明:

  • xmlfile - xml文件名
  • contenthandler - 必须是一个ContentHandler的对象
  • errorhandler - 如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象

parseString方法

parseString方法创建一个XML解析器并解析xml字符串:

  1. xml.sax.parseString(xmlstring, contenthandler[, errorhandler])

参数说明:

  • xmlstring - xml字符串
  • contenthandler - 必须是一个ContentHandler的对象
  • errorhandler - 如果指定该参数,errorhandler必须是一个SAX ErrorHandler对象

Python 解析XML实例

  1. #!/usr/bin/python
  2.  
  3. import xml.sax
  4.  
  5. class MovieHandler( xml.sax.ContentHandler ):
  6. def __init__(self):
  7. self.CurrentData = ""
  8. self.type = ""
  9. self.format = ""
  10. self.year = ""
  11. self.rating = ""
  12. self.stars = ""
  13. self.description = ""
  14.  
  15. # 元素开始事件处理
  16. def startElement(self, tag, attributes):
  17. self.CurrentData = tag
  18. if tag == "movie":
  19. print "*****Movie*****"
  20. title = attributes["title"]
  21. print "Title:", title
  22.  
  23. # 元素结束事件处理
  24. def endElement(self, tag):
  25. if self.CurrentData == "type":
  26. print "Type:", self.type
  27. elif self.CurrentData == "format":
  28. print "Format:", self.format
  29. elif self.CurrentData == "year":
  30. print "Year:", self.year
  31. elif self.CurrentData == "rating":
  32. print "Rating:", self.rating
  33. elif self.CurrentData == "stars":
  34. print "Stars:", self.stars
  35. elif self.CurrentData == "description":
  36. print "Description:", self.description
  37. self.CurrentData = ""
  38.  
  39. # 内容事件处理
  40. def characters(self, content):
  41. if self.CurrentData == "type":
  42. self.type = content
  43. elif self.CurrentData == "format":
  44. self.format = content
  45. elif self.CurrentData == "year":
  46. self.year = content
  47. elif self.CurrentData == "rating":
  48. self.rating = content
  49. elif self.CurrentData == "stars":
  50. self.stars = content
  51. elif self.CurrentData == "description":
  52. self.description = content
  53.  
  54. if ( __name__ == "__main__"):
  55.  
  56. # 创建一个 XMLReader
  57. parser = xml.sax.make_parser()
  58. # turn off namepsaces
  59. parser.setFeature(xml.sax.handler.feature_namespaces, 0)
  60.  
  61. # 重写 ContextHandler
  62. Handler = MovieHandler()
  63. parser.setContentHandler( Handler )
  64.  
  65. parser.parse("movies.xml")

以上代码执行结果如下:

  1. *****Movie*****
  2. Title: Enemy Behind
  3. Type: War, Thriller
  4. Format: DVD
  5. Year: 2003
  6. Rating: PG
  7. Stars: 10
  8. Description: Talk about a US-Japan war
  9. *****Movie*****
  10. Title: Transformers
  11. Type: Anime, Science Fiction
  12. Format: DVD
  13. Year: 1989
  14. Rating: R
  15. Stars: 8
  16. Description: A schientific fiction
  17. *****Movie*****
  18. Title: Trigun
  19. Type: Anime, Action
  20. Format: DVD
  21. Rating: PG
  22. Stars: 10
  23. Description: Vash the Stampede!
  24. *****Movie*****
  25. Title: Ishtar
  26. Type: Comedy
  27. Format: VHS
  28. Rating: PG
  29. Stars: 2
  30. Description: Viewable boredom

完整的 SAX API 文档请查阅Python SAX APIs


使用xml.dom解析xml

文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口。

一个 DOM 的解析器在解析一个 XML 文档时,一次性读取整个文档,把文档中所有元素保存在内存中的一个树结构里,之后你可以利用DOM 提供的不同的函数来读取或修改文档的内容和结构,也可以把修改过的内容写入xml文件。

python中用xml.dom.minidom来解析xml文件,实例如下:

  1. #!/usr/bin/python
  2.  
  3. from xml.dom.minidom import parse
  4. import xml.dom.minidom
  5.  
  6. # 使用minidom解析器打开 XML 文档
  7. DOMTree = xml.dom.minidom.parse("movies.xml")
  8. collection = DOMTree.documentElement
  9. if collection.hasAttribute("shelf"):
  10. print "Root element : %s" % collection.getAttribute("shelf")
  11.  
  12. # 在集合中获取所有电影
  13. movies = collection.getElementsByTagName("movie")
  14.  
  15. # 打印每部电影的详细信息
  16. for movie in movies:
  17. print "*****Movie*****"
  18. if movie.hasAttribute("title"):
  19. print "Title: %s" % movie.getAttribute("title")
  20.  
  21. type = movie.getElementsByTagName('type')[0]
  22. print "Type: %s" % type.childNodes[0].data
  23. format = movie.getElementsByTagName('format')[0]
  24. print "Format: %s" % format.childNodes[0].data
  25. rating = movie.getElementsByTagName('rating')[0]
  26. print "Rating: %s" % rating.childNodes[0].data
  27. description = movie.getElementsByTagName('description')[0]
  28. print "Description: %s" % description.childNodes[0].data

以上程序执行结果如下:

Root element : New Arrivals*****Movie*****Title: Enemy BehindType: War, ThrillerFormat: DVDRating: PGDescription: Talk about a US-Japan war*****Movie*****Title: TransformersType: Anime, Science FictionFormat: DVDRating: RDescription: A schientific fiction*****Movie*****Title:
TrigunType: Anime, ActionFormat: DVDRating: PGDescription: Vash the Stampede!*****Movie*****Title: IshtarType: ComedyFormat: VHSRating: PGDescription: Viewable boredom

Python入门(四,高级)的更多相关文章

  1. python入门四:异常

    一.异常 异常就是在触发异常条件时(解释器或程序员)而采取相应的措施 c++中异常使用try, throw, catch等关键字,而python中使用try, raise, except等 二.标准异 ...

  2. Python爬虫入门四之Urllib库的高级用法

    1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...

  3. 转 Python爬虫入门四之Urllib库的高级用法

    静觅 » Python爬虫入门四之Urllib库的高级用法 1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我 ...

  4. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

  5. Python学习系列(四)Python 入门语法规则2

    Python学习系列(四)Python 入门语法规则2 2017-4-3 09:18:04 编码和解码 Unicode.gbk,utf8之间的关系 2.对于py2.7, 如果utf8>gbk, ...

  6. Python入门篇-封装与解构和高级数据类型集合(set)和字典(dict)

    Python入门篇-封装与解构和高级数据类型集合(set)和字典(dict) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.封装和结构 #!/usr/bin/env pytho ...

  7. Python基本语法[二],python入门到精通[四]

    在上一篇博客Python基本语法,python入门到精通[二]已经为大家简单介绍了一下python的基本语法,上一篇博客的基本语法只是一个预览版的,目的是让大家对python的基本语法有个大概的了解. ...

  8. 2018-06-20 中文代码示例视频演示Python入门教程第四章 控制流

    知乎原链 续前作: 中文代码示例视频演示Python入门教程第三章 简介Python 对应在线文档: 4. More Control Flow Tools 录制中出了不少岔子. 另外, 输入法确实是一 ...

  9. Linux运维入门到高级全套常用要点

    Linux运维入门到高级全套常用要点 目 录 1. Linux 入门篇................................................................. ...

  10. python入门简介

    Python前世今生 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本解释程序,作为ABC ...

随机推荐

  1. 20145236 《Java程序设计》第九周学习总结

    20145236 <Java程序设计>第九周学习总结 教材学习内容总结 第十六章 整合数据库 JDBC简介 1.JDBC是java联机数据库的标准规范.它定义了一组标准类与接口,标准API ...

  2. Spring使用RowMapper将数据中的每一行封装成用户定义的类

    1.dao public interface MapperSelecteAllEmpDao { public List<Emp> all(); } 2.实现类 public class M ...

  3. Java多线程-新特征-阻塞队列ArrayBlockingQueue

    阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素 ...

  4. 隐藏chrome空白标签栏的最近访问

    chrome版本: 29.0.1547.76 m 找到安装路径下Custom.css文件,添加.most-visited{display:none !important}来修改样式. 我的路径为:C: ...

  5. noip知识点总结之--线性筛法及其拓展

    一.线性筛法 众所周知...线性筛就是在O(n)的时间里找出所有素数的方法 code: void get_prime(int N){ int i, j, k; memset(Flag, ); ; i ...

  6. LAMP整理

    LAMP第一部分 查看编译了哪些软件:是编译时自动生成的 Cat /usr/local/apache2/build/config.nice 网站根目录存放处: /usr/local/apache2/h ...

  7. 使用Linq快速的操作XML

    开始内容之前先分享一段话 有时候,当你知道要做什么的时候就做的很快,比如你要实现个功能,码字的活儿不算很难,做个检索也不会有什么难倒你的.但是,做着做着,你发现好像世界上的工作都在重复,于是你有种心要 ...

  8. python使用urllib2抓取网页

    1.使用python的库urllib2,用到urlopen和Request方法. 2.方法urlopen原形 urllib2.urlopen(url[, data][, timeout]) 其中: u ...

  9. 转: Div与table的区别

    1:速度和加载方式方面的区别 div 和 table 的差异不是速度,而是加载方式,速度只能是指网络速度,如果速度足够快,是没有差异的: div 的加载方式是即读即加载,遇到 <div> ...

  10. 判断一个字符串是否为有效ip地址

    bool f (const char *s) { int s1,s2,s3,s4; ) { return false; } if ((s1 & 0xffffff00) || (s2 & ...