【问题标题】:Best approach to modify instance variable after running each method of a class?运行类的每个方法后修改实例变量的最佳方法?
【发布时间】:2020-04-15 01:46:57
【问题描述】:

我正在使用 Python 开发数据分析应用程序。我有一个DataAttributes 类,它提供了数据集的各种详细信息。但是,在获取其中一些值时,它使用了另一组直接修改数据的方法——我的DataManipulator 类。

为了简单地为每个类添加未来的方法,我希望能够在运行DataAttributes 的方法之后将数据集重置为其原始状态。所以这涉及到:

  • 存储数据集的初始状态
  • DataAttributes 类型的实例运行方法
  • 将数据集重置为初始状态

当然,我可以通过在每个DataAttributes 方法的开头和结尾运行一个方法来完成此操作,但这感觉非常笨拙,尤其是考虑到获取数据属性的方法有几十种。什么是实现这一点的干净方法?我已经研究过制作一个元类,但不确定如何使用这种方法修改实例变量。我也研究过装饰器,但不确定这是否是最好的。

就我想要实现的示例而言,我想做下面所做的事情,但是对于“n”个方法。此外,这是对我正在做的事情的极大简化——让我们假装我对我正在做的事情有充分的理由,我知道从概念上讲,这个例子没有什么意义。它只是为了展示我想要实现的目标。

class MyClass():
    def __init__(self):
        self.mydata = np.array([1, 2, 3])
        self.my_initial_data = np.array([1, 2, 3])

    def store_initial_data(self):
        self.my_initial_data = np.array([1, 2, 3])

    def reset_data(self):
        self.mydata = self.my_initial_data
        print(self.mydata)

    def method_1(self):
        self.store_initial_data()
        self.mydata *= 2
        self.reset_data()

    def method_2(self):
        self.store_initial_data()
        self.mydata *= 2
        self.reset_data()
    .
    .
    .

    def method_n(self):
        self.store_initial_data()
        self.mydata *= 2
        self.reset_data()

my_inst = MyClass()
my_inst.method_1() # prints [1, 2, 3]

【问题讨论】:

  • 您能否在不改变原始数据的情况下对数据副本执行所有操作?
  • 您可以创建一个函数处理程序数组并在 for 循环中调用它们。
  • 我可以这样做,但它需要在我的 DataManipulator 类中添加一个额外的默认参数(因为该类的这种设计是操纵实际数据对象并绘制它)。可以肯定,但这将是一个丑陋的解决方案。
  • @Seyfi 我对函数处理程序不是很熟悉,你能说得更详细一点吗?

标签: python python-3.x class decorator metaclass


【解决方案1】:

我认为最简单的方法是自定义属性访问,以便在从实例中检索方法时,将其包装在将执行以下操作的代码中 设置和清理任务。

如果您的方法只是有一个模式,以便它们可以被识别,那么它可以变得万无一失。在下面的示例中,我对从实例中检索到的每个可调用对象执行此操作,除非它的名称以 _ 开头 - 这将避免特殊方法,并且您不想包装的任何方法都可以以 _ 为前缀.

这个解决方案只需要一个基类——不需要元类:


def wrap(method, prefix, postfix):
    def wrapper(*args, **kw):
        prefix(*args, **kw)
        result = method(*args, **kw)
        postfix(*args, **kw)
        return result
    return wrapper


class SetupCleanupBase:

    def __getattribute__(self, name):
        attr = super().__getattribute__(name)
        if not name.startswith("_") and callable(attr):
            attr = wrap(attr, self._setup, self._cleanup)
        return attr 


class MyClass(SetupCleanupBase):

    ...

    def _setup(self):
        self.my_initial_data = np.array([1, 2, 3])

    def _cleanup(self):
        self.mydata = self.my_initial_data
        print(self.mydata)

【讨论】:

    猜你喜欢
    • 2020-04-15
    • 1970-01-01
    • 2013-11-21
    • 2017-02-15
    • 2020-03-12
    • 2017-03-27
    • 2015-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多