在另一个方法内部调用带有大量参数的方法的Python方法

时间:2018-10-30 21:50:42

标签: python

我是python的新手,想知道经验丰富的编码人员如何解决以下问题。

我有一个名为foo的方法,带有多个参数。我需要在另一个方法bar中调用该方法。有没有一种方法(避免使用类属性),可以避免将“ foo”方法的相同参数传递给“ bar”方法?

class Class:

    def __init__(self, attr1):
        self.attr1 = attr1

    def foo(self, arg1, arg2, arg3):

        return arg1*arg2*arg3

    def bar(self, arg1,arg2, arg3, arg4):

        return arg4*self.foo(arg1, arg2, arg3)

我也必须从其他类中调用bar方法,我想知道是否有一种优雅的解决方案可以使用更少的参数。

2 个答案:

答案 0 :(得分:1)

在不使用类属性/全局变量的情况下,我认为您只需要传递参数即可。但是,您可以编写

class Class:

    def __init__(self, attr1):
         self.attr1 = attr1

     def foo(self, *args):
         # Your logic here/if this is the usage use reduce
         return args[0]*args[1]*args[2]

    def bar(self, *args):
        return args[3]*self.foo(*args[:3])

如您所见,此代码牺牲了代码的可读性。 PEP8(https://www.python.org/dev/peps/pep-0008/)进行澄清。

或者您也可以这样做:

class Class:

    def __init__(self, attr1):
         self.attr1 = attr1

     def foo(self, arg1, arg2, arg3):
         # Your logic here/if this is the usage use reduce
         return arg1*arg2*arg3

    def bar(self, *args):
        return args[3]*self.foo(*args[:3])

*运算符在此遍历给定的数组,并将其元素提供给被调用的函数。

答案 1 :(得分:0)

我在这里要做什么实际上取决于您的功能的实际目的。没有办法避免这样传递参数,但是有办法在适当的条件下使代码更短,更清晰。

我将首先确定foo是否适用于任意输入。如果参数确实是不同的并且具有不同的目的,那么我将保持原样并接受参数列表将很长。另一方面,如果某些参数不是真正不同的并且可以视为序列,则可以使用splat表示法将其明确。关键不是修改输入而是重写foo本身以处理任意输入:

from operator import mul
from functools import reduce

def foo(*args):
     return reduce(mul, args)

当然,某些参数本身可能是不同的且很重要,在这种情况下,您可以混合使用:

def foo(arg1, arg2, *args):
     return arg2 * (arg1 + reduce(mul, args))

现在,您可以决定如何处理bar。结果将取决于您对foo所做的操作以及bar本身的总体目的。

如果bar的唯一主要依存关系是foo,则它可以直接接受foo的参数。我强烈建议您将非foo参数(在您的示例中为arg4)移到参数列表的前面。即使您决定foo需要多个独立的命名参数,您仍然可以执行以下操作:

def bar(arg4, *args, **kwargs):
    return arg4 * foo(*args, **kwargs)

请记住要非常清楚地记录下来。确保在“所有其余参数都直接传递到foo”这一行中有一条注释。

一个更复杂的情况可能是bar要么委托许多复杂的函数,要么本身就拥有大量参数。在这种情况下,我会将foo的参数列表放入位置和关键字参数的两个单独的变量中。这在matplotlib中很常见,在其中注释对象之类的东西需要具有文本属性,箭头属性,不同的变换等:

def bar(arg4, foo_args=None, foo_kwargs=None):
     if foo_args is None:
         foo_args = ()
     if foo_kwargs is None:
         foo_kwargs = {}
     return arg4 * foo(*foo_args, **foo_kwargs)

我们必须做foo_kwargs=None的原因是默认参数是持久且可访问的。如果要在函数外部修改该参数,则默认情况下将使用非空字典来调用foo。将默认参数设置为空容器是一个新手常犯的错误,只是意识到一旦函数运行,它们就不会为空。我们使用None之类的不变标记值来解决此问题,该值使我们知道何时从头开始创建一个新的空容器。请注意,foo_args=None并非绝对必要,因为空元组将始终保持为空。我只是觉得如图所示会更加一致。

我已经用函数符号编写了所有示例,但是如果可以的话,这些思想可以完全转移到方法中。