Local class variables? (mod_python problem)

  • Thread starter Rory Campbell-Lange
  • Start date
R

Rory Campbell-Lange

We have a set of classes using static methods to retain reference
variables between operations. The problem is that the static variables
are not reset between operations when used through mod_python.

Although it is possible to reset the class variables between invocations
of the system, this has the potential of 'wiping out' these variables
when another user is using the system.

Is there a way of getting the equivalent of 'local class variables'? In
other words, a way of making 'print a' and 'print b' below provide the
same output?

Regards
Rory


class TryMe(object):
x = 0
y = 0

def __init__(self):
self.a = 0, self.b = 0

@staticmethod
def incrementer():
TryMe.x += 1, TryMe.y += 1

def addone (self):
TryMe.x += 1, TryMe.y += 1
self.a , += 1 self.b += 1

def __repr__(self):
return """
TryMe.x = %d TryMe.y = %d self.a = %d self.b = %d
""" % (TryMe.x, TryMe.y, self.a, self.b)

if __name__ == '__main__':

a = TryMe()
a.incrementer()
a.addone()

b = TryMe()
b.incrementer()
b.addone()

print 'a:', a
print 'b:', b
 
P

Piet van Oostrum

Rory Campbell-Lange said:
RC> We have a set of classes using static methods to retain reference
RC> variables between operations. The problem is that the static variables
RC> are not reset between operations when used through mod_python.
RC> Although it is possible to reset the class variables between invocations
RC> of the system, this has the potential of 'wiping out' these variables
RC> when another user is using the system.
RC> Is there a way of getting the equivalent of 'local class variables'? In
RC> other words, a way of making 'print a' and 'print b' below provide the
RC> same output?

There are several errors in your python code: quite a number of comma's
have to be replaced by semicolons (or newlines), and there is a spurious
comma.

And a and b already print out the same, so it is not clear what you want.
Do you mean that the x and y of the a and b object should be independent?
In that case you should not use static variables but instance variables.
If they have to survive across different HTTP requests you should use
sessions.
 
D

Diez B. Roggisch

Rory said:
We have a set of classes using static methods to retain reference
variables between operations. The problem is that the static variables
are not reset between operations when used through mod_python.

Although it is possible to reset the class variables between invocations
of the system, this has the potential of 'wiping out' these variables
when another user is using the system.

Is there a way of getting the equivalent of 'local class variables'? In
other words, a way of making 'print a' and 'print b' below provide the
same output?


It's very unclear what you mean here, and I'm additionally under the
impression that you are deep in the murky waters of accidential concurrent
access errors here.

I suggest you explain better what these variables are supposed to contain,
for whom, and for how long, and then we might suggest a better solution.

Diez
 
R

Rory Campbell-Lange

Apologies to Piet and Diez for the lack of clarity in my previous post
(and the broken code).

In essence we use class variables as follows:

class Part (object):
totalgia = 0
def __init__(self, gia):
self.gia = gia # gross internal area
self.giaratio = 0
Part.totalgia += self.gia
def addavgbm(self):
self.giaratio = float(self.gia)/float(Part.totalgia)
def __repr__(self):
return "gia: %0.1f giaratio: %0.2f" % (self.gia, self.giaratio)

if __name__ == '__main__':
p1 = Part(20)
p2 = Part(30)
for p in p1, p2:
p.addavgbm()
print p

totalgia keeps incrementing when this code is used under mod_python.

We most certainly are in 'murky waters of accidental concurrent access'.
A life vest would be gratefully received.

Kind regards
Rory


We have a set of classes using static methods to retain reference
variables between operations. The problem is that the static variables
are not reset between operations when used through mod_python.

Although it is possible to reset the class variables between invocations
of the system, this has the potential of 'wiping out' these variables
when another user is using the system.

Is there a way of getting the equivalent of 'local class variables'? In
other words, a way of making 'print a' and 'print b' below provide the
same output?
 
P

Piet van Oostrum

Rory Campbell-Lange said:
RC> totalgia keeps incrementing when this code is used under mod_python.

And also when used outside of mod_python. It is because it is a class level
variable. In fact I think under certain circumstances in mod_python it will
not do that because different requests can run in different Apache
processes (on Linux, Unix, Mac OS X etc.). So it this desired behaviour or
not? Your post isn't clear about that. And if it isn't what is the desired
behaviour?

And you certainly should do something about the concurrent access.
 
R

Rory Campbell-Lange

In essence we use class variables as follows:

class Part (object):
totalgia = 0
def __init__(self, gia):
self.gia = gia # gross internal area
self.giaratio = 0
Part.totalgia += self.gia
def addavgbm(self):
self.giaratio = float(self.gia)/float(Part.totalgia)
def __repr__(self):
return "gia: %0.1f giaratio: %0.2f" % (self.gia, self.giaratio)

if __name__ == '__main__':
p1 = Part(20)
p2 = Part(30)
for p in p1, p2:
p.addavgbm()
print p

totalgia keeps incrementing when this code is used under mod_python.
And also when used outside of mod_python. It is because it is a class level
variable. In fact I think under certain circumstances in mod_python it will
not do that because different requests can run in different Apache
processes (on Linux, Unix, Mac OS X etc.). So it this desired behaviour or
not? Your post isn't clear about that. And if it isn't what is the desired
behaviour?

And you certainly should do something about the concurrent access.

It is not desirable for the class variable to keep incrementing outside
of invocations of '__main__', as is the case when it is loaded under
mod_python under apache2 on linux.

I would be grateful for pointers on dealing with concurrent access.

Regards
Rory
 
G

greg

Rory said:
class Part (object):
totalgia = 0
def __init__(self, gia):
self.gia = gia # gross internal area
self.giaratio = 0
Part.totalgia += self.gia
>
if __name__ == '__main__':
p1 = Part(20)
p2 = Part(30)
for p in p1, p2:
p.addavgbm()
print p

You need another class, such as PartGroup, to keep track of
the totalgia of a group of parts (as an instance variable, not
a class variable). Then you can create a new instance of it
in your __main__ code, e.g.

class PartGroup(object):

def __init__(self):
self.parts = []
self.totalgia = 0

class Part(object):

def __init__(self, group, gia):
self.gia = gia
group.parts.append(self)
group.gia += gia

if __name__ == "__main__":
parts = PartGroup()
p1 = Part(parts, 10)
p2 = Part(parts, 20)
print parts.totalgia

A possible variation would be not to store the totalgia at
all, but have a function or method that calculates it from
the list of parts when you need it. Whether that's better or
not will depend on how frequently you need the value.
 
D

Diez B. Roggisch

It is not desirable for the class variable to keep incrementing outside
of invocations of '__main__', as is the case when it is loaded under
mod_python under apache2 on linux.

I'm still not clear on what you want to accomplish. In the end it boils down
to who is supposed to share that information in the variables, or in other
words: which scope has it.

Is it per request? Then using some thread-local storage would be in order,
or "abusing" a possible request-object.

Is it per user, over several requests? Then you need a session-mechanism.

Is it per application, for several users, over several requests? Then your
approach is ok, but needs guarding against concurrrent access using
threading.Lock for example. However, I presume that is not the desired
usecase, from what I can extract from your posts I presume it's case two.

Diez
 
R

Rory Campbell-Lange

I'm still not clear on what you want to accomplish. In the end it boils down
to who is supposed to share that information in the variables, or in other
words: which scope has it.

Is it per request? Then using some thread-local storage would be in order,
or "abusing" a possible request-object.

Is it per user, over several requests? Then you need a session-mechanism.

Is it per application, for several users, over several requests? Then your
approach is ok, but needs guarding against concurrrent access using
threading.Lock for example. However, I presume that is not the desired
usecase, from what I can extract from your posts I presume it's case two.

Many thanks for your reply. The use case is per request, and I would be
grateful to learn more about thread-local storage.

Kind regards
Rory
 
D

Diez B. Roggisch

Many thanks for your reply. The use case is per request, and I would be
grateful to learn more about thread-local storage.

There are several ways. I'm not familiar with mod_python, but I guess you
get a dict-like object for the request parameters. In python, this is
usually writable (in contrast to the darn J2EE-spec'ed HttpRequest)

So just add a new key, e.g. "working_state", to it. Under that, file those
variables.

Alternatively, there are recipes out there
(http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302088
)

that give you basically a dictionary keyed with the current thread.

That is helpful if you have computations deeper in code that can't get a
hold on the request object. Might be the case in mod_python - in cherrypy,
the request itself is thread-locally stored, so you can get it whereever
you need.

Diez
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top