"once" assigment in Python

  • Thread starter Lorenzo Di Gregorio
  • Start date
L

Lorenzo Di Gregorio

Hello,

I've been using Python for some DES simulations because we don't need
full C speed and it's so much faster for writing models. During
coding I find it handy to assign a variable *unless it has been
already assigned*: I've found that this is often referred to as "once"
assigment.

The best I could come up with in Python is:

try:
variable
except NameError:
variable = method()

I wonder if sombody has a solution (trick, whatever ...) which looks
more compact in coding. Something like:

once(variable, method)

doesn't work, but it would be perfect. Of course I can preprocess the
Python code but an all-Python solution would be more handy.

Any suggestions?

Thx in advance,
Lorenzo
 
C

Calvin Spealman

This is one of the things that I often see people trying to do in
Python, where the best solution is simply to understand how Python
works and craft the code to work with the language. The problem, in my
view, is not that you don't have a good way to do this "once
assignment" operation, but that you are in a position where you don't
know if a name has been assigned to or not. Yes, Python is a very
dynamic language, but that doesn't mean you should exploit this to be
so dynamic that you don't know the state of your own code at a given
point.

If you don't know that a name has been assigned to or not, there are
only a few kinds of structures that lead to such a lack of state
knowledge and all of them are avoidable. A common idiom might go along
the lines of:

if A:
B = value

Now, if A is false we might not have B defined at all, turning a
condition into an error (a raised NameError if we try to use B. What
we need to do is either find an alternative value, a default value to
assign before all this, or do everything with the value inside the if
block, and not conditionally create names.

There is no good way to do your "once assignment", and that isn't an
accident. Your code is fragile if you don't know what variables you
have. Depending on the type, there are some good solutions. if the
value cannot be None or if its only numbers, for example, you can do
this:

B = B or value

Now it only changes it if B is None or 0, depending on the case. This
may or may not help you. If you use a default None, you can also just
check for that identity explicitly.
 
L

Lawrence D'Oliveiro

Lorenzo Di said:
During coding I find it handy to assign a variable *unless it has been
already assigned*: I've found that this is often referred to as "once"
assigment.

Why not just assign to it once at the beginning and be done with it?
 
S

Steve Holden

Lorenzo said:
Hello,

I've been using Python for some DES simulations because we don't need
full C speed and it's so much faster for writing models. During
coding I find it handy to assign a variable *unless it has been
already assigned*: I've found that this is often referred to as "once"
assigment.

The best I could come up with in Python is:

try:
variable
except NameError:
variable = method()

I wonder if sombody has a solution (trick, whatever ...) which looks
more compact in coding. Something like:

once(variable, method)

doesn't work, but it would be perfect. Of course I can preprocess the
Python code but an all-Python solution would be more handy.

Any suggestions?
Without being fatuous, I would suggest you rethink your approach to the
problem.

Do your variables have default values? If not, what happens if the user
does not set them and your code tries to refer to them? You seem to be
trying to apply defaults if the user hasn't set a value, when the
correct things to do is to apply the defaults *before the user gets a
chance to do anything at all*. Then any changes made by the user will
overwrite the defaults.

Even better, if its practical, is to provide your functionality as one
or more functions, whose definitions can set default values for keyword
arguments.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden

Sorry, the dog ate my .sigline
 
P

Peter Otten

Lorenzo said:
I've been using Python for some DES simulations because we don't need
full C speed and it's so much faster for writing models. During
coding I find it handy to assign a variable *unless it has been
already assigned*: I've found that this is often referred to as "once"
assigment.

The best I could come up with in Python is:

try:
variable
except NameError:
variable = method()

I wonder if sombody has a solution (trick, whatever ...) which looks
more compact in coding. Something like:

once(variable, method)

doesn't work, but it would be perfect. Of course I can preprocess the
Python code but an all-Python solution would be more handy.

Any suggestions?

You can use properties to implement lazy evaluation. Or you can rely on a
naming convention:
.... def __getattr__(self, name):
.... if name.startswith("_calc_"):
.... raise AttributeError("No method to calculate attribute %r" % name[6:])
.... value = getattr(self, "_calc_" + name)()
.... setattr(self, name, value)
.... return value
.... .... def _calc_foo(self):
.... print "calculating foo"
.... return 42
.... calculating foo
42Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __getattr__
'bar-value'

Peter
 
D

DouhetSukd

Agree that what you are looking for may not be a good idea. So make
sure you don't shoot yourself in the foot with it. You should
probably look into your problem some more.
.... if hasattr(obj,attrname):
.... return
.... else:
.... setattr(obj,attrname,value)
........ pass
........ print "i am m1"
........ print "i am m2"
....
This is very generic code, but you could make it specific to a class
and an attribute. If so look into properties.

class Foo2:

def _setMyAttr(self,value):
if hasattr(self,"_myAttr"):
return
self._myAttr = value

def _getMyAttr(self):
if not hasattr(self,"_myAttr"):
return "somedefaultvalue"
return self._myAttr

myAttr = property(_getMyAttr,_setMyAttr)

Note also : stay away from __setattr__ until you know what you are
doing and
you know when to use self.__dict__ assignments. Painful personal
experiences for me.
 
C

Carl Banks

Hello,

I've been using Python for some DES simulations because we don't need
full C speed and it's so much faster for writing models. During coding
I find it handy to assign a variable *unless it has been already
assigned*: I've found that this is often referred to as "once"
assigment.

I could see reasons for doing something like this at a module level or
for attributes; such as setting default values when defaults are
expensive to calculate. You could, as others have said, initialize the
variable to a trivial value and then test whether it still held the
trivial value later, but what's the point?

The best I could come up with in Python is:

try:
variable
except NameError:
variable = method()

I wonder if sombody has a solution (trick, whatever ...) which looks
more compact in coding. Something like:

once(variable, method)

doesn't work, but it would be perfect.

For module level variables you can do something like this:

def once(symbol,method):
g = globals()
if symbol not in g:
g[symbol] = method()

You'd have to pass a symbol as a string, but that's no big deal.

For local variables you're stuck with trying to catch UnboundLocalError.
There's a way to do it by examining stack frames, but I don't really
recommend it: it's inefficient, and the once assignment doesn't make as
much sense for local variables.



Carl Banks
 
L

Lorenzo Di Gregorio

Thank you very much for your suggestions!
I'll try in the next days to elaborate a bit on the last two ones.

By the way, the "once" assignment is not that evil if you use it for
hardware modeling.
Most hardware models look like:

wire1 = function()
instance component(input=wire1,output=wire2)
result = function(wire2)

When employing Python it's pretty straightforward to translate the
instance to an object.

instance = Component(input=wire1,output=wire2)

Then you don't use "instance" *almost* anymore: it's an object which
gets registered with the simulator kernel and gets called by reference
and event-driven only by the simulator kernel. We might reuse the
name for calling some administrative methods related to the instance
(e.g. for reporting) but that's a pretty safe thing to do. Of course
all this can be done during initialization, but there are some good
reasons (see Verilog vs VHDL) why it's handy do be able to do it
*anywhere*. The annoying problem was that every time the program flow
goes over the assignment, the object gets recreated.

Indeed Python itself is not a hardware modeling language, but I built
some infrastructure to fill what I was missing and for quickly
building up a functional prototype and testing some ideas Python is
really excellent.

Best Regards,
Lorenzo
 
A

Alex Martelli

Lorenzo Di Gregorio said:
When employing Python it's pretty straightforward to translate the
instance to an object.

instance = Component(input=wire1,output=wire2)

Then you don't use "instance" *almost* anymore: it's an object which
gets registered with the simulator kernel and gets called by reference
and event-driven only by the simulator kernel. We might reuse the
name for calling some administrative methods related to the instance
(e.g. for reporting) but that's a pretty safe thing to do. Of course
all this can be done during initialization, but there are some good
reasons (see Verilog vs VHDL) why it's handy do be able to do it
*anywhere*. The annoying problem was that every time the program flow
goes over the assignment, the object gets recreated.

If you originally set, e.g.,

instance = None

then using in your later code:

instance = instance or Component(...)

will stop the multiple creations. Other possibilities include using a
compound name (say an.instance where 'an' is an instance of a suitable
container class) and overriding the __new__ method of class Component so
that it will not return multiple distinct objects with identical
attributes. "Has this *plain* name ever been previously assigned to
anything at all" is simply not a particularly good condition to test for
(you COULD probably write a decorator that ensures that all
uninitialized local variables of a function are instead initialized to
None, but I'd DEFINITELY advise against such "black magic").


Alex
 
L

Larry Bates

Lorenzo said:
Hello,

I've been using Python for some DES simulations because we don't need
full C speed and it's so much faster for writing models. During
coding I find it handy to assign a variable *unless it has been
already assigned*: I've found that this is often referred to as "once"
assigment.

The best I could come up with in Python is:

try:
variable
except NameError:
variable = method()

I wonder if sombody has a solution (trick, whatever ...) which looks
more compact in coding. Something like:

once(variable, method)

doesn't work, but it would be perfect. Of course I can preprocess the
Python code but an all-Python solution would be more handy.

Any suggestions?

Thx in advance,
Lorenzo
IMHO variables like what you describe are really data not program variables.
You might consider putting variables like these in a dictionary and then check
to see if the keys exist before assignment:

var_dict={}

#
# See if 'varname' initialized, if not it needs to be
#
if 'varname' not in var_dict:
var_dict[varname]=somevalue

-Larry
 
L

Lorenzo Di Gregorio

IMHO variables like what you describe are really data not program variables.
You might consider putting variables like these in a dictionary and then check
to see if the keys exist before assignment:

var_dict={}

#
# See if 'varname' initialized, if not it needs to be
#
if 'varname' not in var_dict:
var_dict[varname]=somevalue

This is a good point!

I could write something like:

instantiate('component',function)

and have instantiate() to conditionally do:

instance['component']=Module(function)

Of course this means using:

instance['component'].method()

instead of just:

component.method()

A more annoying difficulty is with the fact that, while the scope of
ordinary variables is limited (function, package), the scope of
'component' would be global (the whole instance[]): having global
names could be pretty annoying in modeling a hierarchy. Anyway, some
scoping mechanism could be implemented over the global dictionary and
this could be a good price to pay to avoid other tricks.
Further suggestions?

Thank you!
Lorenzo
 
S

Steve Holden

Lorenzo said:
IMHO variables like what you describe are really data not program variables.
You might consider putting variables like these in a dictionary and then check
to see if the keys exist before assignment:

var_dict={}

#
# See if 'varname' initialized, if not it needs to be
#
if 'varname' not in var_dict:
var_dict[varname]=somevalue

This is a good point!

I could write something like:

instantiate('component',function)

and have instantiate() to conditionally do:

instance['component']=Module(function)

Of course this means using:

instance['component'].method()

instead of just:

component.method()
Well, you could do that. Or you could define a class, with a __getattr__
that returns the required default value in the case where no setting had
been made.

Then you can assign components (with their own hierarchies) to the
attributes of your top-level design ...
A more annoying difficulty is with the fact that, while the scope of
ordinary variables is limited (function, package), the scope of
'component' would be global (the whole instance[]): having global
names could be pretty annoying in modeling a hierarchy. Anyway, some
scoping mechanism could be implemented over the global dictionary and
this could be a good price to pay to avoid other tricks.
Further suggestions?
It's not actually that hard to create objects that allow you to access
their attributes using *either* attribute or indexing notation.

regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden

Sorry, the dog ate my .sigline
 

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,774
Messages
2,569,599
Members
45,166
Latest member
DollyBff32
Top