• 用于可扩展、可重用和优雅的代码的Python工厂


    用于可扩展、可重用和优雅的代码的Python工厂

    通过将行为(在工厂超类中定义)与对象创建(在子类中)解耦,创建灵活、可扩展的代码。

    在现实生活中的工厂中,相同或相似对象的生产不是单独完成的,而是在流水线上精简的。同样地,工厂设计模式允许你创建的软件不与特定的产品相联系,而是可以在许多类似的应用中重复使用。工厂模式是著名的Gof(四人帮)设计模式之一[1]。它是一种创造型的设计模式,它将对象的创建封装在一个叫做工厂的类中。这种模式通过与系统解耦来促进系统的灵活性,即如何、何时以及由谁来创建其对象[6]。

    当你需要创建新类型的对象时,工厂就特别有用。如果对象的创建分散在整个代码中,那么你将不得不花时间去寻找代码中对象类型的确切位置[2]。在软件工程方面,这意味着你有大量的技术债务需要处理。这在机器学习中尤其如此,正如[4]中所解释的那样。机器学习会产生巨大的维护成本,这源于数据依赖、数据漂移和隐藏的反馈回路。最近,通过创建特征商店[3][5],工厂已经在机器学习中找到了自己的方式。特征库可以是在线的,也可以是离线的,其主要目的是抽象数据转换,因为它们适用于不同的特征,并通过这种方式实现更快的开发,更好的协作,有效的模型部署和扩展[7]。

    1.0 在Python中实现工厂的一个例子

    现在让我们来看一个如何在Python中使用工厂的具体例子。假设我们想为一个刚从大学毕业的儿子创建一个新的衣柜,他在一家银行找到了第一份工作,是一个定量金融分析师。鉴于他精通Python,他决定实现一个虚拟衣柜的索引。我们将帮助他为每件衣服分配一个 "正式等级",因为他完全有能力穿着T恤和破洞牛仔裤出现在一个重要的会议上。

    如下图所示,虚拟衣橱索引从创建两个抽象工厂开始, 一个是鞋类(FootWear) 一个是衣服(MensClothes)

    这些都是抽象类,它们只起到模板的作用。与 Java 不同,Python 没有一个固有的抽象类类型。相反,它提供了一个叫做 abc 的模块,它提供了抽象类的基础结构。

    MensClothes 类的 colortcolorb 变量分别代表上衣 (衬衫、毛衣等) 和下衣 (裤子) 的颜色。注意,我们给鞋子和上下装的颜色分配了一个默认值 "棕色"(安全的颜色)。

    import ast
    from abc import ABC

    class FootWear(ABC):
        def shoespecs(self, c="Brown"):
            self.color = c


    class MensClothes(ABC):
        def __init__(self, rt="Brown", rb="Brown"):
            self.colort = rt
            self.colorb = rb

        def clothespecs(self, foot_w):
            pass
    • 1

    现在让我们通过定义具体的类BootsLoafers来实现两种类型的鞋类。我们继承自FootWear类,然后覆盖其shoespecs()方法来实现每个具体类的具体动作。

    class Boots(FootWear):
        def __init__(self):
            print("Wear boots on a cold day")

        def shoespecs(self, c="Brown"):
            print(f"You picked {c} boots")


    class Loafers(FootWear):
        def __init__(self):
            print("Shoes for a nice day")

        def shoespecs(self, c="Brown"):
            print(f"You picked {c} loafers")
    • 1

    同样地,我们创建了两个继承自MensClothes的具体类:SweaterAndCurdoroyPants,和ButtonDownShirtAndDressPants

    每个具体的类都重写了抽象类的方法 clothespecs(),以便为每个样式指定特定的内容。请注意,clothespecs()方法接受一个FootWear对象,以使鞋类的颜色与裤子的颜色相匹配。

    class SweaterAndCorduroyPants(MensClothes):
        def __init__(self, rt="Brown", rb="Brown"):
            super().__init__(rt, rb)
            print(f"You picked the {rt} sweater and the {rb} corduroy pants")

        def clothespecs(self, foot_w):
            foot_w.shoespecs(c=self.colorb)


    class ButtonDownShirtAndDressPants(MensClothes):
        def __init__(self, rt="Brown", rb="Brown"):
            super().__init__(rt, rb)
            print(f"You picked the {rt} button-down shirt and the {rb} dress pants ")

        def clothespecs(self, foot_w):
            foot_w.shoespecs(c=self.colorb)
    • 1

    下面的抽象类Outfit是一个工厂,它提供了选择衣服和鞋子的方法,分别是choose_clothes()choose_shoes(),并且有一个实例属性,formality

    class Outfit(ABC):
        def __init__self(self):
            self.formality=0
            pass

        def choose_clothes(self):
            pass

        def choose_shoes(self):
            pass
    • 1

    下面的具体类LightColor_ColdAndCasualDay继承自抽象类Outfit,有以下方法。

    (a) 一个构造函数,指定了形式和名称变量。形式变量是从Outfit继承的。

    (b) Outfit类的choice_clothes()方法的重载形式,它返回一个SweaterAndCorduroyPants对象。

    (c) Outfitchoice_shoes()方法的重载形式,该方法返回一个Boots对象。

    正如我们所看到的,当我们向上移动类的层次时,事情变得更加具体,而较低级别的类,如FootWearMensClothesOutfit,对于创建什么子类、在哪里创建它们的对象以及它们如何被聚合都是不可知的。

    下面的DarkColor_WarmSemiFormalDay类也定义了一种类似的结构,它定义了一些方法来返回衣服的ButtonDownShirtAndDressPants对象和鞋类的Loafers对象。

    class LightColor_ColdAndCasualDay(Outfit):
        def __init__(self):
            self.formality = 1
            self.name = "Light Colored Outfit for a Cold and Casual Day"

        def choose_clothes(self):
            return SweaterAndCorduroyPants(rt="Cream-colored", rb="Light Brown")

        def choose_shoes(self):
            return Boots()


    class DarkColor_WarmSemiFormalDay(Outfit):
        def __init__(self):
            self.formality = 2
            self.name = "Dark Colored Outfit for a Semi-Formal Day"

        def choose_clothes(self):
            return ButtonDownShirtAndDressPants(rt='burgundy',rb='black')

        def choose_shoes(self):
            return Loafers()
        
    • 1

    与到目前为止我们看到的抽象工厂相比,DarkColor_WarmSemiFormalDayLightColor_ColdAndCasualDay是具体的工厂。它们如何作为对象的工厂,在下面的Look类的定义中得到了说明。类Look是负责创建对象的协调类。

    正如我们在下面看到的,它的构造函数需要一个工厂作为参数。在我们有限的衣柜里,这个工厂可以是LightColor_ColdAndCasualDayDarkColor_WarmSemiFormalDay对象。

    当我们创建一个Look类的对象时,工厂的choose_clothes()choose_shoes()被调用,它们分别给实例变量closho赋值。

    然后,这些变量被用于重要的dress()方法,该方法将所有东西放在一起并创建完整的外观!这是一个可扩展、可重复使用的方法。这是可扩展的、可重复使用的代码,因为战略性地放置了对象创建的封装和多态性。

    class Look:
        def __init__(self, factory):
            self.factory = factory
            self.name = factory.name
            print(factory.name)
            self.clo = factory.choose_clothes()
            self.sho = factory.choose_shoes()
            self.formality = factory.formality

        def dress(self):
            self.clo.clothespecs(self.sho)

        def __eq__(self, m):
            return self.formality == m.formality

        def __gt__(self, m):
            return self.formality > m.formality
    • 1

    在下面的代码片段中,我们可以看到我们的对象创建和礼服()方法的调用。请注意,我们检查了两个对象是否相等或对象g2是否大于对象g1。

    g1 = Look(LightColor_ColdAndCasualDay())
    g1.dress()
    g2 = Look(DarkColor_WarmSemiFormalDay())
    g2.dress()
    print(g1 == g2)
    print(g2 > g1
    • 1

    在上面Look类的定义中,我们把__eq__运算符的输出定义为两个对象的形式性的平等比较的输出。正如我们所讨论的,我们的新晋金融分析师对形式上的风格一无所知,所以我们需要以一种特定的方式(形式上的等级)告诉他,哪些外观在形式上被认为是相等的。

    所以,3是最高的正式性(商务套装),0是没有正式性(T恤衫和运动鞋)。下面的等号操作返回假,大号操作返回真,因为g2的正式性等级(2)比g1(1)高。

    最后,在下面的代码片段中,我们导入了当前的虚拟衣橱,它以字典的形式存在于一个文本文件中,并将我们创建的两个新外观附加到它上面,Outfit对象的名称作为键,形式感作为值。

    with open('virtual_wardrobe.txt') as f:
        data = f.read()
    wardrobe = ast.literal_eval(data)
    print(wardrobe)

    wardrobe[g1.name] = g1.formality
    wardrobe[g2.name] = g2.formality
    print(wardrobe)

    with open('virtual_wardrobe.txt''w') as v_wardrobe:
        v_wardrobe.write(str(wardrobe))
    v_wardrobe.close()
    • 1

    你可以在我的github目录中看到整个代码,作为一个Jupiter笔记本:https://github.com/theomitsa/Python-factories

    谢谢您的阅读!

    参考文献

    Gamma, E., Helm, R., Johnson, and R., J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley Professional, Oct. 1994.

    Eckel, B. et al., Python 3 Patterns, Recipes, and Idioms, Read the Docs (ebook) Fly, A., Feature Store: 数据科学工厂的组成部分,中。迈向数据科学》,2019年9月。

    Sculley, D. et al., 机器学习。The High-Interest Credit Card of Technical Debt, Software Engineering for Machine Learning, NIPS Conference Workshop, 2014.

    Taifi, M., ML Feature Stores: 休闲之旅1/3, Medium, 2020年4月。 Bishop, J, C# 3.0 Design Patterns, O'Reilly Media, p. 336, 2007.

    Hirschtein, A., What Are Feature Stores And Why Are They Critical For Scaling Data Science? , Medium: 迈向数据科学》,2020年4月。

    本文由 mdnice 多平台发布

  • 相关阅读:
    C++核心编程——P36-友元
    【深度学习】Vision Transformer
    毕业4年,薪资25k,这一刻,我决定从字节离职了···
    ERP对接淘宝/天猫/京东/拼多多商品详情数据API接口
    【开源】SpringBoot框架开发民宿预定管理系统
    【Push Kit】关于推送消息没有锁屏通知的问题
    多维时序 | MATLAB实现GWO-LSTM灰狼算法优化长短期记忆神经网络的多变量时间序列预测
    【操作系统】线程&进程相关
    Apache-Doris单机部署
    Pytorch-基于RNN的不同语种人名生成模型
  • 原文地址:https://blog.csdn.net/qq_40523298/article/details/127459162