【问题标题】:Dynamically choosing class to inherit from动态选择要继承的类
【发布时间】:2013-07-10 02:34:03
【问题描述】:

我的Python知识有限,以下情况需要一些帮助。

假设我有两个类 AB,是否可以在 Python 中(从概念上)执行以下操作:

import os
if os.name == 'nt':
    class newClass(A):
       # class body
else:
   class newClass(B):
       # class body

所以问题是我想创建一个类newClass,这样它将根据平台差异从不同的基类继承,这可以在 Python 中实现吗? 谢谢。

【问题讨论】:

    标签: python class inheritance


    【解决方案1】:

    您可以使用conditional expression

    class newClass(A if os.name == 'nt' else B):
        ...
    

    【讨论】:

    • 非常感谢您的回复!
    • @taocp 没问题,很高兴我能帮上忙。
    • 这是一个更优雅的解决方案,因为它不需要重复类主体,但原帖中建议的逻辑也可以。
    • 虽然如果你真的能够做到,如果你有条件地在另一个模块中使用单个变量名创建 A 或 B,然后导入你分配给 A 或 B 的名称,那么很有可能会更好地抽象到其他任何地方。
    【解决方案2】:

    是的,你完全可以按照你写的去做。虽然就个人而言,我可能会这样做是为了清洁:

    class _newClassNT(A):
        # class body
    
    class _newClassOther(B):
        # class body
    
    newClass = _newClassNT if os.name == 'nt' else _newClassOther
    

    这假设您需要在类主体中实际执行不同的操作。如果您需要更改继承,则可以在此处嵌入 if 语句:

    class newClass(A if os.name == 'nt' else B):
        # class body
    

    【讨论】:

    • 非常感谢您的帮助!
    • 为什么要这样做而不是根据条件将 A 或 B 分配给 BaseCls 然后 class newClass(BaseCls)
    【解决方案3】:

    来自 Java 和 C# 的世界,做这样的事情的想法让我畏缩 =P。 (并不是说有条件地继承一个类的想法不好——我只是不习惯而已。)

    考虑一下,如果这个问题是关于 Java 的,我会做这样的事情。我正在发布模式 - 实现一个接口,然后使用工厂在实现之间进行选择 - 以便为问题提供另一个视角:

    public interface OsDependent {
      public void doOsDependentStuff();
    }
    
    public class WindowsDependentComponent implements OsDependent {
      @Override
      public void doOsDependentStuff() {
        //snip
      }
    }
    
    public class AppleDependentComponent implements OsDependent {
      @Override
      public void doOsDependentStuff() {
        //snip
      }
    }
    
    public class OsDependentComponentFactory {
      public OsDependent getOsDependentComponent(Platform platform) {
        if(platform == Platform.WINDOWS)
          return new WindowsDependentComponent();
        else if(platform == Platform.APPLE)
          return new AppleDependentComponent();
        else
          return null;
      }
    }
    

    肯定有更多代码,但它是强类型环境中的合适解决方案。


    编辑:我注意到我的答案和原始问题之间的一个显着差异:

    如果您有条件地从多个不同的类继承,那么超类包含的代码取决于您使用的操作系统,而从它们继承的类包含的代码对于所有操作系统都是相同的。继承链的顶部是依赖于操作系统的;底部不是。

    我的方法是相反的。 OsDepndent 接口(或超类)为所有平台定义了相似的方法,而不同的实现(或子类)具有依赖于操作系统的代码。继承链的顶端与操作系统无关。

    【讨论】:

    • 我肯定更喜欢这个(转换为 python)或 Henry Keiter 的解决方案。尽管 arshajii 的版本既好又简单,但它只能处理两种不同的操作系统类型,因此它不是“未来安全的”,正如 Robert C. Martin 在他的精彩著作(清洁代码)中指出的那样,最好是安全而不是抱歉。 Python 运行在太多不同的平台上,无法忽视这一事实……
    【解决方案4】:

    当您有两个以上的选项可供选择时,我找到了自己的动态继承类的方法。我相信其他人在我之前用过这个,但是我在网上找不到类似的东西,所以我想我应该和你分享。

    class A():
        # Class A Body
    class B():
        # Class B Body
    class C():
        # Class C Body
    class D():
        # Class D Body
    def MakeObject(InheritedClassName): # InheritedClassName is a string
        def CheckClass(InheritedClass):
            if InheritedClass == "A":
                return A
            elif InheritedClass == "B":
                return B
            elif InheritedClass == "C":
                return C
            else:
                return D
        class WantedClass(CheckClass(InheritedClassName)):
            # WantedClass Body
        YourObject = WantedClass()
        return YourObject
    CreateObject = MakeObject(str(input("Chose A, B, C or D")))
    

    这个代码可以修改,你可以用它来做很多事情。这是我最喜欢的设置动态类继承的方式,尽管它有点长,因为您可以拥有任意数量的选项,甚至可以为每个对象动态选择多个继承。

    【讨论】:

      【解决方案5】:

      适用于在使用不同模块时有相似需求的人。 首先,创建一个文件switcher.py 并在其中放入以下内容

      class Switcher():
          def choose(clname):
               Switcher.clname = clname
      

      接下来,在你的newClass.py

      import switcher
      
      class newClass(switcher.Switcher.clname):
          ...
      

      终于在你的主脚本中

      import switcher
      import os
          if os.name == 'nt':
              switcher.Switcher.choose(A):
          else:
              switcher.Switcher.choose(B):
      
      # that's the moment you're creating class with desired inheritance
      import newClass.newClass
      

      【讨论】:

        猜你喜欢
        • 2021-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多