【问题标题】:Python class methods to construct child classesPython类方法构造子类
【发布时间】:2022-01-02 08:42:34
【问题描述】:

我不知道如何在python中干净利落地重用派生类的classmethod来构造子类:

class Base:
     def __init__(... lots of parameters .... )
         ... assign parameters .... 
         
     @classmethod
     def from_file(cls,file)
         .... read lots of parameters ....
         return cls(.... lots of parameters .... )

class Derived(Base):
     def __init__(derived_param, .... base parameters ..... )
         super().__init__(base parameters)

     @classmethod
     def from_file(cls,file)
         ??? do i have to replicate the whole code from   
         Base.from_file() here ???? 

【问题讨论】:

    标签: python inheritance factory


    【解决方案1】:

    您不必在子类中重新定义方法。默认情况下,它使用父函数:

    class Base:
         def __init__(... lots of parameters .... )
             ... assign parameters .... 
             
         @classmethod
         def from_file(cls,file)
             .... read lots of parameters ....
             return cls(.... lots of parameters .... )
    
    class Derived(Base):
         def __init__(derived_param, .... base parameters ..... )
             super().__init__(base parameters)
    
    derived_class = Derived(...params...)
    derived_class.from_file(...params...)  # This line will work without any further changes
    

    【讨论】:

    • 非常感谢,但这可能只是答案的 50%。我需要的是 Derived 类的 from_file 类方法。在这个类中,我不能调用Base.from_file(),因为派生类还不存在。更糟糕的是,在某些时候我需要调用 cls(derived_pa​​ram, base param) 其中 cls == Derived 而我没有基本参数。解决方法似乎是在 Derived.from_file() 方法中实际调用 Base.from_file() 并传递参数。
    • 明白了。您可以为此使用super().from_file
    • 不是父类,而是实际调用类方法的任何类,无论哪个类定义该方法。 d = Derived.from_file(...) 将创建一个 Derived 的实例,即使该方法继承自 Base
    【解决方案2】:

    现在是花哨的答案:

    
    class Base:
        def __init__(self, **params):
            self.assign(params,['base_x','base_y'])
    
        def assign(self,params,required):
            for k in required:
                # will throw an exception if a required variable is not present
                self.__dict__[k] = params[k]
    
    
        @classmethod
        def from_file(cls):
            """ read from file here"""
            return cls(base_x='xval',base_y='yval')
    
    
    class Derived(Base):
        def __init__(self, **params):
            super().__init__(**params) # it does not hurt to have all the derived params in the dict
            self.assign(params,['derived_var']) # here we assign only the derived vars, note this has to be a list
    
        @classmethod
        def from_file(cls):
            base = Base.from_file()
            derived_dict = { 'derived_var' : 'derived value'}
            derived = cls( **(derived_dict | base.__dict__) )
            return derived
    
    
    if __name__ == '__main__':
        derived = Derived.from_file()
        print("Base: ", derived.base_x, derived.base_y," Derived: ", derived.derived_var)
    
    
    

    这样你只需要在每个子类中指定所需的属性,如果你错过了一个关键错误就会抛出一个关键错误。

    【讨论】:

      【解决方案3】:

      解决方法似乎是在 Derived.from_file() 方法中实际调用 Base.from_file() 并传递参数。

      class Base:
          def __init__(self,base_var):
              self.base_var = base_var
      
          @classmethod
          def from_file(cls):
              """ read from file here"""
              base_init = "base_init"
              return cls(base_var=base_init)
      
      
      class Derived(Base):
          def __init__(self,derived_var,base_var):
              super().__init__(base_var)
              self.derived_var = derived_var
      
          @classmethod
          def from_file(cls):
              derived_init = "derived_init"
              base = Base.from_file()
              derived = cls(derived_init,base.base_var)
      
              return derived
      

      【讨论】:

        【解决方案4】:

        类方法接收调用该方法的类作为第一个参数。

        如果你写

        d = Derived.from_file(3)
        

        然后调用的是在Base 中定义的from_file 函数,但使用Derived,而不是Base,作为第一个参数(绑定到cls)。结果,您将获得正确类的实例。

        但是,如果您需要使用文件执行 Derived 特定的事情,您仍然需要覆盖该方法并使用 super() 在您自己的 Derived 之前执行任何 Base 特定的事情-具体的事情。

        class Base:
             def __init__(*, x, y, z, **kwargs)
                 super().__init__(**kwargs)
                 # assign x, y, z
                 
             @classmethod
             def from_file(cls, file)
                 # Process file to get values for x, y, and z
                 return cls(x=..., y=..., z=...)
        
        class Derived(Base):
             def __init__(*, a, b, c, **kwargs )
                 super().__init__(**kwargs)
                 # assign a, b, c
        
             @classmethod
             def from_file(cls, file)
                 obj = super().from_file(file)
                 # Do additional work with obj
                 return obj  
        

        【讨论】:

          猜你喜欢
          • 2018-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多