给Python的NoneType增加方法
我正在使用BeautifulSoup进行网页爬虫,想要把多个查找操作连在一起,比如:
soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
当然,如果找不到某个div,这个链式调用就会出错,抛出一个
AttributeError: 'NoneType' object has no attribute 'find'
有没有办法修改NoneType,让它也能有一个像这样的查找方法
class NoneType:
def find(*args):
return None
这样我就可以做类似这样的操作
thing = soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
if thing:
do more stuff
而不是
thing1 = soup.find('div', class_="class1")
if thing1:
thing2 = thing1.find('div', class_="class2")
if thing2:
thing3 = thing2.find('div', class_="class3")
etc.
我觉得我可以通过使用支持XPath的解析器来实现类似的功能,但这个问题并不局限于这个用例,更是关于如何修改或重写内置类。
6 个回答
0
你不能从None继承:
>>> class Noneish(type(None)):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'NoneType' is not an acceptable base type
1
你不能修改这个类,真正的问题是你为什么会想要这么做?NoneType表示这里没有数据,所以当你在这种类型上尝试使用 .find() 方法时,即使它存在,你也只会得到空值或者没有任何值。我建议你可以试试下面的这个方法。
try:
var = soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
except AttributeError:
do something else instead or message saying there was no div
1
一种方法可能是先准备一个
class FindCaller(object):
def __init__(self, *a, **k):
self.a = a
self.k = k
def __call__(self, obj):
return obj.find(*self.a, **self.k)
def callchain(root, *fcs):
for fc in fcs:
root = fc(root)
if root is None: return
return root
然后再执行
thing = callchain(soup,
FindCaller('div', class_="class1"),
FindCaller('div', class_="class2"),
FindCaller('div', class_="class3"),
)
2
为什么不直接用try/except语句呢?因为你不能修改NoneType
的内容。
try:
thing = soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
do more stuff
except AttributeError:
thing = None # if you need to do more with thing
1
你不能修改像 NoneType
或 str
这样的内置类:
>>> nt = type(None)
>>> nt.bla = 23
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'NoneType'
对于其中一些类(比如 str
),你可以通过继承来扩展:
>>> class bla(str):
... def toto(self): return 1
>>> bla('2123').toto()
1
但是对于 NoneType
,这是不可能的。而且这样做也没有任何帮助:
>>> class myNoneType(nt):
... def find(self): return 1
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
type 'NoneType' is not an acceptable base type