Re: Overriding a global

2011-12-15 Thread Joshua Landau
On 14 December 2011 17:06, Jean-Michel Pichavant wrote:

> Joshua Landau wrote:
>
>> [snip]
>> Using currentLogger is just padding, in my opinion. *Every *value is
>> "current".
>>
> Not always. I try to keep names on the same object because that object is
> supposed to be named that way.
> I can change one of the object attribute, but the object named that way
> keep being the same.
>
> Class Foo:
>  self.__init__(self):
>self.banana = 5
>
> myFoo = Foo()
>
> Now there's a slight difference between
>
> myFoo = Exception()
> and
> myFoo.banana = 4
>
> The first statement rebind myFoo to something complitely different.
> the second statement change one of the object rightfully named myFoo ..
> attribute (not sure about this construct :D )
>
> Int being inmutable, you can rebind a name without changing its meaning.
>

type(myFoo) before != type(myFoo) after
type(myFoo.bannana) before == type(myFoo.bannana) after
type(logger) before == type(logger) after

You are changing the int to a new value, but it's OK for you - if I
understand rightly - because it's not changing its "meaning". The "meaning"
of logger is the same too, as it does the same thing, in approximately the
same way. I agree that "logger = Exception()" would be vary bad in that
sense, too. The point is you use it the same way and it's not going to
cause problems from misunderstanding what the object type is. And because
"logger = childLogger('this_function')" is explicit and hopefully at the
top 'o the function, any conceivable errors should be pretty obvious.

Note that I used quotation marks around "meaning" not to mock the use or
whatnot, but because I was trying to show that I was trying to use the same
version of the word you did. I don't know if that was clear from the
passage itself.

That said, you did keep the myFoo the same, even with the int change. That
makes the change global to all myFoo instances. But I didn't get that as a
main point from your argument, and if it was I fear we're too close to
recursive arguments.


And in regards to your own commentary on your English, I wouldn't like you
to see it as trouble. I'm currently thoroughly enjoying the debate, and
wouldn't like to see myself scaring you off...
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Jean-Michel Pichavant

Joshua Landau wrote:

[snip]
Using currentLogger is just padding, in my opinion. *Every *value is 
"current".
Not always. I try to keep names on the same object because that object 
is supposed to be named that way.
I can change one of the object attribute, but the object named that way 
keep being the same.


Class Foo:
 self.__init__(self):
self.banana = 5

myFoo = Foo()

Now there's a slight difference between

myFoo = Exception()
and
myFoo.banana = 4

The first statement rebind myFoo to something complitely different.
the second statement change one of the object rightfully named myFoo .. 
attribute (not sure about this construct :D )


Int being inmutable, you can rebind a name without changing its meaning.



In regards to a second name - yes this could work and in many cases 
would be desirable, but it doesn't really help this circumstance. 
[assume, for a moment, a lot of functions used a local logger] 
"localLogger" would tell you very little about what the logger 
actually /is/. You still have to look that up. [end assumption] 
Additionally, this would make changing a logger that uses the default 
to a local one /much/ harder. And don't say "but you can just always 
make a local copy", as then you lose the advantage of a global.


Typing something like "logger = childLogger(id)" to the start of a 
function call *is explicit*, it's clean, and it makes sense to have a 
default that's global. You're not appending cruft ("current") and you 
have consistency. If you added "logger = globalLogger" to every 
function start as well you can argue that it's better. I agree it's 
more explicit. But then you lose unneeded if only a small portion of 
your code localises logger. But I would recommend it if a large 
portion of code used local variants.


AND:

The next time I'll illustrate meaningful names,  I'll write a 3000
lines function, just to be sure no one states that my point
does'nt apply to a function named spam which only counts from 1 to 3.
And don't answer that the spam function above does not count from
1 to 3, I know it doesn't.


You're acting in sarcasm to a comment on scale, when you yourself said 
that one of my comments was invalid due to names that were scaled down 
for exampling. It seems a bit hypocritical to me. That said, not all 
functions are long. If the short ones use short names that's fine: I'm 
pretty sure you said it's not.


And in regards to the link:
1) __add__ says otherwise (technically, the operator "+"). It's rarely 
confused me.
2) That's not what we're discussing. As it said: "As long as the 
parameter lists are semantically equal and the desired result is the 
same, all is well." They're doing semantically the same thing (to 
different log levels) with the same parameter lists and they're not 
class methods. You /could/ say that the semantics are different, but 
classes act in a context in the same way local variables can be 
thought of doing, and semantics are the same for them. Instead of a 
different self, it's a different log file/level. Same semantics.
I'd like to argue about that but I won't cause I have the feeling my 
lack of ultra precise english would cause me more trouble. Note that I'm 
not blaming anyone but me, no sarcasm inside.


JM
--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Joshua Landau
On 14 December 2011 10:14, Jean-Michel Pichavant wrote:

> Joshua Landau wrote:
>
>  On 13 December 2011 13:30, Jean-Michel Pichavant 
> > jeanmic...@sequans.com**>> wrote:
>>
>>writing
>>
>>x = 1
>>
>>def spam():
>>  x = 2
>>
>>is in general a bad idea. That was my point.
>>
>>
>> Why? I have a few (probably wrong) guesses.
>>
>> Because you expect it to be the same every time you use it?
>> Well, then this should be "in general a bad idea":
>> x = 1; print(x); x = 2; print(x)
>>
> you're changing the value of x, that's fine. In the example above, the
> assignement is not the problem. The problem is that you create 2 different
> 'x', one in globals(), and one in locals(). Using the same name within 2
> implicit namespaces is a bad idead in general because it can be difficult
> to know which one is used.
>
> If you want to have fun, try this code, prepared to be amazed. There's
> something funny with the global statement, it's applied on the whole block
> no matter where it is stated in the block.
> x=1 # global
>
> def spam():
>   x = 2 # local (or so you may think)
>   print x
>   global x # I need to use the global one now
>   print x
>   print locals()
>

:3: SyntaxWarning: name 'x' is assigned to before global declaration

I think it's a null point. We're not talking about "globals" being wrong
(or was this poor design) for efficiency reasons. There's an error there
for reason.


> For more fun you could create a 'x' name in __builtin__ and import it so
> that people never know which x you are using.
>
>  Even though it makes total sense to me.
>>
>> Is it because it's used to different purpose between similarly-looking
>> functions?
>> This looks fine, though:
>> def func1(): x=1; print(x)
>> def func2(): x=2; print(x)
>>
>> Is it because it looks like a reassignment of the more global x?
>> I don't have an example here but, simply put, I don't believe this. We
>> can use "id" as our own local variable without thinking that we're
>> tampering with "__builtins__.id". I don't see it as much of a leap from
>> builtin to global (except that you /*can*/ do "dir = 1; del dir; dir"
>> without error).
>>
>>
>> That said, I'm sorta' just guessing the reason you might think it's a bad
>> idea.
>>
>
> The problem makes little sense when using names like x or func1. Besides
> namespace issues, naming 2 *different objects* with the same meaningful
> name is usually a bad idea and points the fact that your names are no that
> meaningful. To go back to the original post, having a 'logger' that may
> name 2 different logger object during the execution is a bad idea. One
> quick way to fix it is to name the logger 'currentLogger', this way you
> warn the reader that the logger named by curentLogger may change over time.
>
> As someone sugggested in this thread one other option is to use a
> different name for the second logger.


So the only problem is that "x" isn't meaningful?

def countToTen():
 for number in range(1, 10): print(number)

def countToTwenty():
 for number in range(1, 20): print(number)

.. Looks fine to me.

Using currentLogger is just padding, in my opinion. *Every *value is
"current". That changes nothing. As long as you never infer that
"logger" is static or totally global (no "global logger" in global
namespace or terming it "LOGGER") I would never assume as much, as with
every other variable I see. Unless I see "global " in a function, I
need to hold the belief that  can change.

In regards to a second name - yes this could work and in many cases would
be desirable, but it doesn't really help this circumstance. [assume, for a
moment, a lot of functions used a local logger] "localLogger" would tell
you very little about what the logger actually *is*. You still have to look
that up. [end assumption] Additionally, this would make changing a logger
that uses the default to a local one *much* harder. And don't say "but you
can just always make a local copy", as then you lose the advantage of a
global.

Typing something like "logger = childLogger(id)" to the start of a function
call *is explicit*, it's clean, and it makes sense to have a default that's
global. You're not appending cruft ("current") and you have consistency. If
you added "logger = globalLogger" to every function start as well you can
argue that it's better. I agree it's more explicit. But then you
lose unneeded if only a small portion of your code localises logger. But I
would recommend it if a large portion of code used local variants.

AND:

> The next time I'll illustrate meaningful names,  I'll write a 3000 lines
> function, just to be sure no one states that my point does'nt apply to a
> function named spam which only counts from 1 to 3.
> And don't answer that the spam function above does not count from 1 to 3,
> I know it doesn't.


You're acting in sarcasm to a comment on scale, when you yourself said that
one of my comments was invalid due to names that were scaled down for
exampling. It seems a bi

Re: Overriding a global

2011-12-14 Thread Jean-Michel Pichavant

Steven D'Aprano wrote:

On Wed, 14 Dec 2011 13:05:19 +0100, Jean-Michel Pichavant wrote:

  

Bad ideas :

i = 5

def spam():
  for i,v in enumerate([1,2,3,4]):
for i,v in enumerate(['a','b', 'c']):
  print i, v
print i,v # bad surprise



The bad surprise happens because you are using the same name twice in 
*one* namespace, the local scope. This example has nothing to do with 
local/global name clashes: the existence of global i is irrelevant. 
Python's scoping rules work correctly, and global i is not affected by 
the local i.


Programming languages use multiple namespaces so that you don't need to 
make your variable names globally unique. There are languages that don't 
distinguish between local and global. Python is not one of them. The 
programmer should feel free to use local names without worrying too much 
if they accidentally use a global name.


Having said that, re-using names isn't *entirely* risk free, because if 
you use a global name locally, and then try to *also* access the global 
name, you will fail. This is called shadowing, and the problem with 
shadowing is when you do it by accident. (Newbies are particularly prone 
to this, especially when they call variables "str", "list", etc.) But it 
is the "by accident" part that is dangerous: there is nothing wrong with 
shadowing globals or builtins when you do it by design.



  

good ideas :

# global
nameThatWillNotBeUsedlocally = 'foo'



Oh please. Names can be too long as well as too short.

 
  

def spam():
  for qtyIndex, quantity in enumerate([5,6,3,1]):
for fruitIndex, fruit in enumerate(['orange', 'banana']):
  print fruitIndex, fruit
print qtyIndex, quantity



More sensible naming conventions are to be encouraged, but verbose names 
just for the sake of verbosity is not. spam() is a five line function; if 
the programmer can't keep track of the meaning of loop variables i and j 
over five lines, perhaps they should consider a change of career and get 
a job more suited to their intellectual prowess. I hear McDonalds is 
hiring.


If spam() were larger and more complex, then more expressive names would 
be valuable. But in the simple example you give, it just adds noise.


  


The next time I'll illustrate meaningful names,  I'll write a 3000 lines 
function, just to be sure no one states that my point does'nt apply to a 
function named spam which only counts from 1 to 3.
And don't answer that the spam function above does not count from 1 to 
3, I know it doesn't.


For anyone interested in the actual topic, a good reading is
http://tottinge.blogsome.com/meaningfulnames/#Mult_Meanings


JM

--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Steven D'Aprano
On Wed, 14 Dec 2011 13:05:19 +0100, Jean-Michel Pichavant wrote:

> Bad ideas :
> 
> i = 5
> 
> def spam():
>   for i,v in enumerate([1,2,3,4]):
> for i,v in enumerate(['a','b', 'c']):
>   print i, v
> print i,v # bad surprise

The bad surprise happens because you are using the same name twice in 
*one* namespace, the local scope. This example has nothing to do with 
local/global name clashes: the existence of global i is irrelevant. 
Python's scoping rules work correctly, and global i is not affected by 
the local i.

Programming languages use multiple namespaces so that you don't need to 
make your variable names globally unique. There are languages that don't 
distinguish between local and global. Python is not one of them. The 
programmer should feel free to use local names without worrying too much 
if they accidentally use a global name.

Having said that, re-using names isn't *entirely* risk free, because if 
you use a global name locally, and then try to *also* access the global 
name, you will fail. This is called shadowing, and the problem with 
shadowing is when you do it by accident. (Newbies are particularly prone 
to this, especially when they call variables "str", "list", etc.) But it 
is the "by accident" part that is dangerous: there is nothing wrong with 
shadowing globals or builtins when you do it by design.


> good ideas :
> 
> # global
> nameThatWillNotBeUsedlocally = 'foo'

Oh please. Names can be too long as well as too short.

 
> def spam():
>   for qtyIndex, quantity in enumerate([5,6,3,1]):
> for fruitIndex, fruit in enumerate(['orange', 'banana']):
>   print fruitIndex, fruit
> print qtyIndex, quantity

More sensible naming conventions are to be encouraged, but verbose names 
just for the sake of verbosity is not. spam() is a five line function; if 
the programmer can't keep track of the meaning of loop variables i and j 
over five lines, perhaps they should consider a change of career and get 
a job more suited to their intellectual prowess. I hear McDonalds is 
hiring.

If spam() were larger and more complex, then more expressive names would 
be valuable. But in the simple example you give, it just adds noise.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Chris Angelico
On Wed, Dec 14, 2011 at 11:05 PM, Jean-Michel Pichavant
 wrote:
> Chris Angelico wrote:
>>
>> So... it's a bad idea for me to use 'i' many times in my code, with
>> the same name having different meanings in different places? In
>> languages with infinitely-nesting scopes...

> Bad ideas :
>
> i = 5
>
> def spam():
>  for i,v in enumerate([1,2,3,4]):
>   for i,v in enumerate(['a','b', 'c']):
>     print i, v
>   print i,v # bad surprise

That's my point. It's not safe to do it in Python, because the "inner"
local i is the same as the "outer" local i. Python doesn't have block
scope the way most C-like languages do.

int spam()
{
for (int i=0;i<5;++i)
{
for (int i=2;i<4;++i) write("inner "+i+"\n");
write("outer "+i+"\n");
}
}

Works perfectly, and the only cost is that variables must be formally declared.

In Python, you can kinda fudge that sort of thing with nested functions.

def spam():
q=2  # just to prove that the scopes really are nested
for i in range(5):
def ham():
for i in range(2,4):
print("q = %d, i = %d"%(q,i))
ham()
print("i = %d"%i)

It's somewhat clunky, but it does give the illusion of block scope.
Inners mask outers, outers are visible to inner functions. It's an odd
construct though. Very odd.

So... I think I've figured out how to implement from __future__ import braces.

#define { def innerfunc():
#define } innerfunc()

And there you are, out of your difficulty at once!

ChrisA
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Jean-Michel Pichavant

Chris Angelico wrote:

On Wed, Dec 14, 2011 at 9:14 PM, Jean-Michel Pichavant
 wrote:
  

The problem makes little sense when using names like x or func1. Besides
namespace issues, naming 2 *different objects* with the same meaningful name
is usually a bad idea and points the fact that your names are no that
meaningful.



So... it's a bad idea for me to use 'i' many times in my code, with
the same name having different meanings in different places? In
languages with infinitely-nesting scopes (one of Python's great lacks,
imho), I've often had three different variables with the same names,
all perfectly valid, and all doing what they should. It's not just
loop indices - I used to have a piece of code in which 'res' was a
MySQL resource being processed in a loop, and I had three nested
loops. Each time I referenced 'res', it used the innermost available
resource, which was precisely what I wanted. If I'd arbitrarily had to
guarantee that all variable names were unique, I would have had
completely unnecessary fiddling around.

Python wouldn't let you do that with three nested 'res'es in one
function, but you can perfectly reasonably have a global and a local.
It makes perfect sense... which is a good reason for keeping it legal.

ChrisA
  


Bad ideas :

i = 5

def spam():
 for i,v in enumerate([1,2,3,4]):
   for i,v in enumerate(['a','b', 'c']):
 print i, v
   print i,v # bad surprise


good ideas :

# global
nameThatWillNotBeUsedlocally = 'foo'

def spam():
 for qtyIndex, quantity in enumerate([5,6,3,1]):
   for fruitIndex, fruit in enumerate(['orange', 'banana']):
 print fruitIndex, fruit
   print qtyIndex, quantity

While a lot of people still use i,j,k,v to handler values and indexes, I 
think it's a bad idea. I'm just stating an opinion from my personnal 
python experience. I know some people can successfully use the hard way.


JM


--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Chris Angelico
On Wed, Dec 14, 2011 at 9:14 PM, Jean-Michel Pichavant
 wrote:
> The problem makes little sense when using names like x or func1. Besides
> namespace issues, naming 2 *different objects* with the same meaningful name
> is usually a bad idea and points the fact that your names are no that
> meaningful.

So... it's a bad idea for me to use 'i' many times in my code, with
the same name having different meanings in different places? In
languages with infinitely-nesting scopes (one of Python's great lacks,
imho), I've often had three different variables with the same names,
all perfectly valid, and all doing what they should. It's not just
loop indices - I used to have a piece of code in which 'res' was a
MySQL resource being processed in a loop, and I had three nested
loops. Each time I referenced 'res', it used the innermost available
resource, which was precisely what I wanted. If I'd arbitrarily had to
guarantee that all variable names were unique, I would have had
completely unnecessary fiddling around.

Python wouldn't let you do that with three nested 'res'es in one
function, but you can perfectly reasonably have a global and a local.
It makes perfect sense... which is a good reason for keeping it legal.

ChrisA
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-14 Thread Jean-Michel Pichavant

Joshua Landau wrote:
On 13 December 2011 13:30, Jean-Michel Pichavant 
mailto:jeanmic...@sequans.com>> wrote:


writing

x = 1

def spam():
  x = 2

is in general a bad idea. That was my point.


Why? I have a few (probably wrong) guesses.

Because you expect it to be the same every time you use it?
Well, then this should be "in general a bad idea":
x = 1; print(x); x = 2; print(x)
you're changing the value of x, that's fine. In the example above, the 
assignement is not the problem. The problem is that you create 2 
different 'x', one in globals(), and one in locals(). Using the same 
name within 2 implicit namespaces is a bad idead in general because it 
can be difficult to know which one is used.


If you want to have fun, try this code, prepared to be amazed. There's 
something funny with the global statement, it's applied on the whole 
block no matter where it is stated in the block.

x=1 # global

def spam():
   x = 2 # local (or so you may think)
   print x
   global x # I need to use the global one now
   print x
   print locals()

For more fun you could create a 'x' name in __builtin__ and import it so 
that people never know which x you are using.



Even though it makes total sense to me.

Is it because it's used to different purpose between similarly-looking 
functions?

This looks fine, though:
def func1(): x=1; print(x)
def func2(): x=2; print(x)

Is it because it looks like a reassignment of the more global x?
I don't have an example here but, simply put, I don't believe this. We 
can use "id" as our own local variable without thinking that we're 
tampering with "__builtins__.id". I don't see it as much of a leap 
from builtin to global (except that you /*can*/ do "dir = 1; del dir; 
dir" without error).


That said, I'm sorta' just guessing the reason you might think it's a 
bad idea.


The problem makes little sense when using names like x or func1. Besides 
namespace issues, naming 2 *different objects* with the same meaningful 
name is usually a bad idea and points the fact that your names are no 
that meaningful. To go back to the original post, having a 'logger' that 
may name 2 different logger object during the execution is a bad idea. 
One quick way to fix it is to name the logger 'currentLogger', this way 
you warn the reader that the logger named by curentLogger may change 
over time.


As someone sugggested in this thread one other option is to use a 
different name for the second logger.


JM
--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Joshua Landau
On 13 December 2011 19:54, Ian Kelly  wrote:

> On Tue, Dec 13, 2011 at 12:43 PM, Joshua Landau
>  wrote:
> > On 13 December 2011 19:34, Ian Kelly  wrote:
> >>
> >> On Tue, Dec 13, 2011 at 1:34 AM, Joshua Landau
> >>  wrote:
> >> >> No, there is another difference, the reason for rebinding the name.
> >> >> In a subclass, you would rebind a class attribute because that
> >> >> particular attribute, which you need to change, is used and expected
> >> >> by external code, either in the base class or in code that uses its
> >> >> API (or both).  Local variables in functions, on the other hand, are
> >> >> not externally visible, so there is no need to do this in order to
> >> >> conform to the expectations of external code.  All it does in that
> >> >> case is to sow potential confusion.
> >> >>
> >> > So you're saying you should never extend methods or attributes that
> >> > aren't meant to be used as part of of the API? Because I can claim
> >> > guilty on this point.
> >>
> >> No, I'm only saying that replacing attributes in subclasses is
> >> accepted because it is necessary due to external dependencies, and
> >> that local variables in functions don't have that excuse.
> >
> >
> > But they aren't needed due to external dependencies if they're
> > implementation-specific and not part of the API, no?
>
> By "external dependencies" I mean anything that's not specifically
> part of the subclass.  This includes the base class.  If they're not
> part of the API, then the base class presumably uses them for
> something, and by replacing them, you change the behavior of that base
> functionality.  That's an external dependency.
>

Touché. On this point, I yield.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Ian Kelly
On Tue, Dec 13, 2011 at 12:43 PM, Joshua Landau
 wrote:
> On 13 December 2011 19:34, Ian Kelly  wrote:
>>
>> On Tue, Dec 13, 2011 at 1:34 AM, Joshua Landau
>>  wrote:
>> >> No, there is another difference, the reason for rebinding the name.
>> >> In a subclass, you would rebind a class attribute because that
>> >> particular attribute, which you need to change, is used and expected
>> >> by external code, either in the base class or in code that uses its
>> >> API (or both).  Local variables in functions, on the other hand, are
>> >> not externally visible, so there is no need to do this in order to
>> >> conform to the expectations of external code.  All it does in that
>> >> case is to sow potential confusion.
>> >>
>> > So you're saying you should never extend methods or attributes that
>> > aren't meant to be used as part of of the API? Because I can claim
>> > guilty on this point.
>>
>> No, I'm only saying that replacing attributes in subclasses is
>> accepted because it is necessary due to external dependencies, and
>> that local variables in functions don't have that excuse.
>
>
> But they aren't needed due to external dependencies if they're
> implementation-specific and not part of the API, no?

By "external dependencies" I mean anything that's not specifically
part of the subclass.  This includes the base class.  If they're not
part of the API, then the base class presumably uses them for
something, and by replacing them, you change the behavior of that base
functionality.  That's an external dependency.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Joshua Landau
On 13 December 2011 19:34, Ian Kelly  wrote:

> On Tue, Dec 13, 2011 at 1:34 AM, Joshua Landau
>  wrote:
> >> No, there is another difference, the reason for rebinding the name.
> >> In a subclass, you would rebind a class attribute because that
> >> particular attribute, which you need to change, is used and expected
> >> by external code, either in the base class or in code that uses its
> >> API (or both).  Local variables in functions, on the other hand, are
> >> not externally visible, so there is no need to do this in order to
> >> conform to the expectations of external code.  All it does in that
> >> case is to sow potential confusion.
> >>
> > So you're saying you should never extend methods or attributes that
> > aren't meant to be used as part of of the API? Because I can claim
> > guilty on this point.
>
> No, I'm only saying that replacing attributes in subclasses is
> accepted because it is necessary due to external dependencies, and
> that local variables in functions don't have that excuse.
>

But they aren't needed due to external dependencies if they're
implementation-specific and not part of the API, no?
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Ian Kelly
On Tue, Dec 13, 2011 at 1:34 AM, Joshua Landau
 wrote:
>> No, there is another difference, the reason for rebinding the name.
>> In a subclass, you would rebind a class attribute because that
>> particular attribute, which you need to change, is used and expected
>> by external code, either in the base class or in code that uses its
>> API (or both).  Local variables in functions, on the other hand, are
>> not externally visible, so there is no need to do this in order to
>> conform to the expectations of external code.  All it does in that
>> case is to sow potential confusion.
>>
> So you're saying you should never extend methods or attributes that
> aren't meant to be used as part of of the API? Because I can claim
> guilty on this point.

No, I'm only saying that replacing attributes in subclasses is
accepted because it is necessary due to external dependencies, and
that local variables in functions don't have that excuse.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Joshua Landau
On 13 December 2011 13:30, Jean-Michel Pichavant wrote:
>
> writing
>
> x = 1
>
> def spam():
>   x = 2
>
> is in general a bad idea. That was my point.


Why? I have a few (probably wrong) guesses.

Because you expect it to be the same every time you use it?
Well, then this should be "in general a bad idea":
 x = 1; print(x); x = 2; print(x)
Even though it makes total sense to me.

Is it because it's used to different purpose between similarly-looking
functions?
This looks fine, though:
def func1(): x=1; print(x)
def func2(): x=2; print(x)

Is it because it looks like a reassignment of the more global x?
I don't have an example here but, simply put, I don't believe this. We can
use "id" as our own local variable without thinking that we're tampering
with "__builtins__.id". I don't see it as much of a leap from builtin to
global (except that you **can** do "dir = 1; del dir; dir" without error).

That said, I'm sorta' just guessing the reason you might think it's a bad
idea.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Jean-Michel Pichavant

Steven D'Aprano wrote:

On Tue, 13 Dec 2011 10:54:51 +0100, Jean-Michel Pichavant wrote:

  

Steven D'Aprano wrote:


On Mon, 12 Dec 2011 12:13:33 +0100, Jean-Michel Pichavant wrote:


  

Using the same name for 2 different objects is a bad idea in general.




We have namespaces precisely so you don't need to care about making
names globally unique.



  

I don't get your point, namespaced names are unique, by definition.

foo.aname <> bar.aname



Assuming foo and bar are not names for the same object, there are at 
least three namespaces here: the local namespace, where foo and bar can 
be found, the foo.__dict__ namespace, and the bar.__dict__ namespace.



  

The OP showed a code where there was a confusion between a global name
and a local one. There's no namespace involved. Having a local name
identical to a global one is a bad idea, def.



Of course there are namespaces involved. There is the global namespace, 
and the local namespace. That's how you can have x inside a function 
without it overwriting global x outside of it, because they are different 
namespaces. Which is my point.


When I write this:

x = 1

def spam():
x = 2

def ham():
x = 3

The three x's don't clash because they are in three separate namespaces.

  

I know that, why do I have the feel this is juste a semantic issue ?
Aren't you/I/we confusion namespaces & scopes ?

Anyway, semantic is not what we're interested in here.

writing

x = 1

def spam():
   x = 2


is in general a bad idea. That was my point.

JM



--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Steven D'Aprano
On Tue, 13 Dec 2011 10:54:51 +0100, Jean-Michel Pichavant wrote:

> Steven D'Aprano wrote:
>> On Mon, 12 Dec 2011 12:13:33 +0100, Jean-Michel Pichavant wrote:
>>
>>
>>> Using the same name for 2 different objects is a bad idea in general.
>>> 
>>> 
>> We have namespaces precisely so you don't need to care about making
>> names globally unique.
>>
>>
>>
> I don't get your point, namespaced names are unique, by definition.
> 
> foo.aname <> bar.aname

Assuming foo and bar are not names for the same object, there are at 
least three namespaces here: the local namespace, where foo and bar can 
be found, the foo.__dict__ namespace, and the bar.__dict__ namespace.


> The OP showed a code where there was a confusion between a global name
> and a local one. There's no namespace involved. Having a local name
> identical to a global one is a bad idea, def.

Of course there are namespaces involved. There is the global namespace, 
and the local namespace. That's how you can have x inside a function 
without it overwriting global x outside of it, because they are different 
namespaces. Which is my point.

When I write this:

x = 1

def spam():
x = 2

def ham():
x = 3

The three x's don't clash because they are in three separate namespaces.

-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Jean-Michel Pichavant

Steven D'Aprano wrote:

On Mon, 12 Dec 2011 12:13:33 +0100, Jean-Michel Pichavant wrote:

  

Using the same name for 2 different objects is a bad idea in general.



We have namespaces precisely so you don't need to care about making names 
globally unique.



  

I don't get your point, namespaced names are unique, by definition.

foo.aname <> bar.aname

The OP showed a code where there was a confusion between a global name 
and a local one. There's no namespace involved. Having a local name 
identical to a global one is a bad idea, def.


JM
--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Antoon Pardon

On 12/10/2011 09:47 PM, Roy Smith wrote:

I've got a code pattern I use a lot.  In each module, I create a logger
for the entire module and log to it all over:

logger = logging.getLogger('my.module.name')

class Foo:
def function(self):
   logger.debug('stuff')
   logger.debug('other stuff')

and so on.  This works, but every once in a while I decide that a
particular function needs a more specific logger, so I can adjust the
logging level for that function independent of the rest of the module.
What I really want to do is:

def function(self):
   logger = logger.getChild('function')
   logger.debug('stuff')
   logger.debug('other stuff')

which lets me not have to change any lines of code other than inserting
the one to redefine logger.  Unfortunately, that's not legal Python (it
leads to "UnboundLocalError: local variable 'logger' referenced before
assignment").

Any ideas on the best way to implement this?
   

How about two global references:

globallogger = logger = logging.getLogger('my.module.name')

def function(self):
  logger = globallogger.getChild('function')
  logger.debug('stuff')
  logger.debug('other stuff')

--
Antoon Pardon

--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-13 Thread Joshua Landau
On 13/12/2011, Ian Kelly  wrote:
> On Mon, Dec 12, 2011 at 4:48 PM, Joshua Landau
>  wrote:
>> Rebinding logger locally in a function is really no
>> different to a subclass rebinding a variable from its main class using
>> that
>> class' value. The only difference is that, in that case, you have an
>> alternate binding to the original value.
>
> No, there is another difference, the reason for rebinding the name.
> In a subclass, you would rebind a class attribute because that
> particular attribute, which you need to change, is used and expected
> by external code, either in the base class or in code that uses its
> API (or both).  Local variables in functions, on the other hand, are
> not externally visible, so there is no need to do this in order to
> conform to the expectations of external code.  All it does in that
> case is to sow potential confusion.
>
So you're saying you should never extend methods or attributes that
aren't meant to be used as part of of the API? Because I can claim
guilty on this point.

I'd make this longer, but I've got class now :(
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Ian Kelly
On Mon, Dec 12, 2011 at 4:48 PM, Joshua Landau
 wrote:
> Rebinding logger locally in a function is really no
> different to a subclass rebinding a variable from its main class using that
> class' value. The only difference is that, in that case, you have an
> alternate binding to the original value.

No, there is another difference, the reason for rebinding the name.
In a subclass, you would rebind a class attribute because that
particular attribute, which you need to change, is used and expected
by external code, either in the base class or in code that uses its
API (or both).  Local variables in functions, on the other hand, are
not externally visible, so there is no need to do this in order to
conform to the expectations of external code.  All it does in that
case is to sow potential confusion.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Steven D'Aprano
On Tue, 13 Dec 2011 09:27:09 +1100, Ben Finney wrote:

> Dave Angel  writes:
> 
>> True, but in this code, the function is trying to both use the global
>> value, but also a local that deliberately has the same name, but a
>> different meaning and "value". The CPython compiler doesn't make this
>> easy, and I think the globals() technique is unnecessarily obscure, as
>> is the default-argument trick.
> 
> I disagree. The language makes it difficult, and it *should* be
> difficult to do what you describe.
> 
> The tricks to achieve it are obscure and ugly, which is a good thing
> IMO: they're a code smell that the design of the code needs changing.

Devil's Advocate: perhaps not. Think of local and global names as 
analogous to instance and class attributes. There are good use cases for 
making something a class attribute, while allowing instances to override 
that name with an instance attribute. I see a reasonable case for saying 
"use this global, unless a local overrides it".

Similarly, globals override built-ins with the same name; while 
monkeypatching needs to be used with care, it is a legitimate technique.

To a human reader, the following pseudocode might be ambiguous, but 
either case makes sense:

x = 1
def spam():
print x  # prints 1
x = 2  # does this create a new local x, or modify the old global x?
print x  # unambiguously prints 2

print x  # prints 1 or 2


Python doesn't allow this, but another language might; in Python, a 
reasonable way to get similar behaviour might be:

x = 1
def spam():
print globals()['x']
x = 2  # unambiguously creates a new local x
print x  # unambiguously prints 2

print x  # unambiguously prints 1


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Dave Angel

On 12/12/2011 06:48 PM, Joshua Landau wrote:

If a function knows of the presence of a global, it's not asking too
much for it to not re-use the same name in local scope.

Yes.


It's just a function wanting to act as-if it were in a different
environment than its default. By that same reasoning you could state that
"If a function knows of the presence of a built-in, it's not asking
too much for it to not re-use the same name in local scope."

It's entirely different.  It's only the same if the function actually 
tries to call the built-in, then also wants a local variable with a 
different purpose.  Think a little about what I mean that the function 
"knows of the presence."  I did not say the programmer knows of the 
presence.

--

DaveA

--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Joshua Landau
>
> > If a function knows of the presence of a global, it's not asking too
> > much for it to not re-use the same name in local scope.
>
> Yes.


It's just a function wanting to act as-if it were in a different
environment than its default. By that same reasoning you could state that
"If a function knows of the presence of a built-in, it's not asking
too much for it to not re-use the same name in local scope." Yet if
rebinding "id" is such a crime, why is it so oft done? Rebinding logger
locally in a function is really no different to a subclass rebinding a
variable from its main class using that class' value. *The only difference
is that, in that case, you have an alternate binding to the original value.*
*
*
>>> class A():
... val = 1
...
>>> class B(A):
... val = str(val) # Obviously, this doesn't work
...

NameError: name 'val' is not defined
>>> class B(A):
... val = str(A.val) # But it's OK as we can just do this ^^
...
>>> B().val
'1'
>>>

The only reason it's not minded with classes is because there's a good way
to do it.

I get that my analogy doesn't use globals, but the idea of extending a
more-global attribute locally is shared between the concepts.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Ben Finney
Dave Angel  writes:

> True, but in this code, the function is trying to both use the global
> value, but also a local that deliberately has the same name, but a
> different meaning and "value". The CPython compiler doesn't make this
> easy, and I think the globals() technique is unnecessarily obscure, as
> is the default-argument trick.

I disagree. The language makes it difficult, and it *should* be
difficult to do what you describe.

The tricks to achieve it are obscure and ugly, which is a good thing
IMO: they're a code smell that the design of the code needs changing.

Or, in brief: they're not unnecessarily obscure, they're as obscure as
they need to be.

> If a function knows of the presence of a global, it's not asking too
> much for it to not re-use the same name in local scope.

Yes. 

-- 
 \ “Airports are ugly. Some are very ugly. Some attain a degree of |
  `\ugliness that can only be the result of a special effort.” |
_o__) —Douglas Adams, _The Long Dark Tea-Time Of The Soul_ |
Ben Finney
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Joshua Landau
Wouldn't this be nicer, though?:

def getChildLogger(id):
return logger.getChild(id)

def someFunc():
logger = getChildLogger("someFunc")


-- UNTESTED --

No messing around with globals this way, and it's more extendable. And
'globals()["logger"].getChild("someFunc")' reads like a brick.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Dave Angel

On 12/12/2011 04:28 PM, Steven D'Aprano wrote:

On Mon, 12 Dec 2011 12:13:33 +0100, Jean-Michel Pichavant wrote:


Using the same name for 2 different objects is a bad idea in general.

We have namespaces precisely so you don't need to care about making names
globally unique.


True, but in this code, the function is trying to both use the global 
value, but also a local that deliberately has the same name, but a 
different meaning and "value".  The CPython compiler doesn't make this 
easy, and I think the globals() technique is unnecessarily obscure, as 
is the default-argument trick.


If a function knows of the presence of a global, it's not asking too 
much for it to not re-use the same name in local scope.


Since it seems to be in vogue to propose language changes, how about a 
new place for 'as' ?

def myfunc():
 global logger as g_logger
 logger = g_logger.debug('stuff').getChild('function')

--

DaveA

--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Steven D'Aprano
On Mon, 12 Dec 2011 12:13:33 +0100, Jean-Michel Pichavant wrote:

> Using the same name for 2 different objects is a bad idea in general.

We have namespaces precisely so you don't need to care about making names 
globally unique.


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-12 Thread Jean-Michel Pichavant

Roy Smith wrote:

MRAB  wrote:

  

or use 'globals':

 def function(self):
 logger = globals()['logger'].getChild('function')
 logger.debug('stuff')
 logger.debug('other stuff')



Ah-ha!  That's precisely what I was looking for.  Much appreciated.
  

Using the same name for 2 different objects is a bad idea in general.
In debug mode, i.e. the logger is configured with the debug level, you 
could simply write down the filename and the line number on your log 
events.


formatter = logging.Formatter('%(name)s : %(filename)s %(lineno)s  
%(message)s')


So you can easily see who logged what (if I'm not wrong, that's what 
you're trying to do)


JM
--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-11 Thread Peter Otten
Roy Smith wrote:

> I've got a code pattern I use a lot.  In each module, I create a logger
> for the entire module and log to it all over:
> 
> logger = logging.getLogger('my.module.name')
> 
> class Foo:
>def function(self):
>   logger.debug('stuff')
>   logger.debug('other stuff')
> 
> and so on.  This works, but every once in a while I decide that a
> particular function needs a more specific logger, so I can adjust the
> logging level for that function independent of the rest of the module.
> What I really want to do is:
> 
>def function(self):
>   logger = logger.getChild('function')
>   logger.debug('stuff')
>   logger.debug('other stuff')
> 
> which lets me not have to change any lines of code other than inserting
> the one to redefine logger.  Unfortunately, that's not legal Python (it
> leads to "UnboundLocalError: local variable 'logger' referenced before
> assignment").
> 
> Any ideas on the best way to implement this?

def function(self, logger=logger.getChild("function")):
logger.debug("stuff")

But the "best way" is to use another name.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-10 Thread Terry Reedy

On 12/10/2011 7:14 PM, Terry Reedy wrote:

On 12/10/2011 3:47 PM, Roy Smith wrote:


What I really want to do is:

def function(self):


Add a global statement to rebind a global name:
global logger


But I see that that is not what you want to do, which is to override the 
global name just within the function while still accessing the global 
name. MRAB's solution does that nicely.



logger = logger.getChild('function')
logger.debug('stuff')
logger.debug('other stuff')

which lets me not have to change any lines of code other than inserting
the one to redefine logger. Unfortunately, that's not legal Python (it
leads to "UnboundLocalError: local variable 'logger' referenced before
assignment").

Any ideas on the best way to implement this?






--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-10 Thread Terry Reedy

On 12/10/2011 3:47 PM, Roy Smith wrote:


What I really want to do is:

def function(self):


Add a global statement to rebind a global name:
   global logger


   logger = logger.getChild('function')
   logger.debug('stuff')
   logger.debug('other stuff')

which lets me not have to change any lines of code other than inserting
the one to redefine logger.  Unfortunately, that's not legal Python (it
leads to "UnboundLocalError: local variable 'logger' referenced before
assignment").

Any ideas on the best way to implement this?



--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-10 Thread Roy Smith
MRAB  wrote:

> or use 'globals':
> 
>  def function(self):
>  logger = globals()['logger'].getChild('function')
>  logger.debug('stuff')
>  logger.debug('other stuff')

Ah-ha!  That's precisely what I was looking for.  Much appreciated.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Overriding a global

2011-12-10 Thread MRAB

On 10/12/2011 20:47, Roy Smith wrote:

I've got a code pattern I use a lot.  In each module, I create a logger
for the entire module and log to it all over:

logger = logging.getLogger('my.module.name')

class Foo:
def function(self):
   logger.debug('stuff')
   logger.debug('other stuff')

and so on.  This works, but every once in a while I decide that a
particular function needs a more specific logger, so I can adjust the
logging level for that function independent of the rest of the module.
What I really want to do is:

def function(self):
   logger = logger.getChild('function')
   logger.debug('stuff')
   logger.debug('other stuff')

which lets me not have to change any lines of code other than inserting
the one to redefine logger.  Unfortunately, that's not legal Python (it
leads to "UnboundLocalError: local variable 'logger' referenced before
assignment").

Any ideas on the best way to implement this?


You could use a different name:

def function(self):
logger2 = logger.getChild('function')
logger2.debug('stuff')
logger2.debug('other stuff')

or use 'globals':

def function(self):
logger = globals()['logger'].getChild('function')
logger.debug('stuff')
logger.debug('other stuff')
--
http://mail.python.org/mailman/listinfo/python-list


Overriding a global

2011-12-10 Thread Roy Smith
I've got a code pattern I use a lot.  In each module, I create a logger 
for the entire module and log to it all over:

logger = logging.getLogger('my.module.name')

class Foo:
   def function(self):
  logger.debug('stuff')
  logger.debug('other stuff')

and so on.  This works, but every once in a while I decide that a 
particular function needs a more specific logger, so I can adjust the 
logging level for that function independent of the rest of the module.  
What I really want to do is:

   def function(self):
  logger = logger.getChild('function')
  logger.debug('stuff')
  logger.debug('other stuff')

which lets me not have to change any lines of code other than inserting 
the one to redefine logger.  Unfortunately, that's not legal Python (it 
leads to "UnboundLocalError: local variable 'logger' referenced before 
assignment").

Any ideas on the best way to implement this?
-- 
http://mail.python.org/mailman/listinfo/python-list