2015-06-01 85 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)尚未出现,因此我们添加并初始化所有这些变量。之后,他们可以按照指示使用。

但是,正如其他人已经指出的那样,用数据成员编写一个类而不是这些“静态”函数变量要好得多。

相关问题