[Python-Dev] a feature i'd like to see in python #1: better iteration control

2006-12-03 Thread Ben Wing
many times writing somewhat complex loops over lists i've found the need
to sometimes delete an item from the list.  currently there's no easy
way to do so; basically, you have to write something like

i = 0
while i < len(list):
  el =  list[i]
  ...do something...
  if el should be deleted:
del list[i]
  else:
i += 1

note that you can't write

for x in list:

or even

for i in xrange(len(list)):

note also that you need to do some trickiness to adjust the index
appropriately when deleting.

i'd much rather see something like:

for x:iter in list:
  ...do something...
  if x should be deleted:
iter.delete()

the idea is that you have a way of retrieving both the element itself
and the iterator for the element, so that you can then call methods on
the iterator.  it shouldn't be too hard to implement iter.delete(), as 
well as iter.insert() and similar functions. (the recent changes to the 
generator protocol in 2.5 might help.)

the only question then is how to access the iterator.  the syntax i've 
proposed, with `x:iter', seems fairly logical (note that parallels with 
slice notation, which also uses a colon) and doesn't introduce any new 
operators. (comma is impossible since `for x,iter in list:' already has 
a meaning)

btw someone is probably going to come out and say "why don't you just 
use a list comprehension with an `if' clause?  the problems are [1] i'd
like this to be destructive; [2] i'd like this to work over non-lists
as well, e.g. hash-tables; [3] list comprehensions work well in simple
cases, but in more complicated cases when you may be doing various 
things on each step, and might not know whether you need to delete or 
insert an element until after you've done various other things, a list 
comprehension would not fit naturally; [4] this mechanism is extendible 
to insertions, replacements and other such changes as well as just 
filterings.

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] a feature i'd like to see in python #2: indexing of match objects

2006-12-03 Thread Ben Wing
this one is fairly simple.  if `m' is a match object, i'd like to be
able to write m[1] instead of m.group(1). (similarly, m[:] should return
the same as list(m.groups()).) this would remove some of the verbosity
of regexp code, with probably a net gain in readability; certainly no loss.

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [NPERS] Re: a feature i'd like to see in python #2: indexing of match objects

2006-12-03 Thread Ben Wing


Martin v. Löwis wrote:
> Aahz schrieb:
>   
 this one is fairly simple.  if `m' is a match object, i'd like to be
 able to write m[1] instead of m.group(1). (similarly, m[:] should return
 the same as list(m.groups()).) this would remove some of the verbosity
 of regexp code, with probably a net gain in readability; certainly no loss.
 
>>> Please post a patch to sf.net/projects/python (or its successor).
>>>   
>> Given the list of issues and subsequent discussion so far, I think a PEP
>> will be required.  This needs more documentation than the typical patch.
>> 
>
> I disagree. So far, nobody has spoken against the proposed feature. It's
> really a small addition of a new method to an existing type. Entire
> classes have been added to the standard library without a PEP. People
> can still criticize the patch when its posted (and it's not clear that
> the OP is even willing to produce a patch).
>
>   
i've never worked up a python patch before, but i imagine this wouldn't 
be too hard.

it seems that m[1] should be m.group(1), and everything else should 
follow.  i forgot about m[0] when making my slice proposal; i suppose 
then that m[:] should just do what we expect, and m[1:] = m.groups().  
len(m) = 1 + number of groups, m['name'] = m.group('name').

the only strangeness here is the numbering of groups starting at 1, and 
making 0 be a special case.  this isn't any more (or less) of a problem 
for the indexing form than it is for m.group(), and it's well known from 
various other languages.  we could always consider making groups start 
at 0 for python 3000, but this seems to me like a gratuitous 
incompatibility with the rest of the world.

ben



___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] a feature i'd like to see in python #1: better iteration control

2006-12-03 Thread Ben Wing


Brian Harring wrote:
> On Sun, Dec 03, 2006 at 06:24:17AM -0600, Ben Wing wrote:
>   
>> many times writing somewhat complex loops over lists i've found the need
>> to sometimes delete an item from the list.  currently there's no easy
>> way to do so; basically, you have to write something like
>>
>> i = 0
>> while i < len(list):
>>   el =  list[i]
>>   ...do something...
>>   if el should be deleted:
>> del list[i]
>>   else:
>> i += 1
>>
>> note that you can't write
>>
>> for x in list:
>>
>> or even
>>
>> for i in xrange(len(list)):
>>
>> note also that you need to do some trickiness to adjust the index
>> appropriately when deleting.
>>
>> i'd much rather see something like:
>>
>> for x:iter in list:
>>   ...do something...
>>   if x should be deleted:
>> iter.delete()
>>
>> the idea is that you have a way of retrieving both the element itself
>> and the iterator for the element, so that you can then call methods on
>> the iterator.  it shouldn't be too hard to implement iter.delete(), as 
>> well as iter.insert() and similar functions. (the recent changes to the 
>> generator protocol in 2.5 might help.)
>>
>> the only question then is how to access the iterator.  the syntax i've 
>> proposed, with `x:iter', seems fairly logical (note that parallels with 
>> slice notation, which also uses a colon) and doesn't introduce any new 
>> operators. (comma is impossible since `for x,iter in list:' already has 
>> a meaning)
>>
>> btw someone is probably going to come out and say "why don't you just 
>> use a list comprehension with an `if' clause?  the problems are [1] i'd
>> like this to be destructive; 
>> 
>
> Just use slice assignment.
>
> l = list(xrange(100))
> l2 = [x for x in l if x > 50]
> l[:] = l2[:]
>
>   
>> [2] i'd like this to work over non-lists as well, e.g. hash-tables; 
>> 
>
> There in is the sucky part; iterator protocol is simple; what you're 
> proposing is extending iterators so that they recall the last value 
> (else iter.delete() would not do anything), which... eh.
>
> Think it sucks, to say the least ;)
>
> Simple example of where this gets ugly is in iterating over a file.
>
>   
with some more thought i see that a language extension to `for' isn't 
needed, as you can write something like

it = iter(foo)
for x in it:
  ...

but i still don't see why supporting iter.delete() is so wrong.  clearly 
it doesn't need to work on files or other such things where it doesn't 
make sense.

before you diss this completely, note that java supports exactly the 
same thing:

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Iterator.html


  remove

public void *remove*()

Removes from the underlying collection the last element returned by
the iterator (optional operation). This method can be called only
once per call to next. The behavior of an iterator is unspecified if
the underlying collection is modified while the iteration is in
progress in any way other than by calling this method. 

*Throws:*
|UnsupportedOperationException
<../../java/lang/UnsupportedOperationException.html>| - if the
remove operation is not supported by this Iterator. 
|IllegalStateException
<../../java/lang/IllegalStateException.html>| - if the next
method has not yet been called, or the remove method has already
been called after the last call to the next method.


___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] features i'd like [Python 3000] ... #3: fix super()

2006-12-03 Thread Ben Wing
i don't like the current super() at all.  having to type super(Foo, 
self).__init__(...) is messy, hard to remember, and error-prone.  it 
also introduces an unfortunate dependency in that the name of the class 
(Foo) has to be hard-coded in the call, and if you change the class name 
you also have to go and change all super() calls -- more chances for 
errors.  as a result, i imagine there's a strong urge to just hardcode 
the name of the parent -- a bad idea, and the reason why super() was 
introduced in the first place.

instead, `super' should work like in other languages.  a couple of ideas:

-- super.meth(args) calls the superclass method `meth', in the same way 
that super(Foo, self).meth(args) currently works. (this is the same 
syntax as in java.  this probably requires making `super' be a keyword, 
although it might be possible to hack this by examining the current call 
stack.)
-- as an alternative or in addition, super(args) would work like 
super.meth(args) if we're currently inside of `meth' in a subclass.  i 
suspect that 90% of the time or more, `super' is used to chain to the 
superclass version of an overridden method, and this optimizes for the 
common case.  it makes for one less possibility of misspelling 
`__init__' and one less thing that requires renaming if a method is 
renamed or code copied to another method (granted, this isn't such a big 
deal as in the case of class renaming).  if the form `super.meth(args)' 
isn't also supported, then a call of this sort would have to be made 
through the introspection API. (i think it would be a good idea to have 
this functionality available through the introspection API, in any 
case.  currently i don't see any obvious way in module `inspect' to find 
out which class a call to `super(...).meth(...)' is invoked on, although 
maybe a loop with inspect.getmro() and hasattr() would work.  it would 
be nice to have a function like inspect.getsuper(class, 'meth'), i think.)

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] a feature i'd like to see in python #1: better iteration control

2006-12-03 Thread Ben Wing


Brian Harring wrote:
> On Sun, Dec 03, 2006 at 08:35:58PM -0600, Ben Wing wrote:
>   
>> but i still don't see why supporting iter.delete() is so wrong.  clearly 
>> it doesn't need to work on files or other such things where it doesn't 
>> make sense.
>>
>> before you diss this completely, note that java supports exactly the 
>> same thing:
>>
>> http://java.sun.com/j2se/1.4.2/docs/api/java/util/Iterator.html
>> 
>
> Not all iterators would support remove; that right there is a bit of 
> an issue since right now, the only exception you need to expect for 
> iterator protocol is StopIteration being thrown when the iterator has 
> nothing more to yield.
>
> So, it's no longer simpler, which is a bit of a con in my opinion.
>   
well, it's not like adding a new exception to any existing iterator 
method.  it would only occur if you call iter.delete() in the wrong context.
> For dict; it actually *cannot* work.  You can't remove keys from a 
> dict as you're iterating over it (can change the val of a key, but not 
> remove the key).  So iter.delete would require fair bit of changes 
> internally to dict, either tracking what it's yielded already, or 
> forcing iterkeys to actually be iter(keys()) (creating an intermediate 
> list), which is worse for memory usage and general performance.
>
> Set's suffer the same thing; can't change what it contains while 
> iterating, have to restart the iteration after a removal/addition.
>   

> Leaves lists... which personally, I view as a mostly bad thing to be 
> doing anyways.  Trying to pop an item out of the middle of a list 
> results in shifting everything right of it one spot to the left; this 
> sucks from a performance standpoint, again, worst case, quad.
>
> Now... occasionally, have to do it admittedly.  But it's not something 
> you actaully want to be doing in your code all that much- admittedly 
> generating a new list to avoid that hit also sucks somewhat, but the 
> worst case there is far more behaved, a temp trade of space vs 
> runtime.
>
> What I'm trying to get at is that what iter(list).next().delete() 
> would do isn't a good thing to paper over, it makes the op look like 
> it costs nothing when it can cost a _lot_.
>   
i do see your point.  i was trying to remember what i ended up doing 
when i ran into this issue before, and in fact i ended up just making a 
new list and appending all the elements i didn't want to delete.  i see 
you'd get N^2 behavior if you deleted lots of elements from a list, but 
you get the same thing currently if you call `del list[i]' a lot; it's 
not obvious that iter.delete() actually "papers over" the cost any more 
than `del list[i]' does.
> Unless I'm missing something, the only real usage of this is a list 
> (could do it on files also, although that would suffer the same 
> issue as a list, just worse via truncate calls).  Would work better on 
> collections.deque, but deque is a linked list and used rather 
> selectively.
>
>   
i actually think now this would be best for hash tables and such.  
copying a large hash table is a real drag, and using the iterator 
protocol is the *only* way to iterate over the elements of a hash 
table.  in fact, i imagine this is exactly why java added this 
functionality.  certainly in lisp, the `maphash' function explicitly 
allows you to delete the current element being iterated over, for the 
same reason.

however, for hash tables there's no reason to use iter.delete().  you 
should just be able to write `del hash[x]'.  is this disallowed 
currently?  if so, it seems like something that should be fixed.

> So... why add it, if it's basically for one major type, and it's 
> not a good idea to blindly do such an action on that type in the first 
> place? 
>   
ok, i see your point and i retract the suggestion.

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [NPERS] Re: a feature i'd like to see in python #1: betteriteration control

2006-12-03 Thread Ben Wing


Terry Reedy wrote:
> Iterate in reverse and no index adjustment is needed
>
>
>   
a good idea, thanks.

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] features i'd like [Python 3000?] ... #4: interpolated strings ala perl

2006-12-03 Thread Ben Wing
sorry to be casting multiple ideas at once to the list.  i've been 
looking into other languages recently and reading the recent PEP's and 
such and it's helped crystallize ideas about what could be better about 
python.

i see in PEP 3101 that there's some work going on to fix up the string 
formatting capabilities of python.  it looks good to me but it still 
doesn't really address the lack of a simple interpolated string 
mechanism, as in perl or ruby.  i find myself constantly writing stuff like

text="Family: %s" % self.name

maybe_errout("%s, line %s: %s\n" % (title, lineno, errstr))

def __str__(self):
return "CCGFeatval(%s, parents=%s, licensing=%s)" % (
(self.name, self.parents, self.licensing))

and lots of similar examples that are just crying out for perl-style 
variable interpolation.  the proposals in PEP 3101 don't help much; i'd 
get instead something like

maybe_errout("{0}, line {1}: {2}\n".format(title, lineno, errstr))

which isn't any better than the current % notation, or something like

maybe_errout("{title}, line {lineno}: {errstr}\n".format(title=title, 
lineno=lineno, errstr=errstr))

where i have to repeat each interpolated variable three times.  yuck 
yuck yuck.

how about something nice like

maybe_errout(i"[title], line [lineno]: [errstr]\n")

or (with the first example above)

text=i"Family: [self.name]"

or (third example above)

def __str__(self):
return i"CCGFeatval([self.name], parents=[self.parents], 
licensing=[self.licensing])"

the advantage of these is the same as for all such interpolations: the 
interpolated variable is logically placed exactly where it will be 
substituted, rather than somewhere else, with the brain needing to do 
some additional cross-referencing.

`i' in front of a string indicates an "interpolated" string just like 
`r' in the same position means "raw string".  if you think this is too 
invisible, you could maybe use `in' or something easier to see.  
however, i could see a case being made for combining both `i' and `r' on 
the same string, and so using a single letter seems to make the most sense.

formatting params can follow, e.g.

  print i"The value of [stock[x]] is [stockval[x]:%6.2f]"

some comments:

1. i suggest brackets here so as to parallel but not interfere with PEP 
3101, which uses braces; PEP 3101 is somewhat orthogonal to this 
proposal and the two might want to coexist.  i think using something 
like brackets or braces is better than perl's $ convention (it 
explicitly indicates the boundaries of the interpolation) and simpler 
than ruby's #{...} or make's ${...}; since strings are only interpolated 
if you specifically indicate this, there's less need to use funny 
characters to avoid accidental interpolation.
2. as shown in the last example, format specifiers can be added to an 
interpolation, as in PEP 3101.  maybe the % is unnecessary.
3. as shown in various examples, things other than just straight 
variables can be interpolated.  the above examples include array/hash 
references and object attributes.  it's not exactly clear what should 
and shouldn't be allowed.  one possibility is just to allow an arbitrary 
expression.  PEP 3101 isn't going to do this because it's working on 
existing strings (including ones that may come from the user), and so 
allowing arbitrary expressions could lead to security holes.  but here, 
we're talking about immediate strings, so security holes of this sort 
should not a concern.
4. the semantics of an interpolated string are exactly that of a series 
of string concatenations, e.g.

return i"CCGFeatval([self.name], parents=[self.parents], 
licensing=[self.licensing])"

is equivalent to

return "CCGFeatval(" + self.name + ", parents=" + self.parents + ", 
licensing=" + self.licensing + ")"

ben


___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] features i'd like [Python 3000?] ... #4: interpolated strings ala perl

2006-12-03 Thread Ben Wing
Ben Wing wrote:
> [interpolated strings]
btw if people think this idea is good, i can certainly write it up in 
PEP form.

ben
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [NPERS] Re: a feature i'd like to see in python #2: indexing of match objects

2006-12-04 Thread Ben Wing


Fredrik Lundh wrote:
> Martin v. Löwis wrote:
>
>   
>>> it can quickly become rather confusing if you also interpret m[:] as 
>>> m.groups(), not to mention if you add len() and arbitrary slicing to
>>> the mix.  what about m[] and m[i,j,k], btw?
>>>   
>> I take it that you are objecting to that feature, then?
>> 
>
> I haven't seen a complete and self-consistent proposal yet, so that's 
> not easy to say.
>
> 
>
>   
my current proposal can be summarized:

1. m[x] == m.group(x) for x an integer >= 0.
2. all other sequence properties should be consistent with this 
numbering and with the view of `m' as basically an array.
3. m[name] == m.group(name) for name a string; names are aliases for 
group numbers.

this implies, for example, that negative indices count from the end, 
that len(m) == 1 + m.lastindex, that the expression `m[1:]' should be 
the same as `m.groups()', that `foo in m' is true if `foo' is equal to 
any group in m or to the whole string, etc.  property 3 should also 
probably imply that names should be allowed as slice indices -- a name 
is just an alias for a group number, and should behave the same way.

an alternative would be to view a match object as a hash table.  then, 
slices would presumably be disallowed, and `foo in m' would be true if 
`foo' is a group number in range, or a name of a group.  but i don't 
like this as much; for example, it's not clear what len(m) should return 
in the case of a named group -- does it count the group once (since a 
name is just an alias), or twice?

(btw i never really thought until now about the inconsistency in the 
'in' operator between arrays and hash tables.)

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [NPERS] Re: a feature i'd like to see in python #2: indexing of match objects

2006-12-05 Thread Ben Wing


Fredrik Lundh wrote:
> Ka-Ping Yee wrote:
>
>   
>> I'd say, don't pretend m is a sequence.  Pretend it's a mapping.
>> Then the conceptual issues go away.
>> 
>
> almost; that would mean returning KeyError instead of IndexError for 
> groups that don't exist, which means that the common pattern
>
>  a, b, c = m.groups()
>
> cannot be rewritten as
>
>  _, a, b, c = m
>
> which would, perhaps, be a bit unfortunate.
>
> taking everything into account, I think we should simply map __getitem__ 
> to group, and stop there.  no len(), no slicing, no sequence or mapping 
> semantics.  if people want full sequence behaviour with len and slicing 
> and iterators and whatnot, they can do list(m) first.
>
>   
i'm ok either way -- that is, either with the proposal i previously 
published, or with this restricted idea.

ben
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] bool conversion wart?

2007-02-22 Thread Ben Wing

On 2/22/07, Neal Becker <[EMAIL PROTECTED]> wrote:


Mike Klaas wrote:

> On 2/22/07, Neal Becker <[EMAIL PROTECTED]> wrote:
>
>> Well consider this:
>> >>>str (4)
>> '4'
>> >>>int(str (4))
>> 4
>> >>>str (False)
>> 'False'
>>
>> >>>bool(str(False))
>> True
>>
>> Doesn't this seem a bit inconsisent?
>
> Virtually no python objects accept a stringified version of themselves
> in their constructor:
>
 str({})
> '{}'
 dict('{}')
> Traceback (most recent call last):
>   File "", line 1, in 
> ValueError: dictionary update sequence element #0 has length 1; 2 is
> required
 str([])
> '[]'
 list('[]')
> ['[', ']']
>
> Python is not Perl.
>
Except, all the numeric types do, including int, float, and complex.  But
not bool.  In fact, this is not just academic.  The fact that other
numeric
types act this way leaves a reasonable expectation that bool will.
Instead, bool fails in _the worst possible way_: it silently gives a
_wrong
result_.



i agree with mike; it would just be asking for trouble. (have you ever been
bitten by the Perl behavior where the string '0' is considered false?  it's
a nasty, nasty problem to debug.)

neal, you may be confusing the concepts of "convert data from one type to
another" and "read the printed representation of data".


ben
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] elimination of scope bleeding of iteration variables

2006-04-30 Thread Ben Wing
apologies if this has been brought up on python-dev already.

a suggestion i have, perhaps for python 3.0 since it may break some code 
(but imo it could go into 2.6 or 2.7 because the likely breakage would 
be very small, see below), is the elimination of the misfeature whereby 
the iteration variable used in for-loops, list comprehensions, etc. 
bleeds out into the surrounding scope.

[i'm aware that there is a similar proposal for python 3.0 for list 
comprehensions specifically, but that's not enough.]

i've been bitten by this problem more than once.  most recently, i had a 
simple function like this:

# Replace property named PROP with NEW in PROPLIST, a list of tuples.
def property_name_replace(prop, new, proplist):
for i in xrange(len(proplist)):
if x[i][0] == prop:
x[i] = (new, x[i][1])

the use of `x' in here is an error, as it should be `proplist'; i 
previously had a loop `for x in proplist', but ran into the problem that 
tuples can't be modified, and lists can't be modified except by index.

despite this obviously bad code, however, it ran without any complaint 
from python -- which amazed me, when i finally tracked this problem 
down.  turns out i had two offenders, both way down in the "main" code 
at the bottom of the file -- a for-loop with loop variable x, and a list 
comprehension [x for x in output_file_map]  -- and suddenly `x' is a 
global variable.  yuck.

i suggest that the scope of list comprehension iteration variables be 
only the list comprehension itself (see python 3000), and the scope of 
for-loop iteration variables be only the for-loop (including any 
following `else' statement -- this way you can access it and store it in 
some other variable if you really want it).

in practice, i seriously doubt this will break much code and probably 
could be introduced like the previous scope change: using `from 
__future__' in python 2.5 or 2.6, and by default in the next version.  
it should be possible, in most circumstances, to issue a warning about 
code that relies on the old behavior.


ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] global variable modification in functions [Re: elimination of scope bleeding of iteration variables]

2006-05-01 Thread Ben Wing


Nick Coghlan wrote:

> Ben Wing wrote:
>
>> apologies if this has been brought up on python-dev already.
>>
>> a suggestion i have, perhaps for python 3.0 since it may break some 
>> code (but imo it could go into 2.6 or 2.7 because the likely breakage 
>> would be very small, see below), is the elimination of the misfeature 
>> whereby the iteration variable used in for-loops, list 
>> comprehensions, etc. bleeds out into the surrounding scope.
>>
>> [i'm aware that there is a similar proposal for python 3.0 for list 
>> comprehensions specifically, but that's not enough.]
>
>
> List comprehensions will be fixed in Py3k. However, the scoping of for 
> loop variables won't change, as the current behaviour is essential for 
> search loops that use a break statement to terminate the loop when the 
> item is found. Accordingly, there is plenty of code in the wild that 
> *would* break if the for loop variables were constrained to the for 
> loop, even if your own code wouldn't have such a problem.
>
> Outside pure scripts, significant control flow logic (like for loops) 
> should be avoided at module level. You are typically much better off 
> moving the logic inside a _main() function and invoking it at the end 
> of the module. This avoids the 'accidental global' problem for all of 
> the script-only variables, not only the ones that happen to be used as 
> for loop variables.

i did in fact end up doing that.  however, in the process i ran into 
another python annoyance i've tripped over repeatedly: you can't assign 
to a global variable without explicitly declaring it as `global'.  
instead, you "magically" get a shadowing local variable.  this behavior 
is extremely hostile to newcomers: e.g.

foo = 1

def set_foo():
  foo = 2

print foo

--> 1

the worst part is, not a single warning from Python about this.  in a 
large program, such a bug can be very tricky to track down.

now i can see how an argument against changing this behavior might hinge 
upon global names like `hash' and `list'; you certainly wouldn't want an 
intended local variable called `hash' or `list' to trounce upon these.  
but this argument confuses lexical and dynamic scope: global variables 
declared inside a module are (or can be viewed as) globally lexically 
scoped in the module, whereas `hash' and `list' are dynamically scoped.

so i'd suggest:

[1] ideally, change this behavior, either for 2.6 or 3.0.  maybe have a 
`local' keyword if you really want a new scope.
[2] until this change, python should always print a warning in this 
situation.
[3] the current 'UnboundLocal' exception should probably be more 
helpful, e.g. suggesting that you might need to use a `global foo' 
declaration.

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] python syntax additions to support indentation insensitivity/generated code

2006-05-01 Thread Ben Wing
recently i've been writing code that generates a python program from a 
source file containing intermixed python code and non-python constructs, 
which get converted into python.

similar things have been done in many other languages -- consider, for 
example, the way php is embedded into web pages.

unfortunately, doing this is really hard in python because of its 
whitespace sensitivity.

i suggest the following simple change: in addition to constructs like this:

block:
  within-block statement
  within-block statement
  ...
out-of-block statement

python should support

block::
  within-block statement
  within-block statement
  ...
end
out-of-block statement

the syntax is similar, but has an extra colon, and is terminated by an 
`end'.  indentation of immediate-level statements within the block is 
unimportant.

mixed-mode code should be possible, e.g.:

block-1::
  within-block-1 statement
  within-block-1 statement
  block-2:
within-block-2 statement
within-block-2 statement
  within-block-1 statement
  ...
end

in other words, code within block-2 is indentation-sensitive; block-2 is 
terminated by the first immediate-level statement at or below the 
indentation of the `block-2' statement. 

similarly, in this:

[A] block-1::
[B]   within-block-1 statement
[C]   within-block-1 statement
[D]   block-2:
[E] within-block-2 statement
[F] within-block-2 statement
[G] block-3::
[H]   within-block-3 statement
[I]   within-block-3 statement
[J] end
[K] within-block-2 statement
[L]   within-block-1 statement
[M]   ...
[N] end

the indentation of lines [D], [E], [F], [G], [K] and [L]  is 
significant, but not any others.  that is, [E], [F], [G], and [K] must 
be at the same level, which is greater than the level of line [D], and 
line [L] must be at a level less than or equal to line [D].  all other 
lines, including [H], [I] and [J], can be at any indentation level.  
also, line [D] can be at any level with respect to line [C].

the idea is that a python code generator could easily mix generated and 
hand-written code.  hand-written code written in normal python style 
could be wrapped by generated code using the indentation-insensitive 
style; if the generated code had no indentation, everything would work 
as expected without the generator having to worry about indentation.

i don't see too many problems with backward-compatibility here.  the 
double-colon shouldn't cause any problems, since that syntax isn't legal 
currently.  `end' could be recognized as a keyword only following a 
double-colon block; elsewhere, it could still be a variable.

ben

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com