python newbie - question about lexical scoping

M

Matt Barnicle

hi everyone.. i've been chugging along learning python for a few months
now and getting answers to all needed questions on my own, but this one
i can't figure out nor can i find information on the internet about it,
possibly because i don't understand the right words to type into google..

i have a very common scenario and need to know the python way to do it.
take this example loop:

comments = []
for row in rows:
comment = models.comment()
comment.author = row[1]
comment.text = row[0]
comments.append(comment)

the problem is that when i go to retrieve the comments later, they are
all the same object! i assume this is due to there being no lexical
scoping? so what is the solution to this?

thank u all!

- m@
 
J

John Machin

hi everyone.. i've been chugging along learning python for a few months
now and getting answers to all needed questions on my own, but this one
i can't figure out nor can i find information on the internet about it,
possibly because i don't understand the right words to type into google..

i have a very common scenario and need to know the python way to do it.
take this example loop:

comments = []
for row in rows:
comment = models.comment()

Insert here:
print type(comment), id(comment), repr(row[:2])
comment.author = row[1]
comment.text = row[0]
comments.append(comment)

the problem is that when i go to retrieve the comments later, they are
all the same object! i assume this is due to there being no lexical
scoping? so what is the solution to this?

And the attributes of the "same object" match the first two elements
of which input row:
(a) rows[0]
(b) rows[-1]
(c) some other row
(d) you can't tell because all input rows have the same value in each
of row[0] and row[1]
(e) none of the above?

It's nothing to do with lexical scoping, at least in the code that
you've shown us, which has no apparent problems. You need to show us
the code for the models.comment function/method/class. Possibly it is
returning the same object each time it is invoked (answer (b) above);
the above print statement will help investigate that possibility, plus
the possibility that the objects are not the same objects, but are
different objects with the same attributes (answer (d) above). Also
show us the code for retrieving the comments later; possibly you are
retrieving the same element of the comments list each time. Use this:
print [id(x) for x in comments]
to verify your assertion that they are all the same object.

Cheers,
John
 
M

Matt Barnicle

hi everyone.. i've been chugging along learning python for a few months
now and getting answers to all needed questions on my own, but this one
i can't figure out nor can i find information on the internet about it,
possibly because i don't understand the right words to type into
google..

i have a very common scenario and need to know the python way to do it.
take this example loop:

comments = []
for row in rows:
comment = models.comment()

Insert here:
print type(comment), id(comment), repr(row[:2])
comment.author = row[1]
comment.text = row[0]
comments.append(comment)

the problem is that when i go to retrieve the comments later, they are
all the same object! i assume this is due to there being no lexical
scoping? so what is the solution to this?

And the attributes of the "same object" match the first two elements
of which input row:
(a) rows[0]
(b) rows[-1]
(c) some other row
(d) you can't tell because all input rows have the same value in each
of row[0] and row[1]
(e) none of the above?

It's nothing to do with lexical scoping, at least in the code that
you've shown us, which has no apparent problems. You need to show us
the code for the models.comment function/method/class. Possibly it is
returning the same object each time it is invoked (answer (b) above);
the above print statement will help investigate that possibility, plus
the possibility that the objects are not the same objects, but are
different objects with the same attributes (answer (d) above). Also
show us the code for retrieving the comments later; possibly you are
retrieving the same element of the comments list each time. Use this:
print [id(x) for x in comments]
to verify your assertion that they are all the same object.

Cheers,
John

aye yaye aye... thanks for the pointers in the right direction.. i
fiddled around with the code for a while and now i've reduced it to the
*real* issue... i have a class dict variable that apparently holds its
value across instantiations of new objects.. the problem can be
illustrated in the following much simpler code:
.... bar = { 'baz': 'bing' }
....
a = foo()
a.bar {'baz': 'bing'}
a.bar['baz'] = 'bong'
a.bar {'baz': 'bong'}
b = foo()
b.bar
{'baz': 'bong'}
 
M

Matt Barnicle

hi everyone.. i've been chugging along learning python for a few months
now and getting answers to all needed questions on my own, but this one
i can't figure out nor can i find information on the internet about it,
possibly because i don't understand the right words to type into
google..

i have a very common scenario and need to know the python way to do it.
take this example loop:

comments = []
for row in rows:
comment = models.comment()

Insert here:
print type(comment), id(comment), repr(row[:2])
comment.author = row[1]
comment.text = row[0]
comments.append(comment)

the problem is that when i go to retrieve the comments later, they are
all the same object! i assume this is due to there being no lexical
scoping? so what is the solution to this?

And the attributes of the "same object" match the first two elements
of which input row:
(a) rows[0]
(b) rows[-1]
(c) some other row
(d) you can't tell because all input rows have the same value in each
of row[0] and row[1]
(e) none of the above?

It's nothing to do with lexical scoping, at least in the code that
you've shown us, which has no apparent problems. You need to show us
the code for the models.comment function/method/class. Possibly it is
returning the same object each time it is invoked (answer (b) above);
the above print statement will help investigate that possibility, plus
the possibility that the objects are not the same objects, but are
different objects with the same attributes (answer (d) above). Also
show us the code for retrieving the comments later; possibly you are
retrieving the same element of the comments list each time. Use this:
print [id(x) for x in comments]
to verify your assertion that they are all the same object.

Cheers,
John

aye yaye aye... thanks for the pointers in the right direction.. i
fiddled around with the code for a while and now i've reduced it to the
*real* issue... i have a class dict variable that apparently holds its
value across instantiations of new objects.. the problem can be
illustrated in the following much simpler code:
.... bar = { 'baz': 'bing' }
....
a = foo()
a.bar {'baz': 'bing'}
a.bar['baz'] = 'bong'
a.bar {'baz': 'bong'}
b = foo()
b.bar
{'baz': 'bong'}
 
T

Tim Roberts

Matt Barnicle said:
hi everyone.. i've been chugging along learning python for a few months
now and getting answers to all needed questions on my own, but this one
i can't figure out nor can i find information on the internet about it,
possibly because i don't understand the right words to type into google..

i have a very common scenario and need to know the python way to do it.
take this example loop:

comments = []
for row in rows:
comment = models.comment()
comment.author = row[1]
comment.text = row[0]
comments.append(comment)

the problem is that when i go to retrieve the comments later, they are
all the same object! i assume this is due to there being no lexical
scoping? so what is the solution to this?

Is that REALLY what the code looks like? Or does it actually look like
this:

comments = []
comment = models.comment()
for row in rows:
comment.author = row[1]
comment.text = row[0]
comments.append(comment)

That construct would produce exactly the result you describe. You would
also get the result you describe if models.comment() were a normal function
that returns a single object, instead of a class name, as I have assumed.
 
M

Matt Barnicle

aye yaye aye... thanks for the pointers in the right direction.. i
fiddled around with the code for a while and now i've reduced it to the
*real* issue... i have a class dict variable that apparently holds its
value across instantiations of new objects.. the problem can be
illustrated in the following much simpler code:
... bar = { 'baz': 'bing' }
...
a = foo()
a.bar {'baz': 'bing'}
a.bar['baz'] = 'bong'
a.bar {'baz': 'bong'}
b = foo()
b.bar
{'baz': 'bong'}

ok, i see... python has a concept i'm not accustomed to which i found
described here:

http://zephyrfalcon.org/labs/python_pitfalls.html
4. Class attributes vs instance attributes

so i'm sure what is going on is obvious to experienced python
programmers... i'm not really sure how to get around this though. i'll
need to spend some time on reworking our models code i guess... i
inherited this from someone, and what he was trying to do was to set
default values for objects representing tables (in kind of a simple ORM
layer) and storing the values in a dict, and when the object is
instantiated, the table is queried and the default dict values are
overwritten. so obviously this method is not going to work as such..

sorry for the misdirection, i didn't quite understand at first..

- m@
 
M

Matt Barnicle

aye yaye aye... thanks for the pointers in the right direction.. i
fiddled around with the code for a while and now i've reduced it to the
*real* issue... i have a class dict variable that apparently holds its
value across instantiations of new objects.. the problem can be
illustrated in the following much simpler code:
... bar = { 'baz': 'bing' }
...
a = foo()
a.bar {'baz': 'bing'}
a.bar['baz'] = 'bong'
a.bar {'baz': 'bong'}
b = foo()
b.bar
{'baz': 'bong'}

ok, i see... python has a concept i'm not accustomed to which i found
described here:

http://zephyrfalcon.org/labs/python_pitfalls.html
4. Class attributes vs instance attributes

so i'm sure what is going on is obvious to experienced python
programmers... i'm not really sure how to get around this though. i'll
need to spend some time on reworking our models code i guess... i
inherited this from someone, and what he was trying to do was to set
default values for objects representing tables (in kind of a simple ORM
layer) and storing the values in a dict, and when the object is
instantiated, the table is queried and the default dict values are
overwritten. so obviously this method is not going to work as such..

sorry for the misdirection, i didn't quite understand at first..

- m@
 
H

Hrvoje Niksic

Matt Barnicle said:
i have a class dict variable that apparently holds its value across
instantiations of new objects..
[...]
ok, i see... python has a concept i'm not accustomed to

I don't doubt that Python managed to confuse you here, but in this
case there is nothing really unusual or novel in Python's treatment of
class variables. Equivalent Java code would behave exactly the same:

class Foo {
static Map bar = new HashMap();
static {
bar.put("baz", "bing");
}
}

Foo a = new Foo();
a.bar.put("baz", "bong");

Foo b = new Foo();
System.out.println(b.bar.get("baz"));
-> "bong"
so i'm sure what is going on is obvious to experienced python
programmers... i'm not really sure how to get around this though.

Simply do what you'd do in any other OO language: assign a fresh value
to each instance in its constructor:

class Foo(object):
def __init__(self):
self.bar = {'baz': 'bing'}

Now each instance of Foo has a separate "bar" attribute dict which can
be mutated without affecting other instances.
 
B

Bruno Desthuilliers

Matt Barnicle a écrit :
If it's a class attribute, it's indeed shared between all instances...
(snip)
ok, i see... python has a concept i'm not accustomed to which i found
described here:

http://zephyrfalcon.org/labs/python_pitfalls.html
4. Class attributes vs instance attributes

so i'm sure what is going on is obvious to experienced python
programmers... i'm not really sure how to get around this though.

It's not a problem:

class Foo(object):
def __init__(self):
self.bar = {'baz':'bing'}


i'll
need to spend some time on reworking our models code i guess... i
inherited this from someone, and what he was trying to do was to set
default values for objects representing tables (in kind of a simple ORM
layer) and storing the values in a dict, and when the object is
instantiated, the table is queried and the default dict values are
overwritten.

class Foo(object):
bar = {'baz':'bing'}
def __init__(self):
self.bar = self.bar
 
H

hdante

On Dec 1, 4:47 pm, Matt Barnicle <[email protected]> wrote:
aye yaye aye... thanks for the pointers in the right direction.. i
fiddled around with the code for a while and now i've reduced it to the
*real* issue... i have a class dict variable that apparently holds its
value across instantiations of new objects.. the problem can be
illustrated in the following much simpler code:
class foo():
... bar = { 'baz': 'bing' }
...
a = foo()
a.bar {'baz': 'bing'}
a.bar['baz'] = 'bong'
a.bar {'baz': 'bong'}
b = foo()
b.bar
{'baz': 'bong'}

ok, i see... python has a concept i'm not accustomed to which i found
described here:

http://zephyrfalcon.org/labs/python_pitfalls.html
4. Class attributes vs instance attributes

so i'm sure what is going on is obvious to experienced python
programmers... i'm not really sure how to get around this though. i'll
need to spend some time on reworking our models code i guess... i
inherited this from someone, and what he was trying to do was to set
default values for objects representing tables (in kind of a simple ORM
layer) and storing the values in a dict, and when the object is
instantiated, the table is queried and the default dict values are
overwritten. so obviously this method is not going to work as such..

sorry for the misdirection, i didn't quite understand at first..

- m@


A trivial solution:

class foo:
default_bar = { 'baz' : 'bong' }
def __init__(self):
self.bar = self.default_bar.copy()
self.bar['woo'] = 'wee'

Note: it's not necessary to reimplement an ORM. Try using Django (if
you need a complete solution) or Elixir (just the ORM).
 
B

Bruno Desthuilliers

Bruno Desthuilliers a écrit :
(snip)

class Foo(object):
bar = {'baz':'bing'}
def __init__(self):
self.bar = self.bar

Hem... Should re-read before posting :(

It's of course:

def __init__(self):
self.bar = self.bar.copy()
 

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

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,037
Latest member
MozzGuardBugs

Latest Threads

Top