为了账号安全,请及时绑定邮箱和手机立即绑定

如何构造从一个 BaseClass 继承的类的方法?

如何构造从一个 BaseClass 继承的类的方法?

肥皂起泡泡 2022-06-07 17:13:24
我有很多从一个基类继承的不同子类。然而,所有不同的子类都实现了非常相似的方法。因此,如果我想更改子类中的代码,我必须多次更改。对我来说,这听起来像是不好的做法,我想正确地实施它。但是经过大量的谷歌搜索后,我仍然没有找到一种连贯的方式来说明如何做到这一点。这是我的意思的一个例子:from ABC import ABC, abstractmethodimport logging.configclass BaseModel(ABC):    def __init__(self):        # initialize logging        logging.config.fileConfig(os.path.join(os.getcwd(),            '../myconfig.ini'))        self.logger = logging.getLogger(__name__)    @abstractmethod    def prepare_data(self):        """        Prepares the needed data.        """        self.logger.info('Data preparation started.\n')        pass所以这是我的BaseClass。现在从这个类中,多个其他类继承了init和 prepare_data 方法。每个类的 prepare_data 方法都非常相似。class Class_One(BaseModel):    def __init__(self):        super.__init()__    def prepare_data(self):        super().prepare_data()        # Some code that this method doesclass Class_Two(BaseModel):    def __init__(self):        super.__init()__    def prepare_data(self):        super().prepare_data()        # Some code that this method does        # Code is almost the same as for Class_Oneclass Class_Three(BaseModel):    def __init__(self):        super.__init()__    def prepare_data(self):        super().prepare_data()        # Some code that this method does        # Code is almost the same as for Class_One and Class_Two# etc.我想您可以将这些方法重构到另一个文件中,然后在每个类中调用它们。我很想知道如何正确地做到这一点。提前非常感谢!
查看完整描述

1 回答

?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

恐怕没有通用的万能的神奇答案——这完全取决于“几乎”部分以及推动代码中这些部分发生变化的力量。IOW,只能用一个具体的例子来回答......


话虽如此,从经验中吸取了一些教训,这些教训主要在著名的(但不幸的是经常被误解的)GOF“设计模式”一书中进行了总结。如果您花时间先阅读本书的第一部分,您就会明白目录中的大多数(如果不是全部)模式都基于相同的原则:将变体与不变体分开。一旦你可以在你的代码中区分一个和另一个(警告:这里有一个陷阱,初学者几乎总是陷入其中),应用哪种模式通常是显而易见的(有时你才意识到你在你之后使用了这个和那个模式重构了你的代码)。


现在正如我所说,有一个陷阱:意外重复。仅仅因为两段代码看起来相似并不意味着它们是重复的——很多时候,它们现在只是“意外地”相似但会造成其中一种改变的力量大多是不相关的。如果您尝试立即重构此代码,您很快就会发现自己使“通用”案例变得越来越复杂,以支持实际上不相关的更改,最终导致过于复杂、难以理解的混乱,只会使您的代码无法维护。所以这里的诀窍是仔细检查整个上下文,问问自己什么会推动一个或其他“相似”部分发生变化,如果有疑问,等到你知道更多。如果它发生比每次更改 A 时都必须出于完全相同的原因在 B 中进行完全相同的更改,那么您确实有真正的重复。


对于基于我们可以从您过于抽象的示例(和经验)中猜测的更实用的短期建议,至少有两种模式最常涉及在类层次结构中排除重复:模板方法和策略。


注意:我说“不幸的是经常被误解”,因为大多数人似乎跳到模式目录并试图强制将它们全部放入他们的代码中(无论它是否对手头的问题有意义),并且通常通过复制粘贴规范教科书_实现_(通常基于Java或C++)而不是理解_概念_并以既惯用又适应具体用例的方式实现它(例如:当函数是第一类对象时,你不一定需要一个Strategie类抽象基类和具体子类 - 最常见的是普通的旧回调函数 JustWork(tm))。


编辑完全不相关,但这个:


    def __init__(self):

        # initialize logging

        logging.config.fileConfig(os.path.join(os.getcwd(),

            '../myconfig.ini'))

        self.logger = logging.getLogger(__name__)

不是如何使用日志记录。库代码可以使用记录器,但不能配置任何东西 - 这是应用程序(您的主脚本/函数/其他)的责任,合理的原因是正确的日志记录配置取决于上下文 - 哪种类型的应用程序正在使用库(a CLI 应用程序、本地 GUI 应用程序和后端 Web 应用程序根本没有相同的需求)以及在哪种环境中(例如,本地开发环境需要比生产环境更多的日志)。


此外,使用__name__在您的基类模块中创建的记录器,所有子类都会将它们的日志发送到同一个记录器,这当然不是您想要的(您希望它们拥有自己的包/模块特定的记录器,以便您可以微调每个包/模块的配置)。


最后,这个:


os.path.join(os.getcwd(),          '../myconfig.ini')

当然不会像您期望的那样工作-此时您的 cwd 可以是任何东西,而您无法提前知道。如果要引用相对于当前文件目录的路径,则需要os.path.dirname(os.path.realpath(__file__)). 当然,在os.path.join()调用中添加系统特定的路径内容(即“../”)完全破坏了使用os.path.


查看完整回答
反对 回复 2022-06-07
  • 1 回答
  • 0 关注
  • 96 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号