具有参数和返回值的函数的pythonic方式

时间:2017-02-10 09:01:36

标签: python parameter-passing

我正在尝试在Python中运行模拟。为此,我需要定义一些参数,并从中推导出其他参数。使用这些我然后调用几个作用于这些参数的函数并返回一定的结果。目前我的代码看起来像这样

common(ai, bi, ..., hi):
    # calculations
    return ao, bo, ..., fo
func1(ai, bi, ..., xi):
    ao, bo, ..., fo = common(ai, bi, ..., hi)
    # calculations specific to func1
    return y
func1(ai, bi, ..., xi):
    ao, bo, ..., fo = common(ai, bi, ..., hi)
    # calculations specific to func2
    return z

ai = 0
bi = 1
...
xi = 2

print(func1(ai, bi, ..., xi))
print(func2(ai, bi, ..., xi))

我使用...缩写参数列表等,并在# calculations部分中执行计算。

我更愿意使用func1(di=2)调用函数,并为所有其他函数设置默认值。然而,这意味着使用命名参数,在这种情况下,我必须指定两次默认值(在func1func2中)。我不认为**kwargs会在这里工作,因为这需要明确传递默认值。

我一直在尝试将字典传递给函数并在传递之前设置非标准参数。这使得函数调用更难以理解,所以我觉得应该有一种更简单的方法来做到这一点。

由于函数只包含相对较长的方程式,因此我不想在变量名称中添加字符,就像将它们存储在字典中并从那里调用它们时所需要的那样。这使得读取方程式变得更加困难。

我的问题是,是否有一种pythonic方法可以解决这个问题。

3 个答案:

答案 0 :(得分:1)

你有两种方法具有相同类型的参数和返回值,唯一的区别是函数内部的进程,即它们共享相同的接口和功能。

您需要一种简单的方法来定义函数,而无需编写默认参数或多次传入字典。

使用装饰器或类继承会很好。

Decorator使您可以定义返回func1func2等函数的工厂方法。该接口仅使用decorator中的默认参数定义一次,返回的函数在过程方法或核心方法上有所不同。

Class继承的工作方式类似,但通过方法继承,它更灵活,更通用。

答案 1 :(得分:0)

您可以创建一个类来保存其属性中的变量:

class SimClass(object):

    def __init__(self, **kw):
        self.ao = kw.get('aa', VA_DEFAULT)
        self.bo = kw.get('bb', VB_DEFAULT)
        # ...
        self.zo = kw.get('zz', VZ_DEFAULT)

    def common(self, ai, bi, ..., hi):
        # calculations set self.ao, self.bo, ..., self.fo
        return

    def func1(self, ai, bi, ..., xi):
        self.common(ai, bi, ..., hi)
        # calculations specific to func1 using self.ao, self.bo, ..., self.fo
        return y

    def func1(self, ai, bi, ..., xi):
        common(ai, bi, ..., hi)
        # calculations specific to func2 using self.ao, self.bo, ..., self.fo
        return z

ai = 0
bi = 1
...
xi = 2

sim = SimClass(bb='BB', cc='CC')

print(sim.func1(ai, bi, ..., xi))
print(sim.func2(ai, bi, ..., xi))

答案 2 :(得分:0)

编程中的函数参数不必像数学中那样完全使用。你可能有一个等式:

z = sqrt((x2 - x1)^2 + (y2 - y1)^2)

仅当变量具有短名称时才易于阅读。你想保留它是可以理解的。但编程语言可能不会那样工作,他们使用自己的语法和工具。

编程中重构的一个重要原则是减少函数中传递的参数的数量。最简单的方法是将所有传递的参数封装在一个对象中,并在函数之间仅传递该对象:

import math

class Line:
    def __init__(self, x1, x2, y1, y2):
         self.x1 = x1
         self.x2 = x2
         self.y1 = y1
         self.y2 = y2

def getLineLength(line):        
    return math.sqrt((line.x2 - line.x1)**2 + (line.y2 - line.y1)**2)

line = Line(3, 5, -2, 7)
print(getLineLength(line))

当然,您必须使用对象名称,原始等式变得不那么可读。而Python代码并不一定非常像数学公式。但相反,您现在可以在代码的其他部分重新使用新类Line

如果函数足够复杂以查看它的作用,可以进一步重构:

def getLineLength(line):
    dx = line.x2 - line.x1
    dy = line.y2 - line.y1      
    return math.sqrt(dx**2 + dy**2)

此函数可能会在Line类中移动:

class Line:
...

def getLength(self):
    dx = self.x2 - self.x1
    dy = self.y2 - self.y1      
    return math.sqrt(dx**2 + dy**2)

line = Line(3, 5, -2, 7)
print(line.getLength())

......甚至进一步重构:

import math

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __sub__(self, other):
        return Point(other.x - self.x, other.y - self.y)

class Line:
    def __init__(self, x1, x2, y1, y2):
         self.start = Point(x1, y1)
         self.end = Point(x2, y2)

    def getLength(self):
        d = self.start - self.end
        return math.sqrt(d.x**2 + d.y**2)

line = Line(3, 5, -2, 7)
print(line.getLength())

新课程Point可以在其他地方重复使用。

因此,可以保持代码清洁,简单和可重用。随着脚本的发展,可重用性变得非常重要。