1

I have written a function to calculate the heading between two points only if a vehicle reports that it's moving and that the vehicle has moved 20cm between points.

The function uses static variables - or at least it would if it worked - to keep track of previous positions and heading values.

Here is the code:

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)

I am getting an error that says eastdist = pos[0]-previous_pos[0] NameError: global name 'previous_pos' is not defined. Please could someone explain the cause of this error?

asked Jun 1, 2015 at 9:59
3
  • The error message is quite clear - global name 'previous_pos' is not defined. Commented Jun 1, 2015 at 10:01
  • wow, i'm not a python expert, but i've never seen anyone declare variables like this withCan.previous_pos = [0.0,0.0] Commented Jun 1, 2015 at 10:02
  • @HaseebR7: It's legal Python. Such things are called function attributes. Commented Jun 1, 2015 at 10:08

4 Answers 4

6

When you do this:

def foo():
 pass
foo.name = 1

You are not creating a global name name. Instead you are adding a property to the foo function! You can access it with:

def foo():
 return foo.name
foo.name = 1

But that is quite weird. If you need a global name, just do it:

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

Remember that if you want to modify the global name from the function, you have to declare it as global. If you fail to do this, you can use it but you cannot assign to it.

Your confusion with static names may come from using classes. But note that in your code withCan is not a class, it is a plain function!

answered Jun 1, 2015 at 10:03

3 Comments

Wow! I didn't know you could do foo.name. Feel like upvoting it 10 times.
@xyres: Yes, in Python you can add properties, just assigning, to almost anything. That is used by some frameworks to add metadata to functions and classes. And to implement static-like variables. But for normal user code and normal variables it may not be the best idea...
Encouraging people to write to globals when it's not absolutely necessary (and it rarely is) is probably not the best idea, either. :)
2

It looks like what you are trying to do is writing a class...

class WithCan():
 def __init(self, previous_pos)__:
 self.previous_pos=previous_pos
 def withCan(self, pos):
 # your function as class method

Then you could initialize an instance

withCan=WithCan(previous_pos)

and access it

withCan.previous_pos=...
answered Jun 1, 2015 at 10:08

1 Comment

And this is the only sane answer so far.
1

You can do static variables in Python using function attributes, but you need to use the full name inside the function to access those attributes.

Here's a short demo.

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

output

3 8
10 16

However, it would be more usual to do this sort of thing using a class, as shown in Tim's answer.

Another way to do statics in Python is to give your function default mutable arguments, but many people are uncomfortable with that. But if you're curious, please see "Least Astonishment" in Python: The Mutable Default Argument.

answered Jun 1, 2015 at 10:13

Comments

0

Let me contribute a perhaps more streamlined way of emulating static variables in functions that could make the OP's example maybe easier to read:

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 ...

Basically at the first invocation we detect that one of the "static" variables (canflag) is not yet there so we add and initialise all of them. After that they can be used as indicated.

However, as others have pointed out already, it is much better to write a class with data members instead of these "static" function variables.

answered Aug 26, 2015 at 12:51

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.