A bundle of questions from a Python newbie
Hans Nowak
wurmy at earthlink.net
Wed Feb 20 23:42:30 EST 2002
"Gonçalo Rodrigues" wrote:
> 1. The way I thought that an assignment like
>
> var += 1
>
> worked was that the interpreter would go to the place pointed by var and
> add 1. In particular, id(var) should remain constant. But this is not
> what happens as a simple test shows it. So what is wrong in my
> perception of what += does? Is this an implemetation issue?
There is no "place pointed by var". Python is a bit different than most
languages in this respect. An "assignment" like
x = 1
creates an integer object with value 1, then attaches the name
'x' to it in the current namespace. In, say, a Pascal tutorial,
you will learn that a variable refers to a reserved place in
memory, and various values can be written to that place. Not
so in Python. When you do
x = 2
later, the same thing happens: integer object with value 2
is created, and the name 'x' is associated with it. Since
this is a new integer, id(x) will have a different value
than before. (The original integer with value 1 may, or
may not, still exist, but 'x' isn't associated with it
anymore.)
Now += is a bit of a different issue, because in the
case of mutable objects, it's capable of changing the
object in-place. Take a list, for example:
>>> a = [1, 2, 3]
>>> id(a)
9586800
>>> a += [4]
>>> a
[1, 2, 3, 4]
>>> id(a)
9586800
a has the same id before and after the +=. This is
different from the = operator, that always (re)binds
to a new name:
>>> a = a + [5]
>>> a
[1, 2, 3, 4, 5]
>>> id(a)
9902208
+= has the same behavior for immutable objects, like
integers and strings:
>>> x = 1
>>> id(x)
7626688
>>> x += 2
>>> x
3
>>> id(x)
7626496
By now you probably think, what the hell is the guy
talking about?! :-) See this document for a clear and
concise description of how Python's object and
name binding mechanism works:
http://www.effbot.org/guides/python-objects.htm
> 2. What is the idea of having in the loop
>
> for var in range(10):
> pass
>
> the var variable still available after it? Wasn't it supposed to die (as
> in being out of scope) when the loop ends?
This is not uncommon in other languages either, if I recall
correctly. Either way, no, it's not out of scope. It only
goes out of scope if the current function/method/class body
ends.
> 3. This is not a question just a small complaint. I really miss the
> do-until control flow in Python. I always have to waste some extra brain
> cycles to convert it to the while 1, etc. idiom. Hey, we all have a
> right to our complaints, right? ;-)
This one comes up every once in a while. The usual reply is that a
do-while construction can easily be mimicked using a while. Your
mileage may vary, but it's probably pointless to argue for this
feature on c.l.py, unless you like long flamewars. ;-)
> 6. Is there a reason why 3.__abs__() does not work? After all 3 is an
> object (in the wider sense of the word). And it does work if we assign
> it to a variable, eg,
>
> var = 3
> var.__abs__()
>
> I know that code like the above (methods applied to number literals) is
> probably rare, but consistence is also a good thing.
I believe this is something of a parsing issue. Not sure, though.
Either way, I don't think there are many people that want to write
3.__abs__...
> 9. What would be better in terms of speed?
>
> for i in range(<whatever>):
> <whatever>
>
> Or to code an iterator like
>
> from __future__ import generators
>
> class Range:
> def __init__(self, end, start = 0, step = 1):
> self.end = end
> self.start = start
> self.step = step
>
> def __iter__(self):
> i = self.start
> while i < self.end:
> yield i
> i += self.step
>
> and then use it in the for loop.
I'd say that normally it's fastest to loop over the
list. Iterators and generators are useful when you have
a possibly really long list that you don't want to have
in memory all at once. AFAIK, they're not faster than
looping over a sequence. I didn't test this though.
c.l.py has some incorrigible benchmarkers who could
prove me wrong... ;-)
> 10. I have a class that works like a list in the sense that supports the
> method __getitem__ and its relatives. But I'm at a loss as to what I
> have to do to support the slice notation.
__getitem__(self, x) will be called with a so-called slice
object if you call your instance with the slice notation.
Example:
>>> import types
>>> class Foo:
def __init__(self, x):
self.data = x
def __getitem__(self, x):
if type(x) == types.IntType:
return self.data[x]
elif type(x) == types.SliceType:
return self.data[x.start:x.stop]
else:
raise IndexError
>>> f = Foo(range(10))
>>> f[1]
1
>>> f[:2]
[0, 1]
HTH,
--
Hans (base64.decodestring('d3VybXlAZWFydGhsaW5rLm5ldA=='))
# decode for email address ;-)
The Pythonic Quarter:: http://www.awaretek.com/nowak/
More information about the Python-list
mailing list