Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to isolate a constant?

36 views
Skip to first unread message

Gnarlodious

unread,
Oct 22, 2011, 8:26:22 PM10/22/11
to
Say this:

class tester():
_someList = [0, 1]
def __call__(self):
someList = self._someList
someList += "X"
return someList

test = tester()

But guess what, every call adds to the variable that I am trying to
copy each time:
test()
> [0, 1, 'X']
test()
> [0, 1, 'X', 'X']


Can someone explain this behavior? And how to prevent a classwide
constant from ever getting changed?

-- Gnarlie

Chris Rebert

unread,
Oct 22, 2011, 8:41:23 PM10/22/11
to Gnarlodious, pytho...@python.org
On Sat, Oct 22, 2011 at 5:26 PM, Gnarlodious <gnarl...@gmail.com> wrote:
> Say this:
>
> class tester():

Style note: either have it explicitly subclass `object`, or don't
include the parens at all. Empty parens for the superclasses is just
weird.

>        _someList = [0, 1]
>        def __call__(self):
>                someList = self._someList
>                someList += "X"
>                return someList
>
> test = tester()
>
> But guess what, every call adds to the variable that I am trying to
> copy each time:
> test()
>> [0, 1, 'X']
> test()
>> [0, 1, 'X', 'X']
>
>
> Can someone explain this behavior?

The line `someList = self._someList` does NOT copy the list. It make
`someList` point to the same existing list object. Hence,
modifications to that object from either variable will affect the
other.
Similarly, `someList += "X"` modifies someList *in-place*; it does not
produce a new list object.

The upshot is that you're just modifying and returning references to
*the same list* repeatedly, never producing a new list object.

> And how to prevent a classwide
> constant from ever getting changed?

Python doesn't have any language-enforced notion of constants. So,
short of writing/using a library to try and enforce such a notion,
you're out of luck. You could use an immutable datatype (e.g. a tuple)
instead of a mutable one (e.g. a list) as some level of safeguard
though.

Cheers,
Chris
--
http://rebertia.com

MRAB

unread,
Oct 22, 2011, 8:46:55 PM10/22/11
to pytho...@python.org
'_someList' is part of the class itself.

This:

someList = self._someList

just creates a new _reference to the list and this:

someList += "X"

appends the items of the sequence "X" to the list.

Note that a string is also a sequence of characters, so:

>>> x = []
>>> x += "XY"
>>> x
['X', 'Y']

Python will copy something only when you tell it to copy. A simple way
of copying a list is to slice it:

someList = self._someList[:]
Message has been deleted

Gnarlodious

unread,
Oct 22, 2011, 9:01:52 PM10/22/11
to
On Oct 22, 6:41 pm, Chris Rebert <c...@rebertia.com> wrote:

> The line `someList = self._someList` does NOT copy the list. It make
> `someList` point to the same existing list object.
Thanks for all those explanations, I've already fixed it with a tuple.
Which is more reliable anyway.

-- Gnarlie

88888 Dihedral

unread,
Oct 23, 2011, 1:12:16 AM10/23/11
to
Thank you for the good trick for a static class owned property. Someone might object this but this is really useful.

Steven D'Aprano

unread,
Oct 23, 2011, 1:32:56 AM10/23/11
to
No, tuples are not "more reliable" than lists. Don't make the mistake of
confusing your inexperience and lack of understanding about Python's
object model for "lists are unreliable". They are completely reliable.
You just have to learn how they work, and not make invalid assumptions
about how they work.

You wouldn't say "Nails are more reliable than screws, because I hammered
a screw into a plaster wall and it just fell out." Of course it fell out:
you used it incorrectly for what you needed.


--
Steven

Paul Rudin

unread,
Oct 23, 2011, 6:23:38 AM10/23/11
to
Gnarlodious <gnarl...@gmail.com> writes:

> Thanks for all those explanations, I've already fixed it with a tuple.
> Which is more reliable anyway.

neither of lists or tuples are "more reliable" than the other. They both
have perfectly well defined behaviour (which can be gleaned from reading
the documentation) and reliably behave as documented. You just have to
choose which fits better for the computation you're trying to implement.


Alan Meyer

unread,
Oct 25, 2011, 3:50:59 PM10/25/11
to
On 10/22/2011 8:46 PM, MRAB wrote:
> On 23/10/2011 01:26, Gnarlodious wrote:
>> Say this:
>>
>> class tester():
>> _someList = [0, 1]
>> def __call__(self):
>> someList = self._someList
>> someList += "X"
>> return someList
>>
>> test = tester()
>>
>> But guess what, every call adds to the variable that I am trying to
>> copy each time:
>> test()
>>> [0, 1, 'X']
>> test()
>>> [0, 1, 'X', 'X']
...
> Python will copy something only when you tell it to copy. A simple way
> of copying a list is to slice it:
>
> someList = self._someList[:]

And another simple way:

...
someList = list(self._someList)
...

Alan

Ian Kelly

unread,
Oct 25, 2011, 4:05:49 PM10/25/11
to pytho...@python.org
On Tue, Oct 25, 2011 at 1:50 PM, Alan Meyer <ame...@yahoo.com> wrote:
>> Python will copy something only when you tell it to copy. A simple way
>> of copying a list is to slice it:
>>
>> someList = self._someList[:]
>
> And another simple way:
>
>    ...
>    someList = list(self._someList)
>    ...

I generally prefer the latter. It's clearer, and it guarantees that
the result will be a list, which is usually what you want in these
situations, rather than whatever unexpected type was passed in.

Cheers,
Ian
Message has been deleted

Ian Kelly

unread,
Oct 25, 2011, 8:30:32 PM10/25/11
to Dennis Lee Bieber, pytho...@python.org
On Tue, Oct 25, 2011 at 6:08 PM, Dennis Lee Bieber
<wlf...@ix.netcom.com> wrote:
> Where's the line form to split those who'd prefer the first vs the
> second result in this sample <G>:
>
>>>> unExpected = "What about a string"
>>>> firstToLast = unExpected[:]

Strings are immutable. That doesn't suffice to copy them, even
assuming you would want to do so in the first place.

>>> unExpected is firstToLast
True

If you find yourself needing to make a copy, that usually means that
you plan on modifying either the original or the copy, which in turn
means that you need a type that supports modification operations,
which usually means a list. If you pass in a string and then copy it
with [:] and then try to modify it, you'll get an exception. If you
don't try to modify it, then you probably didn't need to copy it in
the first place.

Cheers,
Ian

Mel

unread,
Oct 25, 2011, 10:48:12 PM10/25/11
to
Dennis Lee Bieber wrote:

> Where's the line form to split those who'd prefer the first vs the
> second result in this sample <G>:
>
>>>> unExpected = "What about a string"
>>>> firstToLast = unExpected[:]
>>>> repr(firstToLast)
> "'What about a string'"
>>>> explicitList = list(unExpected)
>>>> repr(explicitList)
> "['W', 'h', 'a', 't', ' ', 'a', 'b', 'o', 'u', 't', ' ', 'a', ' ', 's',
> 't', 'r', 'i', 'n', 'g']"
>>>>

Well, as things stand, there's a way to get whichever result you need. The
`list` constructor builds a single list from a single iterable. The list
literal enclosed by `[`, `]` makes a list containing a bunch of items.

Strings being iterable introduces a wrinkle, but `list('abcde')` doesn't
create `['abcde']` just as `list(1)` doesn't create `[1]`.

Mel.

0 new messages