2015-06-01 87 views
1

我寫了一個函數來計算兩點之間的標題,只有當車輛報告它正在移動並且車輛已經移動了20cm之間的點時。函數全局名稱中的Python靜態變量未定義

該函數使用靜態變量 - 或者至少它會起作用 - 跟蹤以前的位置和標題值。

下面是代碼:

def withCan(pos): 

    eastdist = pos[0]-previous_pos[0] 
    northdist = pos[1]-previous_pos[1] 
    canflag = pos[2] 

    if (canflag == 1 or canflag==2): 

     if (previous_canflag == 1 and canflag == 2): 
      previous_heading += 180.0 
      previous_canflag = canflag 
     elif (previous_canflag == 2 and canflag == 1): 
      previous_heading += 180.0 
      previous_canflag = canflag 
     else: 
      previous_canflag = canflag 

    if ((canflag == 1 or canflag == 2) and math.sqrt(northdist*northdist+eastdist*eastdist) > canstep): 
     previous_heading = math.degrees(math.atan2(eastdist, northdist)) 
     previous_pos[0] = pos[0] 
     previous_pos[1] = pos[1] 

    return previous_heading 

withCan.previous_pos = [0.0,0.0] 
withCan.previous_heading = 0.0 
withCan.previous_canflag = 0 
withCan.canstep = 0.2 

positions = backandforth([100,100]) #populates an array of form [x,y,canflag] 

for p in positions: 
    print withCan(p) 

我得到的是說eastdist = pos[0]-previous_pos[0] NameError: global name 'previous_pos' is not defined錯誤。請有人解釋這個錯誤的原因?

+0

錯誤信息非常清晰 - 全局名稱'previous_pos'未定義。 – xyres

+0

哇,我不是一個Python專家,但我從來沒有見過任何人聲明這樣的變量'withCan.previous_pos = [0.0,0.0]' – HaseebR7

+0

@ HaseebR7:這是合法的Python。這些東西被稱爲功能屬性。 –

回答

6

當你這樣做:

def foo(): 
    pass 

foo.name = 1 

沒有創建一個全局命名name。相反,您正在爲foo函數添加一個屬性!你可以訪問它:

def foo(): 
    return foo.name 

foo.name = 1 

但這很奇怪。如果你需要一個全球性的名字,只是做:

def foo(): 
    global name 
    name += 1 
    return name 

name = 1 

記住,如果你想從功能修改全局名稱,就可以將其聲明爲global。如果你沒有做到這一點,你可以使用它,但你不能指定它。

您對靜態名稱的困惑可能來自使用類。但請注意,在您的代碼withCan不是一個類,它是一個普通的功能!

+0

哇!我不知道你可以做'foo.name'。感覺喜歡它10次。 – xyres

+0

@xyres:是的,在Python中,您可以添加屬性,只需指定幾乎任何東西。一些框架使用它來爲函數和類添加元數據。並實現類似於靜態的變量。但對於普通的用戶代碼和普通變量,它可能並不是最好的主意...... – rodrigo

+0

鼓勵人們在不是絕對必要的情況下編寫全局變量(而且很少),也可能不是最好的主意。 :) –

2

它看起來像你正在嘗試做的是寫一個類...

class WithCan(): 
    def __init(self, previous_pos)__: 
     self.previous_pos=previous_pos 

    def withCan(self, pos): 
     # your function as class method 

然後,你可以初始化實例

withCan=WithCan(previous_pos) 

和訪問

withCan.previous_pos=... 
+1

而_this_是目前唯一明智的答案。 –

1

可以在Python中使用函數屬性做靜態變量s,但您需要在函數內使用全名來訪問這些屬性。

這是一個簡短的演示。

def test(a): 
    print a, a + test.b 
    test.b += 1 

test.b = 5 
test(3) 
test(10) 

輸出

3 8 
10 16 

然而,這將是更常見的做使用一類這樣的事情,如在Tim的答案。

在Python中執行靜態的另一種方法是給你的函數默認的可變參數,但許多人對此感到不舒服。但如果您好奇,請參閱「Least Astonishment」 in Python: The Mutable Default Argument

0

讓我貢獻的一個也許更精簡的方式在功能模擬靜態變量,可以使OP的例子也許更容易閱讀:

def with_can(pos): 
    if not hasattr(with_can, "canflag"): 
    # set up and initialise the static variables 
    with_can.canflag = 0 
    with_can.previous_pos = [0.0,0.0] 
    with_can.previous_heading = 0.0 
    with_can.canstep = 0.2 

    # ... use them ... 
    eastdist = pos[0]-with_can.previous_pos[0] 
    # ... etc ... 

基本上在第一次調用我們檢測到其中的「靜態「變量(canflag)尚未出現,因此我們添加並初始化所有這些變量。之後,他們可以按照指示使用。

但是,正如其他人已經指出的那樣,用數據成員編寫一個類而不是這些「靜態」函數變量要好得多。

相關問題