如何使用实用程序模块而不重复不必要的函数调用?

2024-09-27 02:18:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个实用程序模块,用于向其他脚本提供数据。我不知道如何在尽量减少函数调用量的同时最好地利用它(为了论证,这些调用都很慢)。你知道吗

它看起来像这样:

helper.py

dataset1 = slow_process1()
dataset2 = slow_process2()

def get_specific_data1():
    data = #do stuff with dataset1
    return data

def get_specific_data2():
    data = #do stuff with dataset1
    return data

def get_specific_data3():
    data = #do stuff with dataset2
    return data

现在,假设我需要在脚本中运行get_specific_data1。在上面的设置中,我正在导入模块,这意味着在导入时调用slow_process2是不必要的。你知道吗

如果我嵌套了dataset1dataset2的赋值,但是需要在同一个脚本中调用get_specific_data1get_specific_data2,那么我会运行slow_process1两次,这也是不必要的。你知道吗

如果我用get_specific_data函数的方法创建一个Helper类,如果需要,它运行slow_process1slow_process2,存储数据,然后在调用方法时可以根据需要进行访问,我可以绕过这个问题。这样合适吗?你知道吗

比如:

class Helper:
    def __init__(self):
        self.dataset1 = None
        self.dataset2 = None

    def run_dataset1():
        self.dataset1 = slow_process1()

    def run_dataset2():
        self.dataset2 = slow_process2()

    def get_specific_data1():
       if dataset1 is None:
           self.rundataset1()
       data = #do stuff with dataset1
       return data

    etc

抱歉,如果这是一个愚蠢的问题,但我有有限的经验,面向对象,不想犯错误的前面。你知道吗

谢谢


Tags: selfdatagetreturndefwithdoslow
2条回答

这就是我使用带有properties的类的意思,只是在本例中,我使用了名为lazyproperty的类的自定义版本。它被认为是“懒惰”的,因为它只有在被访问时才被计算,就像一个普通的property,但与它们不同的是,计算出的值被有效地缓存在一种方式中,将其更改为一个实例属性,这样它就不会每次都被重新计算。你知道吗

警告:这样做假设值无论何时计算都是相同的,并且在第一次访问之后对它所做的任何更改都将对使用它的类的同一实例的其他方法可见,即它们不会看到新重新计算的值。你知道吗

一旦这样做了,类中的方法就可以引用self.dataset1self.dataset2,就好像它们是常规的实例属性一样,然后,如果是第一次,将计算与其关联的数据,否则只返回先前创建的值。您可以在生成的输出中看到这种情况(如下所示)。你知道吗

# From the book "Python Cookbook" 3rd Edition.
class lazyproperty:
    def __init__(self, func):
        self.func = func
    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            value = self.func(instance)
            setattr(instance, self.func.__name__, value)
            return value

def slow_process1():
    print('slow_process1() running')
    return 13

def slow_process2():
    print('slow_process2() running')
    return 21

class Helper:
    def __init__(self):
        """ Does nothing - so not really needed. """
        pass

    @lazyproperty
    def dataset1(self):
        return slow_process1()

    @lazyproperty
    def dataset2(self):
        return slow_process2()

    def process_data1(self):
       print('self.dataset1:', self.dataset1)  # doing stuff with dataset1
       return self.dataset1 * 2

    def process_data2(self):
       print('self.dataset2:', self.dataset2)  # doing stuff with dataset2
       return self.dataset2 * 2

    def process_data3(self):
       print('self.dataset2:', self.dataset2)  # also does stuff with dataset2
       return self.dataset2 * 3

if __name__ == '__main__':

    helper = Helper()
    print(helper.process_data1())  # Will cause slow_process1() to be called
    print(helper.process_data2())  # Will cause slow_process2() to be called
    print(helper.process_data3())  # Won't call slow_process2() again

输出:

slow_process1() running
self.dataset1: 13
26
slow_process2() running
self.dataset2: 21
42
self.dataset2: 21
63

您可以使用延迟加载技术来解决此问题:

dataset1 = None
dataset2 = None

def ensureDataset1():
    global dataset1
    if dataset1 is None:
        dataset1 = slow_process1()

def ensureDataset2():
    global dataset2
    if dataset2 is None:
        dataset2 = slow_process2()

def get_specific_data1():
    ensureDataset1()
    data = #do stuff with dataset1
    return data

etc

这里的副作用是,如果你从来没有时间去检查dataset1dataset2,它们永远不会加载。你知道吗

相关问题 更多 >

    热门问题