我正在尝试解析python中的一些html页面。当我到达某个标签时,我想开始打印所有数据。到目前为止,我想出了这个:
class MyHTMLParser(HTMLParser):
start = False;
counter = 0;
def handle_starttag(self,tag,attrs):
if(tag == 'TBODY'):
start = True;
counter +=1
#if counter == 1
def handle_data(self,data):
if (start == True): # this is the error line
print data
问题是有一个错误,说它不知道什么是开始。我知道我可以使用全局,但这不会强迫我在整个类之外定义变量吗?
编辑: 将start更改为self.start可以解决问题,但有没有办法在 init 中定义它而不会弄乱HTMLParser init?
答案 0 :(得分:2)
class MyHTMLParser(HTMLParser):
start = False;
counter = 0;
...
这不符合你的想法!
在Java,C#或类似语言中,类似代码所做的是声明被称为MyHTMLParser
的对象类都具有属性start
,其初始值为False
和counter
,初始值为0
。
在Python中,类也是对象。它们有自己的属性,就像其他所有对象一样。所以上面在Python中做的是创建一个名为MyHTMLParser
的类对象,其中属性start
设置为False
,属性counter
设置为0
。 1
要记住的另一件事是没有办法来分配像start = True
这样的裸名称在对象上设置属性。它总是设置一个名为start
。 2
因此,您的类不包含任何在MyHTMLParser
个实例上设置任何属性的代码;类主体中的代码是在类对象本身上设置属性,handle_starttag
中的代码设置局部变量,然后当它们超出范围时被丢弃。
handle_data
中的代码正在读取名为start
的局部变量(您从未设置过),原因类似。在Python中,如果没有指定要查找的对象,就无法读取属性。裸start
始终引用变量,在本地函数范围或某些外部范围内。您需要self.start
才能阅读start
对象的self
属性。
请记住,定义方法的def
块没有什么特别之处,它是一个像其他任何函数一样的函数。只有在该函数恰好存储在类对象的属性中时才能将该函数归类为方法。因此self
参数的行为与任何其他参数相同,实际上与任何其他名称相同。它不必被命名为self
(虽然这是一个明智的约定),并且它没有特殊权限,使得对裸名称的读取和写入寻找self
的属性。
所以:
不要在类块中使用初始值定义属性;这是由所有类的实例共享的值,而不是每个实例的属性。只有在引用特定实例后,才能初始化实例属性;最常见的是,这是在__init__
方法中完成的,只要对象存在就会调用该方法。
您必须指定要在哪个对象中读取或写入属性。这在每个上下文中应用始终。特别是,您通常会将方法中的属性称为self.attribute
。
应用它(并消除Python中不需要的分号):
class MyHTMLParser(HTMLParser):
def __init__(self):
start = False
counter = 0
def handle_starttag(self, tag, attrs):
if(tag == 'TBODY'):
self.start = True
self.counter += 1
def handle_data(self, data):
if (self.start == True):
print data
1 方法handle_starttag
和handle_data
也只不过是恰好是用作类的对象属性的函数。
2 通常是一个局部变量;如果您已将start
声明为global
或nonlocal
,那么它可能是外部变量。但它肯定不是你碰巧在附近的某个对象的属性,即使该另一个对象绑定到名称self
。
答案 1 :(得分:1)
使用self关键字
class MyHTMLParser(HTMLParser):
def __init__(self):
self.start = False;
self.counter = 0;
def handle_starttag(self,tag,attrs):
if(tag == 'TBODY'):
self.start = True;
self.counter +=1
#if counter == 1
def handle_data(self,data):
if (self.start == True): # this is the error line
print data
答案 2 :(得分:0)
注意,您不需要在每行的末尾添加分号;
。您可以将其用作分隔符,以便在必要时将多个语句放在同一行上。见Why is semicolon allowed in this python snippet?