大家好,我是新来的,但希望我的问题很清楚。
我的代码是用 Python 编写的。 我有一个代表一般网站的基类,这个类包含一些从网站获取数据并保存的基本方法。该类由许多其他类扩展,每个类代表一个不同的网站,每个网站都持有特定于该网站的属性,每个子类使用基类方法来获取数据。所有网站都应该在其上解析数据,但许多网站共享相同的解析功能。所以我创建了几个解析类来保存不同解析方法的功能和属性(我有大约六个)。我开始思考将这些类与需要它们的网站类集成的最佳方式是什么。
起初我以为每个网站类都会保存一个类变量和与之对应的解析器类,但后来我认为一定有更好的方法来做到这一点。
我读了一点,认为我可能最好依靠 Mixins 来为每个网站集成解析器,但后来我认为虽然这可行,但它“听起来”不对,因为网站类没有继承自的业务解析器类(甚至认为它只是一个 Mixin,并不意味着是一个完整的类继承),因为除了网站使用解析器功能之外,它们没有任何关系。
然后我想我可能会依赖一些我看到的 python 依赖注入(inject)代码来将解析器注入(inject)每个网站,但这听起来有点矫枉过正。
所以我想我的问题基本上是,什么时候最好使用每种情况(在我的项目和任何其他项目中),因为它们都可以完成工作,但似乎不是最合适的。
感谢您提供的任何帮助,我希望我说的很清楚。
添加一个小的模拟示例来说明:
class BaseWebsite():
def fetch(): # Shared by all subclasses websites
....
def save(): # Shared by all subclasses websites
....
class FirstWebsite(BaseWebsite): # Uses parsing method one
....
class SecondWebsite(BaseWebsite): # Uses parsing method one
....
class ThirdWebsite(BaseWebsite): # Uses parsing method two
....
等等
请您参考如下方法:
我认为你的问题是你在应该使用实例的地方使用了子类。
根据您的描述,每个网站都有一个类,具有一系列属性。假设您创建了每个类的单例实例。在 Python 中很少有充分的理由这样做。如果每个网站都需要不同的数据——基本 URL、解析器对象/工厂/函数等——您可以将其存储在实例属性中,这样每个网站都可以是同一类的实例。
如果网站实际上需要,比如说,以不同的方式覆盖基类方法,那么将它们作为不同的类是有意义的(尽管即使在那里,您也应该考虑是否将该功能移动到外部函数或对象中由网站使用,就像您已经使用解析器一样)。但如果不是,就没有充分的理由这样做。
当然我在这里可能是错的,但事实上你定义了旧式类,在你的方法中留下了 self 参数,谈论类属性,并且通常使用 Java 术语而不是Python 术语让我觉得这个错误不太可能。
换句话说,你想要的是:
class Website:
def __init__(self, parser, spam, eggs):
self.parser = parser
# ...
def fetch(self):
data = # ...
soup = self.parser(data)
# ...
first_website = Website(parser_one, urls[0], 23)
second_website = Website(parser_one, urls[1], 42)
third_website = Website(parser_two, urls[2], 69105)
假设您有 20 个网站。如果您要创建 20 个子类,您将为每个子类编写六行样板代码,并且您可能会在细节上出错很多,调试起来可能很痛苦。如果您要创建 20 个实例,那么它只是几个样板字符,而且出错的可能性要小得多:
websites = [Website(parser_one, urls[0], 23),
Website(parser_two, urls[1], 42),
# ...
]
或者您甚至可以将数据移动到数据文件中。例如,像这样的 CSV:
url,parser,spam
http://example.com/foo,parser_one,23
http://example.com/bar,parser_two,42
…
您可以更轻松地编辑它——甚至可以使用电子表格程序来完成——无需任何额外的输入。您可以使用几行代码将其导入 Python:
with open('websites.csv') as f:
websites = [Website(**row) for row in csv.DictReader(f)]
