• Python入门(四,高级)


    一,面向对象

    面向对象技术简介

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

    创建类

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

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

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

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

    实例

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

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

    创建实例对象

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

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

    访问属性

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

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

    完整实例:

    #!/usr/bin/python
    
    class Employee:
       'Common base class for all employees'
       empCount = 0
    
       def __init__(self, name, salary):
          self.name = name
          self.salary = salary
          Employee.empCount += 1
       
       def displayCount(self):
         print "Total Employee %d" % Employee.empCount
    
       def displayEmployee(self):
          print "Name : ", self.name,  ", Salary: ", self.salary
    
    "This would create first object of Employee class"
    emp1 = Employee("Zara", 2000)
    "This would create second object of Employee class"
    emp2 = Employee("Manni", 5000)
    emp1.displayEmployee()
    emp2.displayEmployee()
    print "Total Employee %d" % Employee.empCount
    

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

    Name :  Zara ,Salary:  2000
    Name :  Manni ,Salary:  5000
    Total Employee 2
    

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

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

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

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

    Python内置类属性

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

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

    #!/usr/bin/python
    
    class Employee:
       'Common base class for all employees'
       empCount = 0
    
       def __init__(self, name, salary):
          self.name = name
          self.salary = salary
          Employee.empCount += 1
       
       def displayCount(self):
         print "Total Employee %d" % Employee.empCount
    
       def displayEmployee(self):
          print "Name : ", self.name,  ", Salary: ", self.salary
    
    print "Employee.__doc__:", Employee.__doc__
    print "Employee.__name__:", Employee.__name__
    print "Employee.__module__:", Employee.__module__
    print "Employee.__bases__:", Employee.__bases__
    print "Employee.__dict__:", Employee.__dict__
    

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

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

    python对象销毁(垃圾回收)

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

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

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

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

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

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

    实例

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

    #!/usr/bin/python
    
    class Point:
       def __init( self, x=0, y=0):
          self.x = x
          self.y = y
       def __del__(self):
          class_name = self.__class__.__name__
          print class_name, "destroyed"
    
    pt1 = Point()
    pt2 = pt1
    pt3 = pt1
    print id(pt1), id(pt2), id(pt3) # 打印对象的id
    del pt1
    del pt2
    del pt3
    <pre>
    <p>以上实例运行结果如下:</p>
    <pre>
    3083401324 3083401324 3083401324
    Point destroyed
    

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

    类的继承

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

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

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

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

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

    语法:

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

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

    实例:

    #!/usr/bin/python
    
    class Parent:        # define parent class
       parentAttr = 100
       def __init__(self):
          print "Calling parent constructor"
    
       def parentMethod(self):
          print 'Calling parent method'
    
       def setAttr(self, attr):
          Parent.parentAttr = attr
    
       def getAttr(self):
          print "Parent attribute :", Parent.parentAttr
    
    class Child(Parent): # define child class
       def __init__(self):
          print "Calling child constructor"
    
       def childMethod(self):
          print 'Calling child method'
    
    c = Child()          # 实例化子类
    c.childMethod()      # 调用子类的方法
    c.parentMethod()     # 调用父类方法
    c.setAttr(200)       # 再次调用父类的方法
    c.getAttr()          # 再次调用父类的方法
    

    以上代码执行结果如下:

    Calling child constructor
    Calling child method
    Calling parent method
    Parent attribute : 200
    

    你可以继承多个类

    class A:        # define your class A
    .....
    
    class B:         # define your calss B
    .....
    
    class C(A, B):   # subclass of A and B
    .....
    

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

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

    重载方法

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

    实例:

    #!/usr/bin/python
    
    class Parent:        # 定义父类
       def myMethod(self):
          print 'Calling parent method'
    
    class Child(Parent): # 定义子类
       def myMethod(self):
          print 'Calling child method'
    
    c = Child()          # 子类实例
    c.myMethod()         # 子类调用重载方法
    

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

    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同样支持运算符重载,实例如下:

    #!/usr/bin/python
    
    class Vector:
       def __init__(self, a, b):
          self.a = a
          self.b = b
    
       def __str__(self):
          return 'Vector (%d, %d)' % (self.a, self.b)
       
       def __add__(self,other):
          return Vector(self.a + other.a, self.b + other.b)
    
    v1 = Vector(2,10)
    v2 = Vector(5,-2)
    print v1 + v2
    

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

    Vector(7,8)
    

    隐藏数据

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

    #!/usr/bin/python
    
    class JustCounter:
       __secretCount = 0
      
       def count(self):
          self.__secretCount += 1
          print self.__secretCount
    
    counter = JustCounter()
    counter.count()
    counter.count()
    print counter.__secretCount
    

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

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

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

    .........................
    print counter._JustCounter__secretCount
    

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

    1
    2
    2
    

    二,多线程

    Python线程

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

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

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

    参数说明:

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

    实例:

    #!/usr/bin/python
    
    import thread
    import time
    
    # 为线程定义一个函数
    def print_time( threadName, delay):
       count = 0
       while count < 5:
          time.sleep(delay)
          count += 1
          print "%s: %s" % ( threadName, time.ctime(time.time()) )
    
    # 创建两个线程
    try:
       thread.start_new_thread( print_time, ("Thread-1", 2, ) )
       thread.start_new_thread( print_time, ("Thread-2", 4, ) )
    except:
       print "Error: unable to start thread"
    
    while 1:
       pass
    

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

    Thread-1: Thu Jan 22 15:42:17 2009
    Thread-1: Thu Jan 22 15:42:19 2009
    Thread-2: Thu Jan 22 15:42:19 2009
    Thread-1: Thu Jan 22 15:42:21 2009
    Thread-2: Thu Jan 22 15:42:23 2009
    Thread-1: Thu Jan 22 15:42:23 2009
    Thread-1: Thu Jan 22 15:42:25 2009
    Thread-2: Thu Jan 22 15:42:27 2009
    Thread-2: Thu Jan 22 15:42:31 2009
    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方法:

    #!/usr/bin/python
    
    import threading
    import time
    
    exitFlag = 0
    
    class myThread (threading.Thread):   #继承父类threading.Thread
        def __init__(self, threadID, name, counter):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.counter = counter
        def run(self):                   #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数 
            print "Starting " + self.name
            print_time(self.name, self.counter, 5)
            print "Exiting " + self.name
    
    def print_time(threadName, delay, counter):
        while counter:
            if exitFlag:
                thread.exit()
            time.sleep(delay)
            print "%s: %s" % (threadName, time.ctime(time.time()))
            counter -= 1
    
    # 创建新线程
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)
    
    # 开启线程
    thread1.start()
    thread2.start()
    
    print "Exiting Main Thread"
    

    以上程序执行结果如下;

    Starting Thread-1
    Starting Thread-2
    Exiting Main Thread
    Thread-1: Thu Mar 21 09:10:03 2013
    Thread-1: Thu Mar 21 09:10:04 2013
    Thread-2: Thu Mar 21 09:10:04 2013
    Thread-1: Thu Mar 21 09:10:05 2013
    Thread-1: Thu Mar 21 09:10:06 2013
    Thread-2: Thu Mar 21 09:10:06 2013
    Thread-1: Thu Mar 21 09:10:07 2013
    Exiting Thread-1
    Thread-2: Thu Mar 21 09:10:08 2013
    Thread-2: Thu Mar 21 09:10:10 2013
    Thread-2: Thu Mar 21 09:10:12 2013
    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的尴尬场面。

    实例:

    #!/usr/bin/python
    
    import threading
    import time
    
    class myThread (threading.Thread):
        def __init__(self, threadID, name, counter):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.counter = counter
        def run(self):
            print "Starting " + self.name
           # 获得锁,成功获得锁定后返回True
           # 可选的timeout参数不填时将一直阻塞直到获得锁定
           # 否则超时后将返回False
            threadLock.acquire()
            print_time(self.name, self.counter, 3)
            # 释放锁
            threadLock.release()
    
    def print_time(threadName, delay, counter):
        while counter:
            time.sleep(delay)
            print "%s: %s" % (threadName, time.ctime(time.time()))
            counter -= 1
    
    threadLock = threading.Lock()
    threads = []
    
    # 创建新线程
    thread1 = myThread(1, "Thread-1", 1)
    thread2 = myThread(2, "Thread-2", 2)
    
    # 开启新线程
    thread1.start()
    thread2.start()
    
    # 添加线程到线程列表
    threads.append(thread1)
    threads.append(thread2)
    
    # 等待所有线程完成
    for t in threads:
        t.join()
    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() 实际上意味着等到队列为空,再执行别的操作

    实例:

    #!/usr/bin/python
    
    import Queue
    import threading
    import time
    
    exitFlag = 0
    
    class myThread (threading.Thread):
        def __init__(self, threadID, name, q):
            threading.Thread.__init__(self)
            self.threadID = threadID
            self.name = name
            self.q = q
        def run(self):
            print "Starting " + self.name
            process_data(self.name, self.q)
            print "Exiting " + self.name
    
    def process_data(threadName, q):
        while not exitFlag:
            queueLock.acquire()
            if not workQueue.empty():
                data = q.get()
                queueLock.release()
                print "%s processing %s" % (threadName, data)
            else:
                queueLock.release()
            time.sleep(1)
    
    threadList = ["Thread-1", "Thread-2", "Thread-3"]
    nameList = ["One", "Two", "Three", "Four", "Five"]
    queueLock = threading.Lock()
    workQueue = Queue.Queue(10)
    threads = []
    threadID = 1
    
    # 创建新线程
    for tName in threadList:
        thread = myThread(threadID, tName, workQueue)
        thread.start()
        threads.append(thread)
        threadID += 1
    
    # 填充队列
    queueLock.acquire()
    for word in nameList:
        workQueue.put(word)
    queueLock.release()
    
    # 等待队列清空
    while not workQueue.empty():
        pass
    
    # 通知线程是时候退出
    exitFlag = 1
    
    # 等待所有线程完成
    for t in threads:
        t.join()
    print "Exiting Main Thread"
    

    以上程序执行结果:

    Starting Thread-1
    Starting Thread-2
    Starting Thread-3
    Thread-1 processing One
    Thread-2 processing Two
    Thread-3 processing Three
    Thread-1 processing Four
    Thread-2 processing Five
    Exiting Thread-3
    Exiting Thread-1
    Exiting Thread-2
    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内容如下:

    <collection shelf="New Arrivals">
    <movie title="Enemy Behind">
       <type>War, Thriller</type>
       <format>DVD</format>
       <year>2003</year>
       <rating>PG</rating>
       <stars>10</stars>
       <description>Talk about a US-Japan war</description>
    </movie>
    <movie title="Transformers">
       <type>Anime, Science Fiction</type>
       <format>DVD</format>
       <year>1989</year>
       <rating>R</rating>
       <stars>8</stars>
       <description>A schientific fiction</description>
    </movie>
       <movie title="Trigun">
       <type>Anime, Action</type>
       <format>DVD</format>
       <episodes>4</episodes>
       <rating>PG</rating>
       <stars>10</stars>
       <description>Vash the Stampede!</description>
    </movie>
    <movie title="Ishtar">
       <type>Comedy</type>
       <format>VHS</format>
       <rating>PG</rating>
       <stars>2</stars>
       <description>Viewable boredom</description>
    </movie>
    </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方法

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

    xml.sax.make_parser( [parser_list] )
    

    参数说明:

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

    parser方法

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

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

    参数说明:

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

    parseString方法

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

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

    参数说明:

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

    Python 解析XML实例

    #!/usr/bin/python
    
    import xml.sax
    
    class MovieHandler( xml.sax.ContentHandler ):
       def __init__(self):
          self.CurrentData = ""
          self.type = ""
          self.format = ""
          self.year = ""
          self.rating = ""
          self.stars = ""
          self.description = ""
    
       # 元素开始事件处理
       def startElement(self, tag, attributes):
          self.CurrentData = tag
          if tag == "movie":
             print "*****Movie*****"
             title = attributes["title"]
             print "Title:", title
    
       # 元素结束事件处理
       def endElement(self, tag):
          if self.CurrentData == "type":
             print "Type:", self.type
          elif self.CurrentData == "format":
             print "Format:", self.format
          elif self.CurrentData == "year":
             print "Year:", self.year
          elif self.CurrentData == "rating":
             print "Rating:", self.rating
          elif self.CurrentData == "stars":
             print "Stars:", self.stars
          elif self.CurrentData == "description":
             print "Description:", self.description
          self.CurrentData = ""
    
       # 内容事件处理
       def characters(self, content):
          if self.CurrentData == "type":
             self.type = content
          elif self.CurrentData == "format":
             self.format = content
          elif self.CurrentData == "year":
             self.year = content
          elif self.CurrentData == "rating":
             self.rating = content
          elif self.CurrentData == "stars":
             self.stars = content
          elif self.CurrentData == "description":
             self.description = content
      
    if ( __name__ == "__main__"):
       
       # 创建一个 XMLReader
       parser = xml.sax.make_parser()
       # turn off namepsaces
       parser.setFeature(xml.sax.handler.feature_namespaces, 0)
    
       # 重写 ContextHandler
       Handler = MovieHandler()
       parser.setContentHandler( Handler )
       
       parser.parse("movies.xml")
    

    以上代码执行结果如下:

    *****Movie*****
    Title: Enemy Behind
    Type: War, Thriller
    Format: DVD
    Year: 2003
    Rating: PG
    Stars: 10
    Description: Talk about a US-Japan war
    *****Movie*****
    Title: Transformers
    Type: Anime, Science Fiction
    Format: DVD
    Year: 1989
    Rating: R
    Stars: 8
    Description: A schientific fiction
    *****Movie*****
    Title: Trigun
    Type: Anime, Action
    Format: DVD
    Rating: PG
    Stars: 10
    Description: Vash the Stampede!
    *****Movie*****
    Title: Ishtar
    Type: Comedy
    Format: VHS
    Rating: PG
    Stars: 2
    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文件,实例如下:

    #!/usr/bin/python
    
    from xml.dom.minidom import parse
    import xml.dom.minidom
    
    # 使用minidom解析器打开 XML 文档
    DOMTree = xml.dom.minidom.parse("movies.xml")
    collection = DOMTree.documentElement
    if collection.hasAttribute("shelf"):
       print "Root element : %s" % collection.getAttribute("shelf")
    
    # 在集合中获取所有电影
    movies = collection.getElementsByTagName("movie")
    
    # 打印每部电影的详细信息
    for movie in movies:
       print "*****Movie*****"
       if movie.hasAttribute("title"):
          print "Title: %s" % movie.getAttribute("title")
    
       type = movie.getElementsByTagName('type')[0]
       print "Type: %s" % type.childNodes[0].data
       format = movie.getElementsByTagName('format')[0]
       print "Format: %s" % format.childNodes[0].data
       rating = movie.getElementsByTagName('rating')[0]
       print "Rating: %s" % rating.childNodes[0].data
       description = movie.getElementsByTagName('description')[0]
       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



  • 相关阅读:
    shell截取字符串的方法
    安装sql server managerment studio报错"The instance id is required but it is missing"
    windows 80端口被占用的解决方法
    centos如何安装软件
    ORA-00257归档日志写满的解决方法
    VCenter克隆虚拟机报错msg.snapshot.error-QUIESCINGERROR
    如何启动或关闭oracle的归档(ARCHIVELOG)模式
    ubuntu下nagios配置
    vsphere vcenter server下安装ubuntu的vmwaretools
    virtualbox迁移至vcenter/vmware workstation
  • 原文地址:https://www.cnblogs.com/bill-technology/p/4130831.html
Copyright © 2020-2023  润新知