【问题标题】:Hide certain class methods depending on load criteria根据负载标准隐藏某些类方法
【发布时间】:2022-11-13 06:39:51
【问题描述】:

我有一个类用于处理三种类型的数据结构。 在这个类中,我有许多绘图方法,这取决于加载到类中的数据类型。 在查看类属性时,有没有办法隐藏不属于加载的数据结构的方法?

例子:

class data_reader():
     def __init__(self):
          self.load_data()
          self.data_type()
          self.common_method_1()
          self.common_method_2()
     
     def load_data(self):
          # Loads the data

     def data_type(self):
          # Figures out which of the three data structures we have

     def common_method_1(self):
          # A method common for all data structures

     def common_method_2(self):
          # Another method common for all data structures

     def plot_data_1(self):
          # Plotting function for data structure 1

     def plot_data_2(self):
          # Plot function for data structure 2

     def plot_data_3(self):
          # Plot function for data structure 3

if __name__ == "__main__":

     a = data_reader()
     a.plot_data_1()

当我检查类的方法时,我可以看到所有绘图函数。如果我加载数据结构 1,我可以隐藏其他两个绘图功能吗?

我尝试做一些内部函数,但后来它并没有成为类外的可调用方法。

感谢您的任何意见。

【问题讨论】:

  • 重新考虑你的班级结构——让他们成为同一个班级真的有意义吗?将常用方法移至父类,并为每种数据类型创建一个从该父类继承的特定类。
  • 根据您的评论,我查找了内部类或嵌套类,它们似乎通过添加另一个属性层来解决问题,因此:a.data1.plot() 或 a.data2.plot()。感谢您的评论!

标签: python function class methods


【解决方案1】:

我的方法取决于您的各种数据结构有多“不同”:

V1:没有那么不同,例如,嵌套列表与 numpy 数组。在这种情况下,我建议您编写不同的数据加载函数,这些函数总是将数据转换为通用格式,例如:

def load_list_data(self, data):
    # reads a list and converts it to a numpy array

def load_npy_array_data(self, data):
    # reads a numpy array which does not need to be converted

def plot_data(self):
    # plots a numpy array

V2:数据差异很大,例如,点云与图像。然后使用两个子类和一个工厂方法。编辑版本包含一个接受文件路径的工厂方法。路径是打开并传递给加载方法的文件对象:

class data_reader():
    def __init__(self, file_object):
        self.load_data(file_object)
        self.data_type()
        self.common_method_1()
        self.common_method_2()

    def load_data(self, file_object):
        # Loads the data
    
    def data_type(self):
        # Figures out which of the three data structures we have

    def common_method_1(self):
        # A method common for all data structures

    def common_method_2(self):
        # Another method common for all data structures

class img_data_read(data_reader):
    def plot_data(self):
        # Plotting function for data structure 1

class pointcloud_data_read(data_reader):
    def plot_data(self):
        # Plotting function for data structure 1

def data_reader_factory(file_path):
    with open(file_path, "r") as f:
        if isinstance(f[FILE_DATA_PATH], IMG_DATA_TYPE):
            return img_data_read(f)
        elif isinstance(f[FILE_DATA_PATH], POINTCLOUD_DATA_TYPE):
            return pointcloud_data_read(f)

然后你可以这样做:

if __name__ == "__main__":

    a = data_reader_factory()
    a.plot_data()

【讨论】:

  • 这似乎是我最接近工作的一个,但我遇到的一个问题是我在加载数据之前不一定知道数据类型。您的最后一个功能需要事先了解这些知识。数据结构也完全不同,数据对象本身并不是我想要转移到绘图类中的唯一东西。我还想转移可能的其他属性。我尝试使用嵌套类,但我无法将属性继承到嵌套类,导致无法绘图。如果有意义的话,你知道如何克服这个问题吗?
  • 那你有什么?您尝试从中加载一些数据的文件路径?一旦你打开那个文件,你会清楚它是什么类型的数据吗?在不了解更多细节的情况下很难提出解决方案。
  • 是的,一旦我打开文件,存储一些特定于该文件的属性,我就会知道它是什么类型。从本质上讲,我通过简单地运行“加载”类的第一部分来解决这个问题,在知道类型之后,我用你提出的方法运行整个事情。可能不是最快的,但它确实运行得非常顺利。
  • 我稍微更新了我的答案,你如何只打开一次文件。这个想法是在工厂方法中打开文件一次,然后根据其内容将打开的对象传递给正确的类。但正如您所写,将整个装载机移至工厂也可以。
【解决方案2】:

与实际对象无关的方法不应该是.他们应该不在首先。因此,不要为不同的数据类型创建一个“通用”对象,而是将公共逻辑提取到父类中并继承到定义特定于数据类型的行为的特定子类。

当然,这需要您在运行前了解数据类型。如果您只能在实际加载数据时决定,我建议实现工厂模式 - 一个单独的类,处理决定创建哪个对象的逻辑。

class data_reader():
    def __init__(self, data):
        self.common_method_1()
        self.common_method_2()


    def common_method_1(self):
        pass

    def common_method_2(self):
        pass


class data_reader_1(data_reader):
    def plot_data_1(self):
        pass
          # Plotting function for data structure 1
class data_reader_2(data_reader):
    def plot_data_2(self):
        pass
        # Plot function for data structure 2

class data_reader_factory():
    
    def load_data(self):
        self.data = 42
        # Loads the data    

    def data_type(self):
        self.type = "1"
        # Figures out which of the three data structures we have
        

    def create_reader(self):
        if self.type == "1":
            return data_reader_1(self.data)
        elif self.type == "2":
            return data_reader_2(self.data)
        # Creates an object of correct type

if __name__ == "__main__":
    a = data_reader_factory().create_reader()
    a.plot_data_1()

【讨论】:

    【解决方案3】:

    根据matszwecja 的评论:

    将所有常用方法放在基类data_reader 中,然后创建该类的子类以覆盖方法plot_data。基类不再需要了解各种类型的绘图。正确的plot_data 方法将根据实际类被调用。这是面向对象编程的基本技术。例如,参见Object-Oriented Programming: Polymorphism in Python

    from abc import ABC, abstractmethod
    
    # This is an abstract class: method plot_data
    # must be overriden in a subclass:
    class data_reader(ABC):
         def __init__(self):
              self.load_data()
              self.common_method_1()
              self.common_method_2()
    
         def load_data(self):
              # Loads the data
              ...
    
         def common_method_1(self):
              # A method common for all data structures
              ...
    
         def common_method_2(self):
              # Another method common for all data structures
              ...
    
         # This method must be overridden in a subclass:
         @abstractmethod
         def plot_data(self):
              pass
    
    class data_reader_1(data_reader):
         def plot_data(self):
              # Plotting function for data structure 1
              ...
    
    class data_reader_2(data_reader):
         def plot_data(self):
              # Plotting function for data structure 2
              ...
    
    class data_reader_3(data_reader):
         def plot_data(self):
              # Plotting function for data structure 3
              ...
    
    
    if __name__ == "__main__":
    
         a = data_reader_1() # A specific subclass
         a.plot_data()
    

    如果load_data必须具体到每个子类,那么在基类中把它做成一个抽象方法(意思是它必须在子类中重写),然后为每个子类定义它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-15
      • 2023-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多