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

因此,可以保持代碼清潔,簡單並且可重用。隨着腳本的發展,可重用性變得非常重要。