Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Re: Creating a local variable scope.

Reply
Thread Tools

Re: Creating a local variable scope.

 
 
markolopa
Guest
Posts: n/a
 
      11-29-2009
Hi,

On 18 Sep, 10:36, "markol...@gmail.com" <markol...@gmail.com> wrote:
> On Sep 11, 7:36 pm, Johan Grönqvist <johan.gronqv...@gmail.com> wrote:
> > I find several places in my code where I would like tohavea variable
> > scope that is smaller than the enclosing function/class/module definition.

>
> This is one of the single major frustrations I have with Python and an
> important source of bugs for me. Here is a typical situation


Here is another bug that I just got. Twenty minutes lost to find it...

class ValueColumn(AbstractColumn):
def __init__(self, name, header, domain_names):
if type(domain_names) != tuple:
raise ValueError('a tuple of domain names must be given')
for name in domain_names:
if type(name) != str:
raise ValueError('a tuple of domain names must be
given')
self.domain_names = domain_names
super(ValueColumn, self).__init__(name, header)

The upper class was initialized with the wrong name, because the for
loop to check
domain_names used "name" which is also the argument to be passed.

If is an old thread but I am reopening to present real situation where
this Python
"feature" bothers me...

Marko
 
Reply With Quote
 
 
 
 
Lie Ryan
Guest
Posts: n/a
 
      11-29-2009
On 11/30/2009 8:12 AM, markolopa wrote:
> Hi,
>
> On 18 Sep, 10:36, "markol...@gmail.com"<markol...@gmail.com> wrote:
>> On Sep 11, 7:36 pm, Johan Grönqvist<johan.gronqv...@gmail.com> wrote:
>>> I find several places in my code where I would like tohavea variable
>>> scope that is smaller than the enclosing function/class/module definition.

>>
>> This is one of the single major frustrations I have with Python and an
>> important source of bugs for me. Here is a typical situation

>
> Here is another bug that I just got. Twenty minutes lost to find it...
>
> class ValueColumn(AbstractColumn):
> def __init__(self, name, header, domain_names):
> if type(domain_names) != tuple:
> raise ValueError('a tuple of domain names must be given')
> for name in domain_names:
> if type(name) != str:
> raise ValueError('a tuple of domain names must be
> given')
> self.domain_names = domain_names
> super(ValueColumn, self).__init__(name, header)
>
> The upper class was initialized with the wrong name, because the for
> loop to check
> domain_names used "name" which is also the argument to be passed.
>
> If is an old thread but I am reopening to present real situation where
> this Python
> "feature" bothers me...
>


here is another bug you might have if python have an "even-more-local"
scope:

while True:
s = raw_input("enter something: ")
if s not in ('q', 'quit', 'exit'): break
print s

if the while block has become its own namespace; print s would generate
NameError.

It is one or the other, you will have problem caused by "namespace too
small" or "namespace too big". Neither is better than the other, so
python's two-level name resolution (global and local level) is the
simplest one, is the better one.
 
Reply With Quote
 
 
 
 
markolopa
Guest
Posts: n/a
 
      11-30-2009
Hi Lie!

On Nov 29, 11:11*pm, Lie Ryan <lie.1...@gmail.com> wrote:
> here is another bug you might have if python have an "even-more-local"
> scope:
>
> while True:
> * * *s = raw_input("enter something: ")
> * * *if s not in ('q', 'quit', 'exit'): break
> print s
>
> if the while block has become its own namespace; print s would generate
> NameError.


This bug you show is completely different, because it is not
dangerous: you get the error and you realise directly how to fix it.

> It is one or the other, you will have problem caused by "namespace too
> small" or "namespace too big". Neither is better than the other, so
> python's two-level name resolution (global and local level) is the
> simplest one, is the better one.


I would be much happier with the smaller namespace. To fix the code
that you show I would impose

s = None
while True:
s = raw_input("enter something: ")
if s not in ('q', 'quit', 'exit'): break
print s

The use in a block of variables created in an inner block is (for me
at least) more an exception than a rule.

Less than 3 hours have passed since my last post and got yet another
bug that could be prevented if Python had the functionality that other
languages have to destroy variables when a block ends. Here is the
code:

=========

arg_columns = []
for domain in self.domains:
i = self.get_column_index(column_names, domain.name)
col = column_elements[i]
if len(col) != len(val_column):
ValueError('column %s has not the same size as the value
column %s'
% (column_names[i], self.name))
arg_columns.append(col)

[...]

value_dict = {}
for i, val_str in enumerate(val_column):
arg_name_row = [c[i] for c in arg_columns]
args = [domain[name] for name in arg_name_row]
value_dict[tuple(args)] = float(val_str)
repo[self.name] = value_dict

=========

The bug is corrected replacing the line

args = [domain[name] for name in arg_name_row]

by

args = [domain[name] for name, domain in zip(arg_name_row,
self.domains)]

so "domain" should not exist in my namespace since I have no
information associated to "domain" only to "self.domains". Python
should allow me to write safe code!

Antoher 15 minutes lost because of that Python "feature"... Is it only
me???

Thanks for your comment!
Marko
 
Reply With Quote
 
Steve Howell
Guest
Posts: n/a
 
      11-30-2009
On Nov 29, 4:26*pm, markolopa <marko.lopa...@gmail.com> wrote:
> Less than 3 hours have passed since my last post and got yet another
> bug that could be prevented if Python had the functionality that other
> languages have to destroy variables when a block ends. Here is the
> code:
>
> =========
>
> arg_columns = []
> for domain in self.domains:
> * * i = self.get_column_index(column_names, domain.name)
> * * col = column_elements[i]
> * * if len(col) != len(val_column):
> * * * * ValueError('column %s has not the same size as the value
> column %s'
> * * * * * * * * * *% (column_names[i], self.name))
> * * * * arg_columns.append(col)
>
> [...]
>
> value_dict = {}
> for i, val_str in enumerate(val_column):
> * * arg_name_row = [c[i] for c in arg_columns]
> * * args = [domain[name] for name in arg_name_row]
> * * value_dict[tuple(args)] = float(val_str)
> repo[self.name] = value_dict
>
> =========
>
> The bug is corrected replacing the line
>
> * * args = [domain[name] for name in arg_name_row]
>
> by
>
> * * args = [domain[name] for name, domain in zip(arg_name_row,
> self.domains)]
>
> so "domain" should not exist in my namespace since I have no
> information associated to "domain" only to "self.domains". Python
> should allow me to write safe code!
>
> Antoher 15 minutes lost because of that Python "feature"... Is it only
> me???
>


I occasionally make the error you make, but I think the real problem
you are having is lack of attention to detail. If name collisions are
a common problem for you, consider writing shorter methods or develop
the habit of using more descriptive variable names. In the code
above, you could have easily cleaned up the namespace by extracting a
method called get_arg_columns(). Having to spend 15 minutes tracking
down a bug usually indicates that you are not being systematic in your
thinking. If you are rushing too much, slow down. If you are tired,
take a break. If you make the same mistake twice, commit to yourself
not to make it a third time. Also, test your methods one at a time
and get them rock solid before writing more code.
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      11-30-2009
* markolopa:
>
> On 18 Sep, 10:36, "markol...@gmail.com" <markol...@gmail.com> wrote:
>> On Sep 11, 7:36 pm, Johan Grönqvist <johan.gronqv...@gmail.com> wrote:
>>> I find several places in my code where I would like tohavea variable
>>> scope that is smaller than the enclosing function/class/module definition.

>> This is one of the single major frustrations I have with Python and an
>> important source of bugs for me. Here is a typical situation

>
> Here is another bug that I just got. Twenty minutes lost to find it...
>
> class ValueColumn(AbstractColumn):
> def __init__(self, name, header, domain_names):
> if type(domain_names) != tuple:
> raise ValueError('a tuple of domain names must be given')
> for name in domain_names:
> if type(name) != str:
> raise ValueError('a tuple of domain names must be
> given')
> self.domain_names = domain_names
> super(ValueColumn, self).__init__(name, header)
>
> The upper class was initialized with the wrong name, because the for
> loop to check
> domain_names used "name" which is also the argument to be passed.
>
> If is an old thread but I am reopening to present real situation where
> this Python
> "feature" bothers me...


I think if one could somehow declare names as const (final, readonly, whatever)
then that would cover the above plus much more.


Cheers,

- Alf
 
Reply With Quote
 
Dave Angel
Guest
Posts: n/a
 
      11-30-2009
markolopa wrote:
> <snip>
> =======
>
> arg_columns =]
> for domain in self.domains:
> i =elf.get_column_index(column_names, domain.name)
> col =olumn_elements[i]
> if len(col) !=en(val_column):
> ValueError('column %s has not the same size as the value
> column %s'
> % (column_names[i], self.name))
> arg_columns.append(col)
>
> [...]
>
> value_dict =}
> for i, val_str in enumerate(val_column):
> arg_name_row =c[i] for c in arg_columns]
> args =domain[name] for name in arg_name_row]
> value_dict[tuple(args)] =loat(val_str)
> repo[self.name] =alue_dict
>
> =======
>
> The bug is corrected replacing the line
>
> args =domain[name] for name in arg_name_row]
>
> by
>
> args =domain[name] for name, domain in zip(arg_name_row,
> self.domains)]
>
> so "domain" should not exist in my namespace since I have no
> information associated to "domain" only to "self.domains". Python
> should allow me to write safe code!
>
> Antoher 15 minutes lost because of that Python "feature"... Is it only
> me???
>
>

Yep, I think so. You're proposing a much more complex scoping rule,
where if a variable already exists before entering a loop, then the loop
uses that existing variable, but if not, it creates its own local one
and destroys it when exiting the loop. That's the exact opposite of
what function definitions do, which already makes it confusing.

I think if you had your wish, you'd find that you had more exceptions
where you had to pre-declare things, than the times when you avoided the
bugs you describe. I don't like languages that make me write extra
stuff 100 times, to save one instance of extra debugging. If Python
already required declarations, then I might buy your arguments. But it
wouldn't be Python.
> Thanks for your comment!
> Marko
>
>


In your particular case, the compiler couldn't guess whether you used
the first loop to decide which domain to use in the second loop, or
whether you accidentally reused the same name without giving it a new
value in the new loop. If you need to use the same name, you could
always follow your loops with the del statement to invalidate the name.


DaveA

 
Reply With Quote
 
Terry Reedy
Guest
Posts: n/a
 
      11-30-2009
markolopa wrote:

>
> so "domain" should not exist in my namespace since I have no
> information associated to "domain" only to "self.domains". Python
> should allow me to write safe code!


Leaving iteration names bound after loop exit is a feature. If you do
not like it, explicitly unbind it.

 
Reply With Quote
 
markolopa
Guest
Posts: n/a
 
      11-30-2009
Hi Steve!

On Nov 30, 1:46*am, Steve Howell <showel...@yahoo.com> wrote:
> I occasionally make the error you make, but I think the real problem
> you are having is lack of attention to detail. *If name collisions are
> a common problem for you, consider writing shorter methods


Yes, this could be a solution, though I believe that too many (sub)
methods called by a single method turn the code less readable.

> or develop
> the habit of using more descriptive variable names.


Also a good suggestion. Alternatively I have considered to do the
opposite, to use weird (the opposite of descriptive) names for
variables that should exist only inside the block, in order to
differentiate them from the variables that should persist.

> *In the code
> above, you could have easily cleaned up the namespace by extracting a
> method called get_arg_columns(). *Having to spend 15 minutes tracking
> down a bug usually indicates that you are not being systematic in your
> thinking. *If you are rushing too much, slow down. *If you are tired,
> take a break. *If you make the same mistake twice, commit to yourself
> not to make it a third time. *Also, test your methods one at a time
> and get them rock solid before writing more code.


Nice suggestions thanks, all of them apply to me!... Compared to
the normal coder I have a strong tendency to loose myself in details.
That is why I have to be very systematic, write lots of defensive code
(to catch the bugs as soon as possible), write unit tests (great habit
I've developped recently!). Python is fantastic for those goals. The
only laking feature I find is really the survival of variables, a
problem that does not exist in C++ or in Perl (with use strict).
Besides this kind of bug I have noticed only 2 other sources of bug I
had more than once with python code.
- expecting float from integer division (easily avoidable, either with
3.0 or from __future__...)
- expecting diferent objects in a list have having the same several
times (deepcopy issue, also easily avoidable once we know it)

So my only other problem is with this "survival" feature. I consider
to write my own version of Python, the one that would not allow the
usage of varaibles outside the block it was created. Of course I won't
rewrite CPython but I could add an error (or warning) to pylint. With
some luck it already exists, I will investigate...

Greets!
Marko
 
Reply With Quote
 
markolopa
Guest
Posts: n/a
 
      11-30-2009
On Nov 30, 4:46*am, Dave Angel <da...@ieee.org> wrote:
> markolopa wrote:
> > Antoher 15 minutes lost because of that Python "feature"... Is it only
> > me???

>
> Yep, I think so.


Not very consoling but thanks anyway!...)))

>*You're proposing a much more complex scoping rule,
> where if a variable already exists before entering a loop, then the loop
> uses that existing variable, but if not, it creates its own local one
> and destroys it when exiting the loop.


Alternatively you could forbid the creation of a variable in a inner
block if it already exists. Either that or forbid the usage of the
variable in an outter block later if it exists both in an inner and
outer block.

Aren't there languages that forbid the declarations of variables in a
function with the same name as global variables? I know that this is
an extreme defensive measure, but I have to say that I like it.
Allowing to create a new variable when a variable with the same name
is already exists in the namespace makes for harm that good, for me at
least. Of course this issue is much broader than the one I proposed
initially.

> I think if you had your wish, you'd find that you had more exceptions
> where you had to pre-declare things, than the times when you avoided the
> bugs you describe. *


You are probably right, otherwise Guido would have done what I
suggest... but I really don't see why.

> I don't like languages that make me write extra
> stuff 100 times, to save one instance of extra debugging. *If Python
> already required declarations, then I might buy your arguments. *But it
> wouldn't be Python.


My guess is that if the change I propose was implemented, the number
additional lines that would be needed to make the present python code
work would be 1 in a thousand or less. Of course I may be wrong...
Besides this additional line can make the code more readable,
strassing the fact that the variable inside the block actually
"belongs" to outside.

> In your particular case, the compiler couldn't guess whether you used
> the first loop to decide which domain to use in the second loop,


That is what I wish the compiler should forbid...:->

> or
> whether you accidentally reused the same name without giving it a new
> value in the new loop. *


That is what I do regularly...8->

> If you need to use the same name, you could
> always follow your loops with the del statement to invalidate the name.


Several people have suggested explicit destruction of the variables I
don't need. Python allows it but of course this does not solve my
problem. It does not make sense to use such a clean language as Python
and regularly delete all variables used inside the blocks when leaving
it. And of course the bug comes because I have no idea that I am using
the same name again.

Cheers!
Marko
 
Reply With Quote
 
Lie Ryan
Guest
Posts: n/a
 
      11-30-2009
On 11/30/2009 8:13 PM, markolopa wrote:
> On Nov 30, 4:46 am, Dave Angel<da...@ieee.org> wrote:
>> markolopa wrote:
>>> Antoher 15 minutes lost because of that Python "feature"... Is it only
>>> me???

>>
>> Yep, I think so.

>
> Not very consoling but thanks anyway!...)))
>
>> You're proposing a much more complex scoping rule,
>> where if a variable already exists before entering a loop, then the loop
>> uses that existing variable, but if not, it creates its own local one
>> and destroys it when exiting the loop.

>
> Alternatively you could forbid the creation of a variable in a inner
> block if it already exists. Either that or forbid the usage of the
> variable in an outter block later if it exists both in an inner and
> outer block.
>


Of course, the best solution would be to allow assignment only in a
single line of source of code. Reassignment by different lines of code
would be a syntax error. You're forced to have different names if you
want assign something multiple times. That way, no bugs is possible.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Creating a local variable scope. Johan Grönqvist Python 14 09-24-2009 11:33 AM
Programmatically creating a local variable using a symol tho_mica_l Ruby 7 01-07-2008 08:17 AM
Instance Variable v.s. Local Variable Jerry Java 5 08-06-2005 04:40 AM
Instance Variable vs Local Variable Paul Carey Java 3 12-03-2003 05:05 PM
a static local variable in a static method is thread local storage? Patrick Hoffmann C++ 3 08-08-2003 02:37 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57