[python]SGMLParser是如何工作的

本文深入探讨了一个简单的Python代码片段,通过解析SGMLParser的工作原理,特别是start_part方法与getattr函数的使用,揭示了代码中start_part运行多次的原因,并解释了getattr的作用和默认参数的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么去想这个问题

毫无疑问的,我是个懒得动脑的家伙,但是同时我也是个手贱的家伙。今天我写了以下代码

# -*- coding:utf-8 -*-

import urllib,re
from sgmllib import SGMLParser

class OLLister(SGMLParser):
    lists = []
    def start_part(self,attrs):
        attr = {}
        for k,v in attrs:
            attr[k]=v
        self.lists.append(attr)
        print self.lists  #1

filed = open('data.xml')
data = filed.read()

lister = OLLister()
lister.feed(data)
print self.lists  #2
这个代码很简单,从xml文件中取出以part为tag的属性及值存入列表,代码运行良好,唯一的遗憾是我在start_part里加了个print。我注意到1处的print运行了四次,每次都会多打印出一条属性,这意味着start_part运行了四次,分别处理了一条<part></part>。这个处理过程到底是怎么样的呢?我想要看看。

SGMLParser的重点

SGMLParser 查找每一个标记并且如果存在特定的方法就调用它们。如果有兴趣深入了解的话,请戳深入Python:Dive InTo Python第八章 来自啄木鸟社区

如果只是想了解SGMLParser的查找步骤的话,请看代码

def finish_starttag(self, tag, attrs):                   #1
        try:                                            
            method = getattr(self, 'start_' + tag)       #2
        except AttributeError:                           #3
            try:                                        
                method = getattr(self, 'do_' + tag)      #4
            except AttributeError:                      
                self.unknown_starttag(tag, attrs)        #5
                return -1                               
            else:                                       
                self.handle_starttag(tag, method, attrs) #6
                return 0                                
        else:                                           
            self.stack.append(tag)                      
            self.handle_starttag(tag, method, attrs)    
            return 1                                     #7

    def handle_starttag(self, tag, method, attrs):      
        method(attrs)                                    #8
函数finish_starttag,顾名思义是之SGMLParser已经找到了一个开始标签,这个时候,他已经分析出了属性列表[('name','value'),('name','value')],最关键的是,他要根据开始标签tag来寻找对应的函数进行动作,这关键一步取决于getattr方法的结果。getattr的作用是获取对象引用,详细的介绍同样来自 深入python

在这里getattr是为了查找是否有符合的start_tag方法,如果没有找到的话就会去找do_tag方法,如果连do_tag都没有找到的话,就只有unknown_starttag了。

在这一串动作中,最神奇的地方就在于getattr的分发作用,对于我这样的菜鸟来说,这种机制实在是太神奇了,我还是第一次明确意识到存在这样的方法。

什么是getattr

getattr Found at: __builtin__
getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.

在深入python第四章,译者提到一个名词叫做自省(这是第四章的章节名),而我又没能看见英文版的说法,所以我其实没有很懂自省的意思,但是结合4.4,尤其是上面那段来自于python2.7的doc,我对getattr有了些理解(getattr是自省中的一部分)。

首先作为一个函数,getattr有一个返回值,这个返回值可以是一个函数也可以是一个属性,也就是obj.name ,其次他的参数则是object,name,最后如果输入的'name'本身就不存在于object呢?

根据doc的解释,如果'name'不存在,会出现一个异常。

还是最初的例子,将

print self.lists  #2
替换成

print getattr(lister,'lists')  #2
是等价的,但是换成

print getattr(lister,'list')  #2
就报错了。

那么可选参数default的意义在哪里?请再使用下面的代码替换

print getattr(lister,'list',lister.lists)

default参数是一个缺省返回值,如果第二个参数指定的属性或者方法没能找到,则将返回这个缺省返回值。

ps 我下载到英文版了,关于自省,英文版的说法是introspection,第四章的章节名叫做The Power of Introspection 或者可以翻译成内省:组建可以发表其支持的操作和属性,同时也支持在其他组件中发现重复利用的对象库。当然,自省和内省这两个说法或者其实可以理解成是一样的。

写在后面的话

我在写完以后百度了一下Dive Into Python,发现了赖勇浩老师的《Dive Into Python》非死不可 及另一篇为什么《Dive into Python》不值得推荐

赖老师的技术水平及知识水平是毋庸置疑的,在这里我想他的意思是这本书不值得推荐给入门者也就是我这样的菜鸟做入门学习,而就我在http://woodpecker.org.cn/diveintopython/看见的介绍也是说这是为有经验的程序猿撰写的。

从我个人学习的经验来说,我确实认为这本书是有点难度的,而且里面的例子,就我看的几章就有些挺头疼的。不过我觉得在大致明白python简明教程后而本身又是一个程序猿的话,这本书可以作为一个深入了解python的参考。

ps 这本书的例子有一些已经过时了

pps 这本书的中文版下载是附带例子的http://woodpecker.org.cn/diveintopython/

ppps我本人是以python简明教程入门同时每天都写写爬虫或者wxpython程序,而且我深以赖勇浩老师的意见为然。请仅将此书作为参考书使用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值