如果需要第一个函数,如何在脚本中执行第二个函数?

Posted

技术标签:

【中文标题】如果需要第一个函数,如何在脚本中执行第二个函数?【英文标题】:How do you execute the second function in a script if it needs the first function? 【发布时间】:2017-07-20 18:19:42 【问题描述】:

我认为这是基本的,我已经看到了我所问问题的多个版本,尽管它们都不完全是我所面临的。

我目前有一个包含两个函数的脚本,我希望能够只调用第二个函数,但它需要运行第一个函数。我的脚本仍然很乱,所以我使用了一个示例:

def func1(input):    # Does something with input data
    my_list = []
    for i in input:
        my_list.append(i)
    return my_list  # Returns a list

func1_list = func1(x) # Save the result from func1 into a variable

def func2(func1_list):   
    my_final_list = []       # This function just edits the first list          
    for val in my_list:       # Results from func2 are needed later on         
        temp = val**3
        my_final_list.append(temp)
    return my_final_list

有没有办法在导入脚本时执行第二个函数而不必调用第一个函数?我不知道在哪里输入 func2 中的 func1_list 变量,这样任何人都可以直接进入 func2 并运行它(无论如何它都会自动执行 func1)。

编辑: func1 和 func2 都应该能够单独执行 - func2 依赖于 func1。两者都将显示信息(func2 仅显示修改后的信息)。示例:func1 将运行一些输入并显示原始结果,而 func2 将获取该原始结果并对其进行修改。如果需要,我希望能够查看原始结果和修改后的结果。

【问题讨论】:

从代码的模块范围中删除func1_list = func1(x),然后您可以在不调用func1 的情况下导入。 在调用func2之前编写一个执行func1_list = func1(x)的包装器? 函数是闭包,因此您可以简单地从函数中删除func1_list 参数(并将for val in my_list 更改为for val in func1_list,或者更好:return [val**3 for val in func1_list]。或者您可以使func2致电func1 我认为你需要退后一步,解释一下你真正想要做什么。这个问题本身并没有多大意义,而且很难理解您要解决的基本问题是什么。 可以肯定的是,如果你最终打电话给func2my_list 会给出一个NameError 【参考方案1】:

如果您希望func1_list = func1(x) 仅在直接执行您的脚本时调用,您需要稍微修改您的脚本,以便在从模块调用时忽略它。您将使用这样的 if 条件:

if __name__ == '__main__':
    func1_list = func1(x) # Save the result from func1 into a variable

__name__仅在直接调用脚本时才等于__main__,因此从模块调用时不会执行。


有关其工作原理的详细说明,请查看here。

【讨论】:

哦,我听说过这个,从来没有真正理解过。但是当你说它被直接调用时是什么意思呢?我导入了我的脚本,所以不是直接调用它吗?我也只是尝试将变量放在函数中,这似乎可行,但我不确定这是否是最佳做法。 如果文件名为A.py,则运行python A.py 将导致该行执行。但是在B.py 中执行import A 不会。 @DNAngel 看官方docs。没有比这更正式的了。 哦,好吧,我将不得不解决这个问题。我对如何让我的 func2 在 func1 中使用相同的对象感到困惑,以便它可以在相同的数据集上工作。即 def func2(input) @DNAngel 在 if 条件中,调用 func2(func1_list)。另外,如果这个答案有帮助,您可以接受它(点击灰色复选标记)。【参考方案2】:

如果您尝试导入脚本,则必须遵循最佳实践和约定。

在不开始构建完整包的情况下,您至少需要确保不执行导入模块时未请求的代码。

要么将代码包装到 class 中,要么从模块的根目录中删除函数调用并提供必须调用的 init_function() 以准备环境。

使用 init_function() 并不丢人,很多库都这样做。

但是,我建议您在 Python classes 内构建您的代码。 FunctionsManager.py 示例:

class FunctionsManager:
    def __init__(self):  
        self.func1_list = self.func1(x) # Save the result from func1 into a variable

    def func1(self, input):    # Does something with input data
        my_list = []
        for i in input:
            my_list.append(i)
        return my_list  # Returns a list

    def func2(self, func1_list):   
        my_final_list = []       # This function just edits the first list          
        for val in my_list:       # Results from func2 are needed later on         
            temp = val**3
            my_final_list.append(temp)
        return my_final_list

然后在你的主代码中:

from FunctionsManager import FunctionsManager

manager = FunctionsManager() # Calls __init__() and so func1()
result = manager.func2(yourlist)

【讨论】:

感谢您提供的信息。上课总是让我害怕(笑),但我确实想按照最佳实践学习。我是一个完全没有课程的菜鸟,但我会再次阅读它并尝试相应地编辑我的函数!没有冒险,没有收获! 是的,我在这条道路上对你的所有鼓励 :-) 你会发现它比预期的要容易!享受 Python【参考方案3】:

注意,您的问题基本上是在询问dependency injection 的入门知识。您可能会很好地阅读它。它与语言无关——它适用于 Java 和 Python 一样好。

您可以采取几种不同的方法;最佳选择取决于您的需求以及所涉及的功能的作用(这就是我在评论中提出所有问题的原因)。

您正在寻找的最简单的形式是让一个函数调用另一个函数。 (COLDSPEED 提到了这一点。):

def func1(input):
    # do some magic to my_list with input
    return my_list

def func2(input):
    func1_list = func1(input)
    # do some magic to make func2's my_list
    return my_list

在这种情况下,func1 和 func2 都可以被调用。导入代码不必担心在 func2 之前调用 func1 - 这由 func2 负责。

在我讨论您的其他选择之前,您提到这两个函数都输出信息。将计算与输出分开是一种很好的做法。所以,不要这样做:

def func1(input):
    # do some magic to my_list with input
    print("func1: Stuff from my list...")
    return my_list

def func2(input):
    func1_list = func1(input)
    print("func2: Stuff from my list...")
    # do some magic to make func2's my_list
    return my_list

因为调用func2 会打印出“func1”行和“func2”行。相反,将逻辑与输出分开。它可能看起来更复杂,但它为您提供了更多的构建块:

def func1(input):
    # do some magic to my_list with input
    return my_list

def func2(input):
    func1_list = func1(input)
    # do some magic to make func2's my_list
    return my_list

def output_func1(input):
    func1_list = func1(input)
    print("func1_list stuff")

def output_func2(input):
    func2_list = func2(input)
    print("func2_list stuff")

现在你有很多不会产生很多噪音的可重用函数。

这是一个很好的步骤,您可以轻松使用它。如果func1 需要一个小时才能运行会发生什么?如果它已经运行过,您不想再次运行它。然后你想使用模块变量来保存状态。像这样的:

func1_results = None

def func1(input):
    # do some magic to my_list with input
    func1_results = my_list
    return my_list

def func2(input):
    if not func1_results:
        func1(input) # this will only run if func1 hasn't been called yet
    # do some magic to make func2's my_list
    return my_list  # you could similarly make a construct to save these results   

现在,只有在需要时才会调用其依赖项的代码。我们越来越好。但是我们将输入传递给 func2,我们只在 func1 中关心它。您可以创建一个 func1 引用的模块变量input,并且您的导入代码可以在调用任何函数之前设置它:

input = None
def func1():
    # do some magic to my_list with module variable input

并将其调用为:

import my_funcs
my_funcs.input = "Happy happy input!"
my_funcs.func1() # or just my_funcs.func2(), etc.

这可能很好,但很危险——如果导入代码没有设置input怎么办?解决这个问题的方法是 Fabien 提到的关于开设课程的内容:

class FuncRunner(object):
    def __init__(self, input):
        self.input = input
        self.func1_results = None
    def func1(self):
        # do some magic to local my_list with input
        self.func1_results = my_list
        return my_list
    def func2(self):
        if not self.func1_results:
            self.func1()
        # do some magic to make func2's my_list
        # maybe save the result as self.func2_results ?
        return my_list

这将被调用为:

from my_funcs import FuncRunner
runner = FuncRunner("Happy happy input!")
foo = runner.func1()  # or foo = runner.func2(), as per your needs

这样做的好处是不让你在不构造对象的情况下运行函数,而且__init__ 的结构方式,如果不传递input,就无法创建对象。 func1 找到的结果存储在对象中,因此它们始终关联在一起。在你的情况下,这可能是做你想做的最干净的方式。

【讨论】:

以上是关于如果需要第一个函数,如何在脚本中执行第二个函数?的主要内容,如果未能解决你的问题,请参考以下文章

第二个参数是获取shell脚本函数中第一个参数的内容[重复]

使用脚本中的参数调用第二个脚本

主要功能未执行我的第二个功能

如何等待异步函数执行?

python脚本结合zabbix 监控mongodb

PL/pgSQL 函数 - 遍历特定列并在循环中执行第二个查询