Mailing List Archive

Pointers to variables
This doesn't work:


for ( var, str ) in [( self.min, 'min_units' ),
( self.max, 'max_units' )]:
if cnf.has_key( str ):
var = cnf[ str ]
del cnf[ str ]


It doesn't assign values to self.min, self.max (both integers). The values
of these variables are inserted into the tuples and not references to the
variables themselves, which is the problem.

How can I cause a reference to the variables to be stored in the tuples
instead of their values?

Thanks,

Randall
Pointers to variables [ In reply to ]
Randall Hopper <aa8vb@vislab.epa.gov> writes:

| This doesn't work:
|
| for ( var, str ) in [( self.min, 'min_units' ),
| ( self.max, 'max_units' )]:
| if cnf.has_key( str ):
| var = cnf[ str ]
| del cnf[ str ]
|
| It doesn't assign values to self.min, self.max (both integers). The
| values of these variables are inserted into the tuples and not
| references to the variables themselves, which is the problem.
|
| How can I cause a reference to the variables to be stored in the
| tuples instead of their values?

Here's how I would do it:

for ( varname, str ) in [( 'min', 'min_units' ),
( 'max', 'max_units' )]:
if cnf.has_key( str ):
setattr (self, varname, cnf[ str ])
del cnf[ str ]

I don't think this is really any slower than what you wanted to do,
since Python was doing namespace lookups on 'min' and 'max' before
anyway.

If min and max were mutable objects, a variation of your approach
would probably work, if there were a method to change them in-place
(e.g., "var.set_me (cnf[str])"). "var = cnf[str]" is never going to
do what you want, since it just makes the name 'var' point to a
different object (that's what assignment means in Python).

I've just been using Python for a week, so take my answer with a grain
of salt...

--
Dan Schmidt -> dfan@harmonixmusic.com, dfan@alum.mit.edu
Honest Bob & the http://www2.thecia.net/users/dfan/
Factory-to-Dealer Incentives -> http://www2.thecia.net/users/dfan/hbob/
Gamelan Galak Tika -> http://web.mit.edu/galak-tika/www/
Pointers to variables [ In reply to ]
Randall Hopper wrote:
>
> This doesn't work:
>
> for ( var, str ) in [( self.min, 'min_units' ),
> ( self.max, 'max_units' )]:
> if cnf.has_key( str ):
> var = cnf[ str ]
> del cnf[ str ]
>
> It doesn't assign values to self.min, self.max (both integers). The values
> of these variables are inserted into the tuples and not references to the
> variables themselves, which is the problem.
>
> How can I cause a reference to the variables to be stored in the tuples
> instead of their values?

Hi there,

I've been trying to understand the purpose of the code in your fragment
and your question for a minute or so, but I'm not entirely sure I get it
yet.

I'm assuming what you want is to get 'cnf[str]' assigned to self.min or
self.max.

What you could do is something like this:

for str in ('min_units', 'max_units'):
if cnf.has_key(str):
setattr(self, str, cnf[str])
del cnf[str]

Tuples, by the way are immutable, so you can't change what values their
elements point to after they've been created (though if these values
point to other things themselves you can change that). That is, you
can't do this:

foo = (value1, value2)
foo[0] = "hey"

But, if you'd use a mutable list, you still run into trouble. If you say
this:

mylist = [None] # list with a single element
None
variable_i_want_to_change = "Foo" # a variable I want to
change
mylist[0] = variable_i_want_to_change # okay, mylist[0] points to
same data
mylist[0] = "Bar" # now mylist[0] points to
different data

then 'variable_i_want_to_change' won't change. You've simply changed
what value mylist[0] points at. This is because a string (and integers
etc) are immutable values in Python. If you use a mutable value such as
a dictionary, you get this:

mylist = [None]
variable_i_want_to_change = {}
mylist[0] = variable_i_want_to_change
mylist[0]["some key"] = "bar" # indeed changes
variable_i_want_to_change!
# mylist[0] = "Bar" -- doesn't work, makes mylist[0] point elsewhere

I suspect I'm making things sound horribly complicated when they aren't
really. I can keep all this in my head easily, it's just hard
communicating it. I can understand the confusion with pointers from C,
but note that this is the actual semi-equivalent C code (of the first
fragment, not the dict one, and using ints instead of strings):

/* Initialize the variables, assume easy allocate functions which do all
the
malloc() calls I don't want to figure out right now */
int** mylist = allocate_list();
*mylist[0] = 0;
/* now we have a list with a pointer to an int value, which is 0 */

int* variable_i_want_to_change = allocate_int();
*variable_i_want_to_change = 1;
/* now we have a variable which points to an int value, which is 1 */

*mylist[0] = *variable_i_want_to_change;
/* now the data mylist[0] points at becomes 1 too */

*mylist[0] = 2;
/* now the data mylist[0] points at becomes 2 */

/* has the data *variable_i_want_to_change changed? no. I hope! :)*/

I don't expect this explained a lot. I feel like Tim Peters somehow...
:)

Regards,

Martijn
Pointers to variables [ In reply to ]
Randall Hopper wrote in message <19990422121403.A279051@vislab.epa.gov>...
[snip]
> How can I cause a reference to the variables to be stored in the tuples
instead of their values?

You can't, or at least not directly. What you *can* do, in the case you
provided, is something like this:

for ( attrname, k ) in [( 'min', 'min_units' ), ( 'max', 'max_units' )]:
if cnf.has_key( k ):
setattr(self, attrname, cnf[ str ])
del cnf[ str ]

Python simply doesn't *have* variables in the sense you're thinking of, with
the exception of function-local variables. Instead it has namespaces, such
as modules, classes, and instances. These can be usefully be thought of as
dictionaries with efficient string-only keys, and can be manipulated as such
using getattr, setattr, delattr, etc.

Function-local-variables-are-a-whole-nother-alien-world-ly yrs,
Evan Simpson
Pointers to variables [ In reply to ]
Randall Hopper wrote:
>
> This doesn't work:
>
> for ( var, str ) in [( self.min, 'min_units' ),
> ( self.max, 'max_units' )]:
> if cnf.has_key( str ):
> var = cnf[ str ]
> del cnf[ str ]
>
> It doesn't assign values to self.min, self.max (both integers). The values
> of these variables are inserted into the tuples and not references to the
> variables themselves, which is the problem.
>
> How can I cause a reference to the variables to be stored in the tuples
> instead of their values?

There is simply no direct way to use references. You need
to use an object which itself has a reference.

One way to achive the wanted effect is to use setattr, while
paying some speed penalty, of course:

for ( var, str ) in [( 'min', 'min_units' ),
( 'max', 'max_units' )]:
if cnf.has_key( str ):
setattr(self, var, cnf[ str ])
del cnf[ str ]

ciao - chris

--
Christian Tismer :^) <mailto:tismer@appliedbiometrics.com>
Applied Biometrics GmbH : Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101 : *Starship* http://starship.python.net
10553 Berlin : PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF
we're tired of banana software - shipped green, ripens at home
Pointers to variables [ In reply to ]
Thanks for the replies and suggestions to use setattr to set variables
by name.

I think I understand the source of my confusion. This construct:

for ( var, val ) in [( min, 1 ), ( max, 100 )]:

isn't pairwise assignment to all the values of the list. If it were, val
would be an alias for the variable min, then an alias for max, etc.

This actually builds a completely new list:

[( valueof(min), 1 ), ( valueof(max), 100 )]

in memory first, which is then iterated over. This is why my original
example didn't work.

Also, the "valueof()" relation for some types in python (apparently)
is a reference rather than a value (lists, objects, etc.) which explains
why these examples work:

(1) min = [ 0 ]
max = [ 0 ]

for ( var, val ) in [( min, 1 ), ( max, 100 )]:
var[0] = val

(2) class Val:
def __init__( self, num ):
self.num = num

min = Val(0)
max = Val(0)

for ( var, val ) in [( min, 1 ), ( max, 100 )]:
var.num = val

but this one doesn't:

(3) min = 0
max = 0
for ( var, val ) in [( min, 1 ), ( max, 100 )]:
var = val

So basically this is just a little asymmetry in the language. Putting a
variable in a list/tuple (valueof(var)) performs a shallow copy rather than
a deep copy.

Does this sound about right?

Randall
Pointers to variables [ In reply to ]
Randall Hopper wrote:
...
[you are beginning to understand the concept]
...
> but this one doesn't:
>
> (3) min = 0
> max = 0
> for ( var, val ) in [( min, 1 ), ( max, 100 )]:
> var = val
>
> So basically this is just a little asymmetry in the language. Putting a
> variable in a list/tuple (valueof(var)) performs a shallow copy rather than
> a deep copy.
>
> Does this sound about right?

Not completely. There is no asymmetry if you take the right
position. I'll try to adjust jour sight a little :-)

There is sometimes a little confusion since people talk
of Python, passing "variables" by "reference", which is
wrong. Python passes objects by reference, but no variables
at all, in the sense of a "C" variable.
(You might find some more about this in the tutor archive).

It is better to think of labels, sticked to boxes which
are the objects.
By "min = 0", you stick the label "min" to the object "0".
By "var = val", you pick the object which has the label
"val", and stick label "var" to it as well.

While passign the values around between the lables, Python
indeed uses reverences to the objects, although in this
example, it makes no difference, since the values of
unchangeable (immutable) objects like numbers cannot be changed.

You will recognze the difference, if you use different objects
like lists. In

a = [1, 2, 3]

I've put a label "a" to a list object with three numbers.
Now I can use a as a handle to the list, it gives me a reference
to the object which I now can change, like

a[1] = "howdy", which reads now

>>> a
[1, 'howdy', 3]
>>>

Now you will understand that I did not change the "variable a".
I also did not change the "label a", but I modified the list
object where a was my handle.

while 1:
if vanished("asymmetry"):
break
think_again() #:-)

Hope this helps - chris

--
Christian Tismer :^) <mailto:tismer@appliedbiometrics.com>
Applied Biometrics GmbH : Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101 : *Starship* http://starship.python.net
10553 Berlin : PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint E182 71C7 1A9D 66E9 9D15 D3CC D4D7 93E2 1FAE F6DF
we're tired of banana software - shipped green, ripens at home
Pointers to variables [ In reply to ]
Fredrik Lundh:
|> but this one doesn't:
|>
|> (3) min = 0
|> max = 0
|> for ( var, val ) in [( min, 1 ), ( max, 100 )]:
|> var = val
|
|here, you tell python to change the binding for the name "var"
|in the local name space so it points to the same thing as the
|name "val".

Ahh (light bulb goes on). Makes sense. I should have seen that (need my
morning caffeine).

When the "for" iterates, var is really an alias for min and max's storage
-- what you want. But the problem is you can't "change" the value of
storage with assignment to var (that just rebinds var).

And Python being "pointerless" there is no:

*var = val
or:
memcpy( var, val, sizeof(*var) )

-like construct. So you have to resort to other means (setattr).

|> So basically this is just a little asymmetry in the language. Putting a
|> variable in a list/tuple (valueof(var)) performs a shallow copy rather than
|> a deep copy.
|
|nope. content is never copied. only references. all the time.
|perfect symmetry.

Thanks.

Randall
Pointers to variables [ In reply to ]
Randall Hopper wrote:
> I think I understand the source of my confusion. This construct:
>
> for ( var, val ) in [( min, 1 ), ( max, 100 )]:
>
> isn't pairwise assignment to all the values of the list. If it were, val
> would be an alias for the variable min, then an alias for max, etc.

but that's exactly what it is. read on!

> This actually builds a completely new list:
>
> [( valueof(min), 1 ), ( valueof(max), 100 )]
>
> in memory first, which is then iterated over. This is why my original
> example didn't work.

nope. that's not the reason. read on!

> Also, the "valueof()" relation for some types in python (apparently)
> is a reference rather than a value (lists, objects, etc.) which explains
> why these examples work:

*EVERYTHING* is a reference. a pointer. a memory address.
or whatever term you prefer.

> (1) min = [ 0 ]
> max = [ 0 ]
>
> for ( var, val ) in [( min, 1 ), ( max, 100 )]:
> var[0] = val

here, you modify the object in place (through the reference),
by assigning to a list slot.

corresponding C-ish code:

varPtr->setitem(0, valPtr);

> (2) class Val:
> def __init__( self, num ):
> self.num = num
>
> min = Val(0)
> max = Val(0)
>
> for ( var, val ) in [( min, 1 ), ( max, 100 )]:
> var.num = val

here, you modify the "var" object in place by
setting an attribute.

corresponding C-ish code:

varPtr->setmember("num", valPtr);

> but this one doesn't:
>
> (3) min = 0
> max = 0
> for ( var, val ) in [( min, 1 ), ( max, 100 )]:
> var = val

here, you tell python to change the binding for the name "var"
in the local name space so it points to the same thing as the
name "val".

corresponding C-ish code:

varPtr = valPtr;

or rather:

setlocalname("var", valPtr);

> So basically this is just a little asymmetry in the language. Putting a
> variable in a list/tuple (valueof(var)) performs a shallow copy rather than
> a deep copy.

nope. content is never copied. only references. all the time.
perfect symmetry.

</F>
Pointers to variables [ In reply to ]
In article <371F6124.48EA9794@pop.vet.uu.nl>,
Martijn Faassen <M.Faassen@vet.uu.nl> wrote:
>But, if you'd use a mutable list, you still run into trouble. If you say
>this:
>
> mylist = [None] # list with a single element
>None
> variable_i_want_to_change = "Foo" # a variable I want to
>change
> mylist[0] = variable_i_want_to_change # okay, mylist[0] points to
>same data
> mylist[0] = "Bar" # now mylist[0] points to
>different data
>
>then 'variable_i_want_to_change' won't change. You've simply changed
>what value mylist[0] points at. This is because a string (and integers
>etc) are immutable values in Python. If you use a mutable value such as
>a dictionary, you get this:

I don't think it has anything to do with mutable or not. mylist[0]
simply points (at first) to the same object (string) that
variable_i_want_to_change (hereafter called 'var2chg'). Then,
at the second assignment, mylist[0] points to something different.
If var2chg were an array or dictionary, it would make no difference;
mylist[0] would still, after the second assignment, be "Bar".


> mylist = [None]
> variable_i_want_to_change = {}
> mylist[0] = variable_i_want_to_change
> mylist[0]["some key"] = "bar" # indeed changes
>variable_i_want_to_change!

This is different from the other examples. Here, you dereference
mylist[0] (which is still pointing to the same object that var2chg
points to). So the common object that they both point to changes.
Strictly speaking, you aren't changing var2chg, just that which it
(and mylist[0]) points to.


> # mylist[0] = "Bar" -- doesn't work, makes mylist[0] point elsewhere

Well, it works as expected. It changes mylist[0], not what mylist[0]
references.


>I suspect I'm making things sound horribly complicated when they aren't
>really. I can keep all this in my head easily, it's just hard
>communicating it. I can understand the confusion with pointers from C,
>but note that this is the actual semi-equivalent C code (of the first
>fragment, not the dict one, and using ints instead of strings):
>
>/* Initialize the variables, assume easy allocate functions which do all
>the
> malloc() calls I don't want to figure out right now */
>int** mylist = allocate_list();
>*mylist[0] = 0;
>/* now we have a list with a pointer to an int value, which is 0 */
>
>int* variable_i_want_to_change = allocate_int();
>*variable_i_want_to_change = 1;
>/* now we have a variable which points to an int value, which is 1 */
>
>*mylist[0] = *variable_i_want_to_change;
>/* now the data mylist[0] points at becomes 1 too */
>
>*mylist[0] = 2;
>/* now the data mylist[0] points at becomes 2 */

I wonder if this is how it goes. I've not dived into the python
engine code, so I don't know. Are immutable objects stored as
objects or just as the data? In the grand scheme of things, it
really makes no difference. If there were an "add" method for
ints (so you could say:

var2chg = 5
var2chg.add(3)

and have var2chg have a value of 8), then it would obviously be
a concern. But you can't, so it really doesn't matter at the
python level whether:

a = 5
b = a

means that b and a point to the same object, or to separate
values of 5. If you could do b.add(3) and suddenly have a
with a value of 8, then it would.

Michael
Pointers to variables [ In reply to ]
Michael Vezie wrote:
>
> In article <371F6124.48EA9794@pop.vet.uu.nl>,
> Martijn Faassen <M.Faassen@vet.uu.nl> wrote:
[snip my code example]
>
> I don't think it has anything to do with mutable or not. mylist[0]
> simply points (at first) to the same object (string) that
> variable_i_want_to_change (hereafter called 'var2chg'). Then,
> at the second assignment, mylist[0] points to something different.
> If var2chg were an array or dictionary, it would make no difference;
> mylist[0] would still, after the second assignment, be "Bar".

I know this; I probably made it sound too horribly complicated.

> > mylist = [None]
> > variable_i_want_to_change = {}
> > mylist[0] = variable_i_want_to_change
> > mylist[0]["some key"] = "bar" # indeed changes
> >variable_i_want_to_change!
>
> This is different from the other examples. Here, you dereference
> mylist[0] (which is still pointing to the same object that var2chg
> points to). So the common object that they both point to changes.
> Strictly speaking, you aren't changing var2chg, just that which it
> (and mylist[0]) points to.

Yes, that's because everything in Python is a reference. But in case of
immutable objects this is identical to value semantics, unless you use a
tuple which contains a mutable object in itself.

> > # mylist[0] = "Bar" -- doesn't work, makes mylist[0] point elsewhere
>
> Well, it works as expected. It changes mylist[0], not what mylist[0]
> references.

If you know you're dealing with references and that assignment only
changes what variable references what data, yes. I was attempting to
explain the implications of this, but I admit it was horribly
convoluted. :)

[snip my atrocious C code]

> I wonder if this is how it goes. I've not dived into the python
> engine code, so I don't know. Are immutable objects stored as
> objects or just as the data?

I haven't dived in the Python code either, but I've seen people talk
about Python allocating an object for either integer, so I imagine yes.

> In the grand scheme of things, it
> really makes no difference. If there were an "add" method for
> ints (so you could say:
>
> var2chg = 5
> var2chg.add(3)
>
> and have var2chg have a value of 8), then it would obviously be
> a concern. But you can't, so it really doesn't matter at the
> python level whether:
>
> a = 5
> b = a
>
> means that b and a point to the same object, or to separate
> values of 5. If you could do b.add(3) and suddenly have a
> with a value of 8, then it would.

Yes, unless you deal with tuples, which are immutable, but can contain
mutable things:

a = { "mutable" : "Yes" }
b = (a, "foo")
c = b
c["mutable"] = "really"
# b is changed at this point too, even though the tuple was immutable

This was pointed out to me on the Python tutor list after I pointed out
that reference vs value semantics is the same in case of immutable
objects. It's only the same in case they're deeply immutable (or if you
exclude tuples).

Anyway, I was trying to attempt to explain the same principles as you
did; I just wasn't very succesful at it. :)

Regards,

Martijn