Re: About Modifying Globals

2014-12-04 Thread Chris Angelico
On Fri, Dec 5, 2014 at 7:09 AM, LJ luisjoseno...@gmail.com wrote:
 def gt(l):
a[1] = a[1] | set([l])


 def gt2(l):
b=b+l

These two may both look like they're assigning something, but one of
them is assigning directly to the name b, while the other assigns to
a subscripted element of a. In the first function, a is still the
same object after the change; in the second, b has been replaced by
a new object. That's why your second one needs a global declaration.
It's all about names and assignment; if you're not assigning to the
actual name, there's no need to declare where the name comes from,
because you're only referencing it, not replacing it.

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


Re: About Modifying Globals

2014-12-04 Thread Ian Kelly
On Thu, Dec 4, 2014 at 1:09 PM, LJ luisjoseno...@gmail.com wrote:

 Hi All,

 I have a quick question regarding the modification of global variables
within functions. To illustrate, consider the following toy example:

 a={1: set()}
 b=9

 def gt(l):
a[1] = a[1] | set([l])

 When calling this last function and checking the a dictionary, I get:

  gt(5)
  a
 {1: set([5])}


 The set in the dictionary was modified. The question is, why isn't it
necessary to declare a as global within the gt function, as apposed to a
case like

 def gt2(l):
b=b+l

 where I need to declare b as global within the function to avoid:

 UnboundLocalError: local variable 'b' referenced before assignment.

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python

In the first case, you never assign to a; you only modify it. Since it's
never assigned locally the compiler knows it can't be a local variable, so
it automatically makes it a global.

In the second case, the assignment to b causes the compiler to treat the
variable as local by default, so it needs to be explicitly marked as global.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: About Modifying Globals

2014-12-04 Thread Dave Angel

On 12/04/2014 03:09 PM, LJ wrote:

Hi All,

I have a quick question regarding the modification of global variables within 
functions. To illustrate, consider the following toy example:

a={1: set()}
b=9

def gt(l):
a[1] = a[1] | set([l])

When calling this last function and checking the a dictionary, I get:


gt(5)
a

{1: set([5])}


The set in the dictionary was modified. The question is, why isn't it necessary 
to declare a as global within the gt function, as apposed to a case like

def gt2(l):
b=b+l

where I need to declare b as global within the function to avoid:

UnboundLocalError: local variable 'b' referenced before assignment.



The reason this sort of thing seems to confuse lots of people is that we 
insist on calling these things assignments.  The thing that's global is 
the name 'a'.  It's global because it's in the global() namespace of 
some module.


The data that's assigned to it is an object.  You bind the object to 
the name 'a' with an assignment statement.  If that object is immutable, 
then the only way to change 'a' is to do another assignment.


But if the object is mutable, as a set is, then it can change as much as 
you like without rebinding the name.


A given object may have any number of names bound to it, including no 
names.  An example of that could be objects that are referenced only in 
some list.


Python doesn't have declarations, so when a function is compiled, the 
compiler has to infer what names are to be local and what are not.  The 
rule it normally uses is roughly based on whether an assignment occurs 
somewhere inside the function.



--
DaveA
--
https://mail.python.org/mailman/listinfo/python-list


Re: About Modifying Globals

2014-12-04 Thread Chris Angelico
On Fri, Dec 5, 2014 at 10:54 AM, Dave Angel da...@davea.name wrote:
 Python doesn't have declarations, so when a function is compiled, the
 compiler has to infer what names are to be local and what are not.  The rule
 it normally uses is roughly based on whether an assignment occurs somewhere
 inside the function.

Not strictly true; Python just inverts the C model. In C, you declare
your locals; in Python, you declare your globals. The global x
statement is a declaration. But otherwise, yes. When a function is
compiled, the compiler has to figure out what's local and what's
global.

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


Re: About Modifying Globals

2014-12-04 Thread Steven D'Aprano
LJ wrote:

 Hi All,
 
 I have a quick question regarding the modification of global variables
 within functions. To illustrate, consider the following toy example:
 
 a={1: set()}
 b=9
 
 def gt(l):
a[1] = a[1] | set([l])

The difference between this example and your second one:

 def gt2(l):
b=b+l


is that the second is a binding operation and the first is not.

Binding operations include direct assignment to a name, deletions, imports
and a few other things:

b = 23
del b
import sys as b


are all considered binding operations, since they bind a value to a name
(or, in the case of del, unbind it). Inside functions, the compiler follows
the rule that any binding operation makes that variable a local for the
entire function, unless declared global.

So in the gt2() example, b = b + 1 is interpreted as this:

- look up local variable b;
- add one to the result;
- assign it to local variable b.

which fails because b hasn't got a value yet.

This is different from, say, Lua, where that line would be interpreted as: 

- look up local variable b;
- if that doesn't exist, look up global variable b instead;
- add one to the result;
- assign it to local variable b.

But that's not what Python does.

On the other hand, your first example doesn't include a direct assignment to
a name:

a[1] = a[1] | set([l])


looks like an assignment, but it's actually a method call! That is
approximately equivalent to:

a.__setitem__(1, X)

with X equal to the right hand side. Since that's a method call, it doesn't
count as a binding operation and the compiler doesn't treat a as a local,
it treats it as global, so the lookup on the right hand side succeeds, and
the method call modifies the set in place.




-- 
Steven

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


Re: About Modifying Globals

2014-12-04 Thread shiyao.ma
On 12/04, LJ wrote:
 Hi All,

 I have a quick question regarding the modification of global variables within 
 functions. To illustrate, consider the following toy example:

 a={1: set()}
 b=9

 def gt(l):
a[1] = a[1] | set([l])

 When calling this last function and checking the a dictionary, I get:

  gt(5)
  a
 {1: set([5])}


 The set in the dictionary was modified. The question is, why isn't it 
 necessary to declare a as global within the gt function, as apposed to a case 
 like

 def gt2(l):
b=b+l

 where I need to declare b as global within the function to avoid:

 UnboundLocalError: local variable 'b' referenced before assignment.

Well. To understand the difference, one first has to know the mechanism of 
CPython.
When you have a script, CPython will first parse it, and then generate bytecode 
representation, and then finally execute it.
If you take a look at the bytecode of both your source code, you will notice, 
that.

In the first snippet, there is something like LOAD_NAME, which loads the global 
name a.
However, in the second snippet, there would be a LOAD_FAST, which loads the 
local name b (which is, technically speaking, stored in the PyFrameObj).

The reason Python treats it differently, is, IIUC, for better semantic meaning, 
and also, for huge performance improvement.


Hope that explains.


Regards.

-- 
Shiyao Ma
http://introo.me
-- 
https://mail.python.org/mailman/listinfo/python-list