2017-02-10 46 views
0

我试图在Python中运行模拟。为了这个工作,我需要定义一些参数并从这些参数中派生出一些参数。然后使用这些函数调用几个函数,这些函数作用于这些参数并返回一定的结果。目前我的代码看起来是这样的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会在这里工作,因为这需要明确地传递默认值。

我一直在玩弄传入一个字典的功能和传递之前设定的非标准参数的妥协。这使得函数调用很难理解,所以我觉得应该有一个更简单的方法来做到这一点。

由于函数只由相对较长的方程,我不想字符添加到它将在字典中存放时,并从那里只是调用它们所需的变量名。这使得阅读方程困难得多。

我的问题是是否有Python方法来解决这个问题。

+1

您是否尝试过使用抽象类? – AreTor

回答

1

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

你想要一个简单的方法来定义功能,而无需编写默认参数或传递字典多次。

这将是很好的使用装饰或类继承。

Decorator使您能够定义返回像func1func2这样的函数的工厂方法。接口只使用装饰器中的默认参数定义一次,返回的函数在处理方法或核心方法上有所不同。

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

+1

我最终将常用代码放在装饰器函数中,并从那里调用特定的代码。参数是使用'** kwargs'来设置装饰器的,如果没有提供参数,则缺省为一些值。这几乎解决了我所有的问题,除了'func1'和'func2'明确提供了一个参数列表。这样,我可以保持我的方程式可读。我明白,这可能不是好的编程实践,但对我来说,使用python完全是为了减少开发时间,并开始真正的工作。对我来说,不是指可读的方程式 – Octaviour

+0

事实上,在大多数面向对象的编程中,这是一种相当常见的设计模式。你会擅长的。 –

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)) 
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可以在其他地方重新使用。

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