更新时间:2023-01-11 10:05:41
这真的不是 ABC 的问题,而是 PyMongo 的问题.此处存在一个问题.pymongo 似乎覆盖了 __getattr__
以返回某种数据库类.这意味着 host.__isabstractmethod__
返回一个 Database 对象,这在布尔上下文中为真.这导致 ABCMeta 认为 host
是一个抽象方法:
问题报告中描述的解决方法是在您的对象上手动设置 host.__isabstractmethod__ = False
.关于该问题的最后一条评论表明已针对 pymongo 3.0 进行了修复.
I created the empty abstract class AbstractStorage
and inherited the Storage
class from it:
import abc
import pymongo as mongo
host = mongo.MongoClient()
print(host.alive()) # True
class AbstractStorage(metaclass=abc.ABCMeta):
pass
class Storage(AbstractStorage):
dbh = host
def __init__(self):
print('__init__')
Storage()
I expected the output to be
True
__init__
however, the one I'm getting is
True
Traceback (most recent call last):
File "/home/vaultah/run.py", line 16, in <module>
Storage()
TypeError: Can't instantiate abstract class Storage with abstract methods dbh
The problem (apparently) goes away if I remove metaclass=abc.ABCMeta
(so that AbstractStorage
becomes an ordinary class) and/or if I set dbh
to some other value.
What's going on here?
This isn't really a problem with ABCs, it's a problem with PyMongo. There is an issue about it here. It seems that pymongo overrides __getattr__
to return some sort of database class. This means that host.__isabstractmethod__
returns a Database object, which is true in a boolean context. This cause ABCMeta to believe that host
is an abstract method:
>>> bool(host.__isabstractmethod__)
True
The workaround described in the issue report is to manually set host.__isabstractmethod__ = False
on your object. The last comment on the issue suggests a fix has been put in for pymongo 3.0.