2

嘿伙计们,我是新来的,但希望我的问题很清楚。

我的代码是用 Python 编写的。我有一个代表一般网站的基类,这个类包含一些从网站获取数据并保存的基本方法。该类由许多其他类扩展,每个类都代表一个不同的网站,每个类都具有特定于该网站的属性,每个子类都使用基类方法来获取数据。所有站点都应在其上解析数据,但许多站点共享相同的解析功能。所以我创建了几个解析类,它们包含不同解析方法的功能和属性(我大约有六个)。我开始思考将这些类与需要它们的网站类集成的最佳方式是什么。

起初我认为每个网站类都会保存一个类变量,其中包含与之对应的解析器类,但后来我认为必须有更好的方法来做到这一点。

我读了一点,并认为依靠 Mixins 为每个网站集成解析器可能会更好,但后来我认为虽然这会起作用,但它并不“听起来”正确,因为网站类没有从解析器类继承的业务(甚至认为它只是一个 Mixin,并不意味着是一个完整的类继承),因为除了网站使用解析器功能之外,它们没有任何关系。

然后我想我可能会依靠我看到的一些依赖注入代码来将解析器注入到每个网站,但这听起来有点矫枉过正。

所以我想我的问题基本上是,什么时候最好使用每种情况(在我的项目和任何其他项目中),因为它们都完成了这项工作,但似乎并不是最合适的。

感谢您提供的任何帮助,我希望我很清楚。

添加一个小模拟示例来说明:

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
    ....

等等

4

1 回答 1

1

我认为您的问题是您在应该使用实例的地方使用子类。

根据您的描述,每个网站都有一个类,具有一堆属性。大概您创建每个类的单例实例。在 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)]
于 2013-08-23T01:58:09.547 回答