Python static variable in function global name not defined - python

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?

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!

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

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.

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.

Related

Python: Change a global variable, which comes from a function parameter

Is there any way to have a parameter of a function, which is a global variable and in the function itself you change the value of this variable. This way you have a global variable as a parameter of a function. In the function itself you change the value of this global variable. So for example:
x = 2
a = 5
def minus_one(x):
x -= 1 #take the global x
minus_one(x)
print(x) #Should print 1
minus_one(a)
print(a) #Should print 4
Yes, you can do something similar.
x = 2
def minus_one(var_name):
globals()[var_name] -= 1 # This accesses the global dict
minus_one('x') # Note that you must pass the variable name as string here
print(x) # Prints 1
Although, this is not recommended at all.
This can cause bugs that are extremely hard to find.
There is almost always a better way to do it
It's kind of ugly
In general, knowing the global dict exists is good. Knowing you should not use it is better.

How to catch a particular name assignment?

(Based on this question):
One can override the __setattr__ magic method for an object to have additional instructions when an attribute of an object is set. As in:
class MyClass(object):
def __init__(self, attribute=None):
object.__init__(self)
self.attribute = attribute
def __setattr__(self, name, value):
self.__dict__[name] = value
if name == 'attribute':
print("attribute's value is modified to {}.".format(
self.attribute))
if __name__ == '__main__':
my_obj = MyClass(True)
while True:
my_obj.attribute = input()
How can I catch a particular name assignment in the current script
without using classes(specifically to call a method with more
instructions)?
def b_is_modified():
print("b is modified!")
if __name__ == '__main__':
a = 3
b = 4
b = 5
How to call b_is_modified when b is assigned a value?
I think the other answer by Nae sums it up; I'm not aware of any built-in mechanisms in the Python languages to detect assignments, so if you want an interrupt-like event system to trigger upon assignment I don't know if it's feasible.
However, you seem quiet determined to get a way to "detect" assignment, so I want to describe an approach that might get you closer than nothing.
There are the built-in functions globals() and locals() that creates dictionary of variables in global and local scope respectively. (They, in additon to vars() are further explained here).
A noteworthy point is that locals() will behave differently if called from inside a function:
If locals() is called inside a function it constructs a dictionary of the function namespace as of that moment and returns it -- any further name assignments are not reflected in the returned dictionary, and any assignments to the dictionary are not reflected in the actual local namespace
If locals() is called outside a function it returns the actual dictionary that is the current namespace. Further changes to the namespace are reflected in the dictionary, and changes to the dictionary are reflected in the namespace:
Here is a "hacky" way to detect changes to variables:
def b_is_modified():
print("b is modified!")
if __name__ == '__main__':
old = locals().get('b')
a = 3
b = 4
b = 5
new = locals().get('b')
if id(new) != id(old) and new is not None:
b_is_modified()
This is nothing else but an (obfuscated?) way of checking if the value of b has changed from one point in execution to another, and there is no callback event or trigger action that detects it. However, if you want to expand on this approach continue reading.
The rest of the answer explains how to check for changes in b by rewriting it to something like:
if __name__ == '__main__':
monitor = ScopeVariableMonitor(locals())
a = 3
b = 4
monitor.compare_and_update() # Detects creation of a and b
b = 5
monitor.compare_and_update() # Detects changes to b
The following will "detect" any changes to the variables, and I've also included an example where it's used inside a function, to reiterate that then the dictionary returned from locals() does not update.
The ScopeVariableMonitor-class is just an example, and combines the code in one place. In essence, it's comparing changes to the existence and values of variables between update()s.
class ScopeVariableMonitor:
def __init__(self, scope_vars):
self.scope_vars = scope_vars # Save a locals()-dictionary instance
self.old = self.scope_vars.copy() # Make a shallow copy for later comparison
def update(self, scope_vars=None):
scope_vars = scope_vars or self.scope_vars
self.old = scope_vars.copy() # Make new shallow copy for next time
def has_changed(self, var_name):
old, new = self.old.get(var_name), self.scope_vars.get(var_name)
print('{} has changed: {}'.format(var_name, id(old) != id(new)))
def compare_and_update(self, var_list=None, scope_vars=None):
scope_vars = scope_vars or self.scope_vars
# Find new keys in the locals()-dictionary
new_variables = set(scope_vars.keys()).difference(set(self.old.keys()))
if var_list:
new_variables = [v for v in new_variables if v in var_list]
if new_variables:
print('\nNew variables:')
for new_variable in new_variables:
print(' {} = {}'.format(new_variable, scope_vars[new_variable]))
# Find changes of values in the locals()-dictionary (does not handle deleted vars)
changed_variables = [var_name for (var_name, value) in self.old.items() if
id(value) != id(scope_vars[var_name])]
if var_list:
changed_variables = [v for v in changed_variables if v in var_list]
if changed_variables:
print('\nChanged variables:')
for var in changed_variables:
print(' Before: {} = {}'.format(var, self.old[var]))
print(' Current: {} = {}\n'.format(var, scope_vars[var], self.old[var]))
self.update()
The "interesting" part is the compare_and_update()-method, if provided with a list of variables names, e.g. ['a', 'b'], it will only look for changes to those to variables. The scope_vars-parameter is required when inside the function scope, but not in the global scope; for reasons explained above.
def some_function_scope():
print('\n --- Now inside function scope --- \n')
monitor = ScopeVariableMonitor(locals())
a = 'foo'
b = 42
monitor.compare_and_update(['a', 'b'], scope_vars=locals())
b = 'bar'
monitor.compare_and_update(scope_vars=locals())
if __name__ == '__main__':
monitor = ScopeVariableMonitor(locals())
var_list = ['a', 'b']
a = 5
b = 10
c = 15
monitor.compare_and_update(var_list=var_list)
print('\n *** *** *** \n') # Separator for print output
a = 10
b = 42
c = 100
d = 1000
monitor.has_changed('b')
monitor.compare_and_update()
some_function_scope()
Output:
New variables:
a = 5
b = 10
*** *** ***
b has changed: True
New variables:
d = 1000
Changed variables:
Before: b = 10
Current: b = 42
Before: a = 5
Current: a = 10
Before: c = 15
Current: c = 100
--- Now inside function scope ---
New variables:
a = foo
b = 42
Changed variables:
Before: b = 42
Current: b = bar
Conclusion
My answer is just a more general way of doing:
b = 1
old_b = b
# ...
if b != old_b:
print('b has been assigned to')
The dictionary from locals() will hold everything that is a variable, including functions and classes; not just "simple" variables like your a, b and c.
In the implementation above, checks between "old" and "new" values are done by comparing the id() of the shallow copy of before with id() of the current value. This approach allows for comparison of ANY value, because the id() will return the virtual memory address, but this is assumable far from a good, general comparison scheme.
I'm curious to what you want to achieve and why you want to detect assignments: if you share your goal then perhaps I can think of another way to reach it in another way.
Based on this answer:
It can't be catched(at least in python level).
Simple name assignment(b = 4), as oppposed to object attribute assignment (object.b = 5), is a fundamental operation of the language itself. It's not implemented in terms of a lower-level operation that one can override. Assignment just is.

Argument passing by reference to a class in python (á la C++), to modify it with the class methods

In this case, I want that the program print "X = changed"
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
self.var = 'changed'
X = 'unchanged'
V = Clase(X)
V.set_var()
print "X = ",X
All values are objects and are passed by reference in Python, and assignment changes the reference.
def myfunc(y):
y = 13
x = 42 # x now points at the integer object, 42
myfunc(y) # inside myfunc, y initially points to 42,
# but myfunc changes its y to point to a
# different object, 13
print(x) # prints 42, since changing y inside myfunc
# does not change any other variable
It's important to note here that there are no "simple types" as there are in other languages. In Python, integers are objects. Floats are objects. Bools are objects. And assignment is always changing a pointer to refer to a different object, whatever the type of that object.
Thus, it's not possible to "assign through" a reference and change someone else's variable. You can, however, simulate this by passing a mutable container (e.g. a list or a dictionary) and changing the contents of the container, as others have shown.
This kind of mutation of arguments through pointers is common in C/C++ and is generally used to work around the fact that a function can only have a single return value. Python will happily create tuples for you in the return statement and unpack them to multiple variables on the other side, making it easy to return multiple values, so this isn't an issue. Just return all the values you want to return. Here is a trivial example:
def myfunc(x, y, z):
return x * 2, y + 5, z - 3
On the other side:
a, b, c = myFunc(4, 5, 6)
In practice, then, there is rarely any reason to need to do what you're trying to do in Python.
In python list and dict types are global and are passed around by reference. So if you change the type of your variable X to one of those you will get the desired results.
[EDIT: Added use case that op needed]
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
self.var.test = 'changed'
class ComplicatedClass():
def __init__(self, test):
self.test = test
X = ComplicatedClass('unchanged')
print('Before:', X.test)
V = Clase(X)
V.set_var()
print("After:",X.test)
>>> Before: unchanged
>>> After: changed
strings are immutable so you could not change X in this way
... an alternative might be reassigning X in the global space... this obviously will fail in many many senarios (ie it is not a global)
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
globals()[self.var] = 'changed'
X = 'unchanged'
V = Clase('X')
V.set_var()
print "X = ",X
the other alternative is to use a mutable data type as suggested by Ashwin
or the best option is that this is probably not a good idea and you should likely not do it...

How can I create an indefinite iterations of objects in python?

I'm new to python and am trying to create a program to test some methods of object creation. Currently, I'm writing a program that involves creating objects, giving them a unique numeric variable, and assigning them to a list for future referencing. Here's what I wrote to create the variable names:
def getRectangleName():
rectName = list("Rectangle")
SPAWNEDOBJECTLIST.append(len(SPAWNEDOBJECTLIST))
rectName.append(str(len(SPAWNEDOBJECTLIST)))
return rectName
and then that's passed onto something to turn that string into a variable name. I tried eval(), learned this was Bad for some reason and it didn't work anyway, and tried some workarounds to no avail.
I figure there's plenty of games that have an indefinite number of characters on the screen. Is there an established way of making iterations of objects like this?
The objects themselves have an X and Y so that they act as reference points for the display of rectangles on screen(the idea in the future is to have each one move around on their own, so simply making lists of X and Y to draw rectangles isn't useful).
Edit: The problem is that I don't know how to give each object its own variable to put it on a list for future referencing.
Edit2: I don't think I'm asking the right question, actually, or using the right terminology. I need to be able to have an indefinite number of objects created on the fly after the program is already running, and be able to reference them individually.
The problem is that I don't know how to give each object its own variable to put it on a list for future referencing.
Whenever you think you need variables you didn't type into your program, you're doing something wrong. You don't need to assign something to a variable to put it on a list:
x = [1, 2, 3] # Note how I don't assign 1, 2, or 3 to variables.
x.append(4) # 4 doesn't get a variable either.
x.append(make_a_rectangle()) # We create a rectangle and stick it on the list.
do_stuff_with(x[4]) # We pass the rectangle to a function.
x = [] # New list.
for i in xrange(n):
x.append(make_a_rectangle()) # This happens n times.
# At this point, we have n rectangles, none of them associated with their own
# variable, none of them with a name.
If you think you need names for things (and quite often, you don't really need the names), you can use a dict:
x = {}
x['foo'] = make_a_rectangle()
do_stuff_with(x['foo'])
It's not a great idea to combine the function of managing the rectangles -- accessing, adding, or deleting them -- with the idea of being rectangles. You never know when you might need to maintain multiple lists, or change from unordered lists to organized ones.
Until you really need more, keep the management functions simple: use built-in lists or dictionaries. Use lists if you just care about ordering, or only need to know you have a bunch of stuff:
class Rectangle (object):
def __init__(self, top, bottom, left, right):
self.Top = top
self.Left = left
self.Right = right
self.Bottom = bottom
list_of_rects = [Rectangle(10,0,0,10), Rectangle(20, 10, 10 ,20)]
# how many rects?
len(list_of_rects)
# result: 2
# where is this particular rect?
fred = Rectangle(30,20,20, 30)
list_of_rects.insert(fred, 1)
list_of_rects.index(fred)
# result: 1
#remove an item from the list:
list_of_rects.remove(fred)
#search the list:
right_of_5 = [rect for rect in list_of_rects if rect.Left > 5]
If you need to get access to the individual rects for some reason -- 'what's the rectangle of the goal' or something -- you have two choices:
1) the code that needs the rect just keeps a reference to it:
class Goal(object):
def __init__(self, rect):
self.Rect = rect
goalrect = Rectangle (0,0,20,20)
mygoal = Goal(goalrect)
list_of_rects.append(goalrect)
# now goalrect always knows about it's own rect, but the list can keep track of it too...
2) Or, use a dictionary:
named_rects = {}
named_rects['goal'] = Rectangle(0,0,20,20)
You get all the same abilities with a dictionary that you do with a list -- add, delete, and find -- except dictionaries don't preserve order, so you can't manage things like priority:
# add to the dict:
named_rects['new_rect'] = Rectangle(90,90,95,95)
# remove
del named_rects['new_rect']
# find = is there a known key?
if 'new_rect' in named_rects: print new_rect
# search:
right_of_5 = [rect for rect in named_rects.items() if rect.Left > 5]
There are cases where you need fancier things than plain old lists and dicts -- but always try it with the free stuff first :)
If you dynamically want to create variables and add them to class instances, use this
class MainClass:
def __setattr__(self, name, value):
self.__dict__[name] = value
def getRectangleNameGenerator(N = 10):
X = 0
while X <= N:
X += 1
yield "Rectangle" + str(X)
RectangleName = getRectangleNameGenerator()
ClassInstances = {next(RectangleName) : MainClass}
ClassInstances[next(RectangleName)] = MainClass
ClassInstances["Rectangle1"].Temp = 10
print ClassInstances["Rectangle1"].Temp
If the class is going to have only X and Y,
class MainClass:
X, Y = 0, 0
def getRectangleNameGenerator(N = 10):
X = 0
while X <= N:
X += 1
yield "Rectangle" + str(X)
RectangleName = getRectangleNameGenerator()
ClassInstances = {next(RectangleName) : MainClass}
ClassInstances[next(RectangleName)] = MainClass
ClassInstances["Rectangle1"].X = 11
print ClassInstances["Rectangle1"].X
If you really want to refer to your rectangle instances by name, I would suggest to keep a dictionary at class level. Something like this:
#! /usr/bin/python3
from threading import Lock
import random
class Rectangle:
instances = {}
lock = Lock ()
#classmethod
def forName (cls, name):
return cls.instances [name] if name in cls.instances else None
#classmethod
def push (cls, inst):
with cls.lock:
name = None
while not name or name in cls.instances:
name = ''.join (random.choice ('abcdefghij') for i in range (16) )
cls.instances [name] = inst
return name
def __init__ (self):
self.name = Rectangle.push (self)
names = [Rectangle ().name for i in range (5) ]
for name in names:
print (name, Rectangle.forName (name) )

How to loop over each call to a function in Python

I need to increment a variable each time a certain number of calls to a certain function is made in Python 2.7.3.
For example, feetTraveled = 0. for every 12 calls to travelOneInch(), feetTraveled += 1.
Is it optimal to use a for loop or should I be using something different?
If it is optimal to use a for loop like the one above, what should be placed instead of 'every 12 calls to'?
Another example: I have four servants. They each do one task in a clock tick, and the time counter is initially time = 0. So for every four calls to servantDo(), time += 1.
In this case, I think I'd use an instance method:
class Foo(object):
def __init__(self):
self.inches = 0
self.feet = 0
def travel_one_inch(self):
self.inches += 1
if self.inches > 11:
self.inches = 0
self.feet += 1
def __str__(self):
return "{feet} feet and {inches} inches".format(feet=self.feet,inches=self.inches)
a = Foo()
for _ in range(123):
a.travel_one_inch()
print(a)
A vast majority of the time, if you want a function to remember some sort of state between calls, you're not looking for a function at all -- You're looking for a class with an instance method.
If you want to work in the global namespace:
inches = 0
feet = 0
def travelOneInch(sure):
inches += 1
if (inches % 12) == 0:
feet += 1
#...
And using inches % 12 == 0 is better than inches > 12 in case you want your function to recognize the second and furher feet.
mgilson (above) knows what's up. If I were you, I'd do the following, to make things easier:
class Foo(object):
def __init__(self):
self.__inches = 0
def travel_one_inch(self):
self.__inches += 1
def feetTraveled(self):
return self.__inches // 12
But, in terms of optimality, if you're just doing this once, then you can use temporary variables:
feetTraveled = 0
inchesTraveled = 0
for i in xrange(72):
# as in mgilson's answer
inchesTraveled += 1
if inchesTraveled > 11:
inchesTraveled = 0
feetTraveled += 1
Probably the best implementation is to use an object to store the status and use the function to modify it:
class Position(object):
def __init__(self):
self.pos = 0
def advance(self,inches=1):
self.pos += inches
def pos_as_foot(self):
return self.pos // 12
If you find this approach a little to boring (even if it's the most correct one), you can try a more esoteric approach: you can use internal values of the function, i.e. treating it like an object
def foo():
foo.value+=1
if foo.value and not foo.value%12:
foo.result+=1
foo.value=0
foo.result=0
for i in range(15):
foo()
print foo.value
#15
print foo.result
#1
It's not the most easy solution, and have problem if you need several counters, but it's interesting to know. It has the advantage to remove some cluttering code (at least in simple cases) from the class definition (that is using under the hood), and keep the state accessible whereever you will use the function, without tampering with global variables (that i reaaaly don't like)

Categories